diff --git a/eslint.config.ts b/eslint.config.ts index edb1bbb..e73d45e 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -17,4 +17,12 @@ export default defineConfigWithVueTs( pluginVue.configs['flat/essential'], vueTsConfigs.recommended, + + { + name: 'app/vue-rules', + files: ['**/*.vue'], + rules: { + 'vue/multi-word-component-names': 'off', + }, + }, ) diff --git a/index.html b/index.html index 09287f9..73181a1 100644 --- a/index.html +++ b/index.html @@ -2,6 +2,7 @@ + Vue Bits diff --git a/package-lock.json b/package-lock.json index 2e970af..f6a56bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "vue-bits", "version": "0.0.0", "dependencies": { + "gsap": "^3.13.0", + "ogl": "^1.0.11", + "primeicons": "^7.0.0", "vue": "^3.5.17", "vue-router": "^4.5.1" }, @@ -3652,6 +3655,12 @@ "dev": true, "license": "MIT" }, + "node_modules/gsap": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.13.0.tgz", + "integrity": "sha512-QL7MJ2WMjm1PHWsoFrAQH/J8wUeqZvMtHO58qdekHpCfhvhSL4gSiz6vJf5EeMP0LOn3ZCprL2ki/gjED8ghVw==", + "license": "Standard 'no charge' license: https://gsap.com/standard-license." + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -4574,6 +4583,12 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/ogl": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ogl/-/ogl-1.0.11.tgz", + "integrity": "sha512-kUpC154AFfxi16pmZUK4jk3J+8zxwTWGPo03EoYA8QPbzikHoaC82n6pNTbd+oEaJonaE8aPWBlX7ad9zrqLsA==", + "license": "Unlicense" + }, "node_modules/open": { "version": "10.1.2", "resolved": "https://registry.npmjs.org/open/-/open-10.1.2.tgz", @@ -4817,6 +4832,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/primeicons": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/primeicons/-/primeicons-7.0.0.tgz", + "integrity": "sha512-jK3Et9UzwzTsd6tzl2RmwrVY/b8raJ3QZLzoDACj+oTJ0oX7L9Hy+XnVwgo4QVKlKpnP/Ur13SXV/pVh4LzaDw==", + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", diff --git a/package.json b/package.json index 256b9ad..e6a12cf 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,9 @@ "lint": "eslint . --fix" }, "dependencies": { + "gsap": "^3.13.0", + "ogl": "^1.0.11", + "primeicons": "^7.0.0", "vue": "^3.5.17", "vue-router": "^4.5.1" }, diff --git a/public/assets/components.gif b/public/assets/components.gif new file mode 100644 index 0000000..ba99128 Binary files /dev/null and b/public/assets/components.gif differ diff --git a/public/assets/grain.webp b/public/assets/grain.webp new file mode 100644 index 0000000..adbae00 Binary files /dev/null and b/public/assets/grain.webp differ diff --git a/public/assets/messages.gif b/public/assets/messages.gif new file mode 100644 index 0000000..da8d6d5 Binary files /dev/null and b/public/assets/messages.gif differ diff --git a/src/App.vue b/src/App.vue index e237e1a..4733645 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,3 +1,27 @@ + + diff --git a/src/assets/common/star.svg b/src/assets/common/star.svg new file mode 100644 index 0000000..7b2f874 --- /dev/null +++ b/src/assets/common/star.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/logos/vue-bits-logo-small-dark.svg b/src/assets/logos/vue-bits-logo-small-dark.svg new file mode 100644 index 0000000..2f9ca97 --- /dev/null +++ b/src/assets/logos/vue-bits-logo-small-dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/logos/vue-bits-logo-small.svg b/src/assets/logos/vue-bits-logo-small.svg new file mode 100644 index 0000000..44571a6 --- /dev/null +++ b/src/assets/logos/vue-bits-logo-small.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/logos/vue-bits-logo.svg b/src/assets/logos/vue-bits-logo.svg new file mode 100644 index 0000000..048c6fb --- /dev/null +++ b/src/assets/logos/vue-bits-logo.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/logos/vuebits-gh-black.svg b/src/assets/logos/vuebits-gh-black.svg new file mode 100644 index 0000000..7306df5 --- /dev/null +++ b/src/assets/logos/vuebits-gh-black.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/logos/vuebits-gh-white.svg b/src/assets/logos/vuebits-gh-white.svg new file mode 100644 index 0000000..8e329aa --- /dev/null +++ b/src/assets/logos/vuebits-gh-white.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/components/common/Logo.vue b/src/components/common/Logo.vue new file mode 100644 index 0000000..d121da7 --- /dev/null +++ b/src/components/common/Logo.vue @@ -0,0 +1,34 @@ + + + diff --git a/src/components/landing/DisplayHeader/DisplayHeader.css b/src/components/landing/DisplayHeader/DisplayHeader.css new file mode 100644 index 0000000..648c46b --- /dev/null +++ b/src/components/landing/DisplayHeader/DisplayHeader.css @@ -0,0 +1,310 @@ +.header { + display: flex; + align-items: center; + z-index: 100; + position: fixed; + top: 0; + left: 50%; + transform: translateX(-50%); + justify-content: space-between; + width: 100vw; + padding: 0 4em; + height: 160px; + margin: 0 auto; + background: linear-gradient(to bottom, #0e0e0e, transparent); +} + +.header-container { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + max-width: 1200px; + margin: 0 auto; +} + +.nav-cta-group { + display: flex; + align-items: center; + gap: 1.5rem; +} + +.logo { + position: relative; + z-index: 2; +} + +.logo::before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 200px; + height: 140px; + background: transparent; + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + mask: radial-gradient(ellipse at center, black 0%, black 20%, transparent 80%); + -webkit-mask: radial-gradient(ellipse at center, black 0%, black 20%, transparent 80%); + z-index: -1; + pointer-events: none; +} + +.logo svg { + height: 26px; + width: auto; + position: relative; + z-index: 2; +} + +.landing-nav-items { + display: none; + color: #fff; + height: 60px; + padding: 0 2.4rem 0 calc(2.4rem + 6px); + border-radius: 50px; + border: 1px solid rgba(255, 255, 255, 0.07); + background: rgba(255, 255, 255, 0.01); + box-shadow: 0 8px 32px 0 rgba(31, 135, 62, 0.15); + backdrop-filter: blur(15px); + -webkit-backdrop-filter: blur(15px); +} + +.nav-link { + position: relative; + text-decoration: none; + color: inherit; + font-weight: 400; + opacity: 0.6; + transition: opacity 0.3s ease, transform 0.2s ease; +} + +.nav-link:hover { + opacity: 1; + transform: translateY(-1px); +} + +.active-link { + opacity: 1; +} + +.active-link::before { + content: ''; + position: absolute; + width: 6px; + height: 6px; + background-color: #fff; + border-radius: 50%; + left: -12px; + top: 50%; + transform: translateY(-50%); + z-index: 2; +} + +.cta-button { + font-weight: 500; + padding: 0 0 0 1.4rem; + height: calc(60px - 2px); + background: linear-gradient(135deg, + rgb(30, 160, 63), + rgba(24, 47, 255, 0.6)); + background-size: 200% 200%; + backdrop-filter: blur(25px); + -webkit-backdrop-filter: blur(25px); + color: #fff; + border: none; + border-radius: 50px; + cursor: pointer; + + display: flex; + align-items: center; + white-space: nowrap; + justify-content: space-between; + transition: .3s ease; +} + +.cta-button span { + background-color: #0e0e0e; + margin-left: 1em; + margin-right: calc(1em - 8px); + padding-top: .1em; + height: 45px; + border-radius: 50px; + width: 100px; + font-weight: 600; + + display: flex; + align-items: center; + justify-content: center; +} + +.cta-button span img { + margin-right: 6px; + width: 16px; + height: 16px; + transition: .3s ease; +} + +.cta-button:hover { + transition: .3s ease; +} + +.cta-button:hover span img { + transform: scale(1.2); + transition: .3s ease; +} + +@media (max-width: 900px) { + .header { + padding: 0 2em; + height: 120px; + } + + .logo svg { + height: 30px; + } + + .logo::before { + width: 180px; + height: 120px; + } + + .cta-button { + padding: 0 0 0 1rem; + height: 50px; + font-size: 0.9rem; + } + + .cta-button span { + height: 38px; + width: 80px; + margin-left: 0.8em; + margin-right: calc(0.8em - 6px); + } + + .cta-button span img { + width: 14px; + height: 14px; + margin-right: 4px; + } +} + +@media (max-width: 640px) { + .header { + padding: 0 1.5em; + height: 100px; + } + + .logo svg { + height: 28px; + } + + .logo::before { + width: 160px; + height: 110px; + } + + .cta-button { + padding: 0 0 0 0.8rem; + height: 45px; + font-size: 0.85rem; + } + + .cta-button span { + height: 35px; + width: 60px !important; + margin-left: 0.6em; + margin-right: calc(0.6em - 4px); + } + + .cta-button span img { + width: 12px; + height: 12px; + margin-right: 3px; + } +} + +@media (max-width: 480px) { + .header { + padding: 0 1rem; + height: 90px; + } + + .logo svg { + height: 26px; + } + + .logo::before { + width: 140px; + height: 95px; + } + + .cta-button { + padding: 0 0 0 0.6rem; + height: 40px; + font-size: 0.8rem; + } + + .cta-button span { + height: 32px; + width: 60px; + margin-left: 0.5em; + margin-right: calc(0.5em - 3px); + font-weight: 500; + } + + .cta-button span img { + width: 10px; + height: 10px; + margin-right: 2px; + } +} + +@media (max-width: 375px) { + .header { + padding: 0 0.8rem; + height: 80px; + } + + .logo svg { + height: 22px; + } + + .logo::before { + width: 120px; + height: 80px; + } + + .cta-button { + padding: 0 0 0 0.5rem; + height: 36px; + font-size: 0.75rem; + } + + .cta-button span { + height: 28px; + width: 50px; + margin-left: 0.4em; + margin-right: calc(0.4em - 2px); + } + + .cta-button span img { + width: 9px; + height: 9px; + margin-right: 1px; + } +} + +@media (min-width: 900px) { + .landing-nav-items { + display: flex; + align-items: center; + justify-content: space-between; + gap: 2rem; + } + + .nav-cta-group { + gap: 2rem; + } +} \ No newline at end of file diff --git a/src/components/landing/DisplayHeader/DisplayHeader.vue b/src/components/landing/DisplayHeader/DisplayHeader.vue new file mode 100644 index 0000000..59f5052 --- /dev/null +++ b/src/components/landing/DisplayHeader/DisplayHeader.vue @@ -0,0 +1,77 @@ + + + diff --git a/src/components/landing/FeatureCards/FeatureCards.css b/src/components/landing/FeatureCards/FeatureCards.css new file mode 100644 index 0000000..32722f2 --- /dev/null +++ b/src/components/landing/FeatureCards/FeatureCards.css @@ -0,0 +1,662 @@ +.features-section { + position: relative; + margin-top: 12em; + padding: 8rem 2rem 4em; + padding-bottom: 0 !important; + z-index: 22; + user-select: none; +} + +.features-container { + max-width: 1200px; + margin: 0 auto; +} + +.features-header { + text-align: center; + margin-bottom: 4rem; +} + +.features-title { + font-size: 4rem; + font-weight: 600; + letter-spacing: -2px; + color: #fff; + margin-bottom: .2rem; + background: linear-gradient(135deg, #fff 0%, #60fa89 20%, #55f788 40%, #00ff62 60%, #55f799 80%, #fff 100%); + background-size: 200% 200%; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + text-align: center; + animation: gradientShift 4s ease-in-out infinite; + display: inline-block; + white-space: nowrap; +} + +.features-title * { + background: inherit; + background-size: inherit; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + animation: inherit; +} + +@keyframes gradientShift { + + 0%, + 100% { + background-position: 0% 50%; + } + + 50% { + background-position: 100% 50%; + } +} + +.features-subtitle { + font-size: 1.2rem; + color: #fff; + text-shadow: + 0 0 2px rgba(255, 255, 255, 0.1), + 0 0 4px rgba(255, 255, 255, 0.3), + 0 0 8px rgba(255, 255, 255, 0.4), + 0 0 136px rgba(0, 255, 98, 0.9); + font-weight: 400; + margin: 0; + text-align: center; +} + +@media (max-width: 768px) { + .features-title { + font-size: 2.5rem; + } + + .features-subtitle { + font-size: 1.1rem; + } + + .features-header { + margin-bottom: 3rem; + } +} + +@media (max-width: 480px) { + .features-title { + font-size: 2rem; + } + + .features-subtitle { + font-size: 1rem; + } +} + +.bento-grid { + max-width: 1200px; + display: grid; + gap: 1.5em; + grid-template-columns: 1fr; + grid-auto-rows: auto; +} + +@media (min-width: 480px) and (max-width: 767px) { + .bento-grid { + grid-template-columns: repeat(2, 1fr); + gap: 1.25em; + } + + .card1 { + grid-column: 1 / 3; + grid-row: 1 / 2; + } + + .card2 { + grid-column: 1 / 2; + grid-row: 2 / 3; + } + + .card4 { + grid-column: 2 / 3; + grid-row: 2 / 3; + } + + +} + +@media (min-width: 50rem) { + .bento-grid { + grid-template-columns: repeat(4, 1fr); + grid-template-rows: repeat(3, auto); + gap: 1.5em; + } + + .card1 { + grid-column: 1 / 3; + grid-row: 1 / 2; + } + + .card2 { + grid-column: 3 / 5; + grid-row: 1 / 3; + } + + .card4 { + grid-column: 1 / 3; + grid-row: 2 / 3; + } + + +} + +@media (min-width: 768px) and (max-width: 49.99rem) { + .bento-grid { + grid-template-columns: repeat(3, 1fr); + gap: 1.25em; + } + + .card1 { + grid-column: 1 / 3; + grid-row: 1 / 2; + } + + .card2 { + grid-column: 3 / 4; + grid-row: 1 / 3; + } + + .card4 { + grid-column: 1 / 2; + grid-row: 2 / 3; + } + + +} + +.feature-card { + user-select: none; + background: #0e0e0e; + border: 1px solid rgba(148, 184, 154, 0.2); + border-radius: 16px; + padding: 2rem; + text-align: left; + text-decoration: none; + transition: all 0.3s ease; + backdrop-filter: blur(10px); + position: relative; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: flex-end; + height: 100%; + min-height: 220px; + --glow-x: 50%; + --glow-y: 50%; + --glow-intensity: 0; +} + +.feature-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 1px; + background: linear-gradient(90deg, transparent, rgba(163, 148, 184, 0.3), transparent); + transition: opacity 0.3s ease; + opacity: 0; +} + +.feature-card::after { + content: ''; + position: absolute; + inset: 0; + padding: 1px; + background: radial-gradient(200px circle at var(--glow-x) var(--glow-y), + rgba(132, 0, 255, calc(var(--glow-intensity) * 0.8)) 0%, + rgba(132, 0, 255, calc(var(--glow-intensity) * 0.4)) 30%, + transparent 60%); + border-radius: inherit; + mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); + mask-composite: subtract; + -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); + -webkit-mask-composite: xor; + pointer-events: none; + transition: opacity 0.3s ease; +} + +.feature-card:hover { + box-shadow: 0 4px 40px -15px rgba(46, 24, 78, 0.4) !important; + background: #07160a; +} + + + +.feature-card:hover::before { + opacity: 1; +} + +.feature-icon { + font-size: 2.5rem; + margin-bottom: 2rem; + display: flex; + justify-content: flex-start; + align-items: center; + flex-shrink: 0; +} + +.feature-card h3 { + font-size: 1rem; + font-weight: 600; + color: #fff; + margin-bottom: 0.5rem; + letter-spacing: -0.01em; + flex-shrink: 0; + position: relative; + z-index: 10; +} + +.feature-card h2 { + font-size: 6rem; + position: relative; + top: 22px; + margin: 0; + font-weight: 800; + background: linear-gradient(135deg, #fff 0%, #60fa7f 20%, #55f783 40%, #00ff48 60%, #58f755 80%, #fff 100%); + background-size: 200% 200%; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + animation: gradientShift 4s ease-in-out infinite; + z-index: 10; +} + +.feature-card p { + color: rgba(161, 148, 184, 0.9); + line-height: 1.4; + font-size: 0.95rem; + text-align: left; + max-width: 100%; + position: relative; + z-index: 10; +} + +.particle-container { + position: relative; + overflow: hidden; +} + +.particle { + position: absolute; + width: 4px; + height: 4px; + background: rgba(0, 255, 98, 0.8); + border-radius: 50%; + pointer-events: none; + z-index: 100; + box-shadow: 0 0 6px rgba(0, 255, 68, 0.6); +} + +.particle::before { + content: ''; + position: absolute; + top: -2px; + left: -2px; + right: -2px; + bottom: -2px; + background: rgba(0, 255, 81, 0.3); + border-radius: 50%; + z-index: -1; +} + +.feature-card.particle-container { + overflow: hidden; +} + +.feature-card.particle-container:hover { + box-shadow: 0 4px 20px rgba(24, 78, 42, 0.4), 0 0 30px rgba(0, 255, 76, 0.2); + background: #07160b; +} + +.global-spotlight { + mix-blend-mode: screen; + will-change: transform, opacity; + z-index: 200 !important; + pointer-events: none; +} + +.components-gif-wrapper { + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + z-index: 1; + overflow: hidden; + opacity: 0; + transition: opacity 0.3s ease; +} + +.feature-card:hover .components-gif-wrapper { + opacity: 1; +} + +.components-gif { + width: 100%; + height: auto; + opacity: 0.2; + mix-blend-mode: lighten; + display: block; + filter: grayscale(100%); +} + +.components-gif-wrapper::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 20%; + background: linear-gradient(to top, #0e0e0e 0%, transparent 100%); + border-radius: 0 0 8px 8px; + pointer-events: none; + z-index: 2; +} + +.components-gif-wrapper::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 20%; + background: linear-gradient(to bottom, #0e0e0e 0%, transparent 100%); + border-radius: 8px 8px 0 0; + pointer-events: none; + z-index: 2; +} + +.messages-gif-wrapper { + position: absolute; + mix-blend-mode: lighten; + top: 0.5rem; + right: 1rem; + bottom: 1rem; + width: 50%; + border-radius: 8px; + z-index: 1; + overflow: hidden; + opacity: 0; + transition: opacity 0.3s ease; +} + +.feature-card:hover .messages-gif-wrapper { + opacity: 1; +} + +.messages-gif { + width: 100%; + height: 100%; + object-fit: contain; + border-radius: 0; + opacity: 0.3; + display: block; +} + +.messages-gif-wrapper::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 20%; + background: linear-gradient(to top, #0e0e0e 0%, transparent 100%); + border-radius: 0 0 8px 8px; + pointer-events: none; + z-index: 2; +} + +.messages-gif-wrapper::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 20%; + background: linear-gradient(to bottom, #0e0e0e 0%, transparent 100%); + border-radius: 8px 8px 0 0; + pointer-events: none; + z-index: 2; +} + +.switch-gif-wrapper { + position: absolute; + top: 0; + right: 1rem; + width: 40%; + mix-blend-mode: lighten; + border-radius: 8px; + z-index: 1; + overflow: hidden; + opacity: 0; + transition: opacity 0.3s ease; +} + +.feature-card:hover .switch-gif-wrapper { + opacity: 1; +} + +.switch-gif { + width: 100%; + height: 100%; + object-fit: contain; + border-radius: 0; + opacity: 0.3; + display: block; +} + +.switch-gif-wrapper::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 20%; + background: linear-gradient(to top, #0e0e0e 0%, transparent 100%); + border-radius: 0 0 8px 8px; + pointer-events: none; + z-index: 2; +} + +.switch-gif-wrapper::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 20%; + background: linear-gradient(to bottom, #0e0e0e 0%, transparent 100%); + border-radius: 8px 8px 0 0; + pointer-events: none; + z-index: 2; +} + + + +@media (max-width: 479px) { + .features-section { + padding: 4rem 1rem 2rem; + padding-bottom: 0; + margin-top: 4em; + } + + .bento-grid { + gap: 1rem; + max-width: 100%; + } + + .feature-card { + min-height: 160px; + padding: 1.25rem; + border-radius: 12px; + } + + .feature-icon { + font-size: 1.75rem; + margin-bottom: 0.75rem; + } + + .feature-card h2 { + font-size: 4rem; + } + + + + .feature-card h3 { + font-size: 1rem; + margin-bottom: 0.5rem; + } + + .feature-card p { + font-size: 0.85rem; + line-height: 1.6; + } + + .components-gif-wrapper, + .messages-gif-wrapper, + .switch-gif-wrapper { + display: none !important; + } +} + +@media (max-width: 360px) { + .features-section { + padding: 2.5rem 0.5rem 1rem; + } + + .bento-grid { + gap: 0.75rem; + } + + .feature-card { + min-height: 150px; + padding: 1rem; + border-radius: 10px; + } + + .feature-icon { + font-size: 1.5rem; + margin-bottom: 0.5rem; + } + + .feature-card h2 { + font-size: 4rem; + } + + + + .feature-card h3 { + font-size: 0.95rem; + margin-bottom: 0.4rem; + } + + .feature-card p { + font-size: 0.8rem; + line-height: 1.7; + } + + .components-gif-wrapper, + .messages-gif-wrapper, + .switch-gif-wrapper { + display: none !important; + } +} + +@media (min-width: 768px) { + .features-section { + padding: 6rem 2rem 3rem; + margin-top: 6em; + } + + .feature-card { + min-height: 200px; + padding: 1.75rem; + } + + .feature-icon { + font-size: 2.25rem; + margin-bottom: 1.5rem; + } + + .feature-card h3 { + font-size: 1.15rem; + } + + .feature-card p { + font-size: 0.92rem; + } + + .components-gif-wrapper, + .messages-gif-wrapper, + .switch-gif-wrapper { + display: none !important; + } +} + +@media (min-width: 50rem) { + .features-section { + padding: 8rem 2rem 4rem; + padding-bottom: 0; + margin-top: 8em; + } + + .feature-card { + min-height: 220px; + padding: 2rem; + } + + .feature-icon { + font-size: 2.5rem; + margin-bottom: 1rem; + } + + .feature-card h3 { + font-size: 2rem; + } + + .feature-card p { + font-size: 0.95rem; + } + + .components-gif-wrapper, + .messages-gif-wrapper, + .switch-gif-wrapper { + display: block !important; + } +} + +@media (max-height: 500px) and (orientation: landscape) { + .features-section { + margin-top: 2em; + padding: 2rem 1rem; + } + + .feature-card { + min-height: 140px; + padding: 1rem; + } + + .feature-icon { + font-size: 1.5rem; + margin-bottom: 0.5rem; + } + + .feature-card h3 { + font-size: 0.9rem; + margin-bottom: 0.3rem; + } + + .feature-card p { + font-size: 0.8rem; + } +} \ No newline at end of file diff --git a/src/components/landing/FeatureCards/FeatureCards.vue b/src/components/landing/FeatureCards/FeatureCards.vue new file mode 100644 index 0000000..7fe705e --- /dev/null +++ b/src/components/landing/FeatureCards/FeatureCards.vue @@ -0,0 +1,286 @@ + + + \ No newline at end of file diff --git a/src/components/landing/Footer/Footer.css b/src/components/landing/Footer/Footer.css new file mode 100644 index 0000000..e078525 --- /dev/null +++ b/src/components/landing/Footer/Footer.css @@ -0,0 +1,155 @@ +.landing-footer { + position: relative; + margin-top: 8rem; + padding: 2.4rem; + border-top: 1px solid rgba(149, 184, 148, 0.1); + background: linear-gradient(to bottom, transparent, #0e0e0e); + z-index: 220; +} + +.footer-content { + max-width: 1200px; + margin: 0 auto; + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 2rem; +} + +.footer-left { + flex-shrink: 0; + display: flex; + flex-direction: column; + align-items: flex-start; + text-align: left; + gap: 0.5rem; +} + +.footer-logo { + height: 28px; + width: auto; + opacity: 0.9; + transition: opacity 0.2s ease; + margin-bottom: 0.5rem; +} + +.footer-logo:hover { + opacity: 1; +} + +.footer-description { + font-size: 1rem; + color: rgba(161, 148, 184, 0.9); + margin: 0; + font-weight: 400; + display: flex; + align-items: center; + gap: 0.25rem; +} + +.footer-heart { + color: #27FF64; + font-size: 1em; + display: inline-block; +} + +.footer-creator-link { + color: #27FF64; + text-decoration: none; + transition: color 0.2s ease; +} + +.footer-creator-link:hover { + color: #ffffff; + text-decoration: underline; +} + +.footer-copyright { + font-size: 0.85rem; + color: rgba(161, 148, 184, 0.7); + margin: 0; + font-weight: 400; +} + +.footer-links { + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + align-items: flex-start; + gap: 1.25rem; +} + +.footer-link { + font-size: 0.9rem; + color: rgba(255, 255, 255, 0.7); + text-decoration: none; + font-weight: 500; + transition: color 0.2s ease; + position: relative; + padding: 0.75rem 1rem; +} + +.footer-link:hover { + color: #ffffff; +} + +@media (max-width: 768px) { + .landing-footer { + margin-top: 6rem; + padding: 3rem 1.5rem 1.5rem; + } + + .footer-content { + flex-direction: column; + align-items: center; + text-align: center; + gap: 2rem; + } + + .footer-left { + align-items: center; + text-align: center; + } + + .footer-links { + justify-content: center; + gap: 1.5rem; + } + + .footer-link { + font-size: 0.85rem; + padding: 0.5rem 0.75rem; + text-align: center; + } +} + +@media (max-width: 480px) { + .landing-footer { + margin-top: 4rem; + padding: 2rem 1rem 1rem; + } + + .footer-content { + gap: 1.5rem; + } + + .footer-links { + gap: 1rem; + flex-direction: column; + align-items: center; + } + + .footer-description { + font-size: 0.8rem; + } + + .footer-copyright { + font-size: 0.75rem; + } + + .footer-link { + font-size: 0.8rem; + padding: 0.5rem 0.75rem; + text-align: center; + } +} \ No newline at end of file diff --git a/src/components/landing/Footer/Footer.vue b/src/components/landing/Footer/Footer.vue new file mode 100644 index 0000000..24faf30 --- /dev/null +++ b/src/components/landing/Footer/Footer.vue @@ -0,0 +1,37 @@ + + + \ No newline at end of file diff --git a/src/components/landing/Hero/Hero.vue b/src/components/landing/Hero/Hero.vue new file mode 100644 index 0000000..fc32eeb --- /dev/null +++ b/src/components/landing/Hero/Hero.vue @@ -0,0 +1,122 @@ + + + + + \ No newline at end of file diff --git a/src/components/landing/PlasmaWave/PlasmaWave.vue b/src/components/landing/PlasmaWave/PlasmaWave.vue new file mode 100644 index 0000000..1b88875 --- /dev/null +++ b/src/components/landing/PlasmaWave/PlasmaWave.vue @@ -0,0 +1,335 @@ + + + \ No newline at end of file diff --git a/src/components/landing/StartBuilding/StartBuilding.css b/src/components/landing/StartBuilding/StartBuilding.css new file mode 100644 index 0000000..4ce1d65 --- /dev/null +++ b/src/components/landing/StartBuilding/StartBuilding.css @@ -0,0 +1,162 @@ +.start-building-section { + width: 100%; + padding: 80px 0; + background: transparent; + position: relative; + z-index: 22; +} + +.start-building-container { + max-width: 1200px; + margin: 0 auto; + padding: 0; +} + +.start-building-card { + width: 100%; + max-width: 1200px; + user-select: none; + margin: 0 auto; + background: linear-gradient(135deg, + #3aed6d, + rgba(24, 255, 93, 0.6)); + background-size: 200% 200%; + border-radius: 16px; + padding: 4rem 3rem; + backdrop-filter: blur(10px); + position: relative; + overflow: hidden; + transition: all 0.3s ease; + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + gap: 1.5rem; +} + +.start-building-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: url('/assets/grain.webp'); + background-size: 500px 500px; + filter: invert(100%); + mix-blend-mode: multiply; + background-repeat: repeat; + opacity: 1; + pointer-events: none; + z-index: 1; +} + +.start-building-card > * { + position: relative; + z-index: 2; +} + +.start-building-title { + color: #0e0e0e; + font-size: 2.6rem; + font-weight: 600; + margin: 0; + line-height: 1; +} + +.start-building-subtitle { + color: #0e0e0e; + font-size: 1.2rem; + font-weight: 500; + margin: -1rem 0 0 0; + opacity: 0.9; + max-width: 600px; + line-height: 1.4; +} + +.start-building-button { + background: transparent; + color: #0e0e0e; + border: 2px solid #0e0e0e; + padding: .6rem 1.6rem; + font-size: 1.1rem; + font-weight: 600; + border-radius: 50px; + cursor: pointer; + transition: all 0.2s ease; +} + +.start-building-button:hover { + background: #0e0e0e; + color: #27FF64; +} + +@media (max-width: 1280px) { + .start-building-container { + max-width: 1000px; + padding: 0 30px; + } + + .start-building-card { + padding: 2.5rem; + } +} + +@media (max-width: 768px) { + .start-building-section { + padding: 60px 0; + } + + .start-building-container { + padding: 0 20px; + } + + .start-building-card { + padding: 3rem 2rem; + border-radius: 12px; + gap: 1.25rem; + } + + .start-building-title { + font-size: 2rem; + } + + .start-building-subtitle { + font-size: 1.1rem; + } + + .start-building-button { + padding: 0.875rem 1.75rem; + font-size: 1rem; + } +} + +@media (max-width: 480px) { + .start-building-section { + padding: 40px 0; + } + + .start-building-container { + padding: 0 16px; + } + + .start-building-card { + padding: 2.5rem 1.5rem; + gap: 1rem; + } + + .start-building-title { + font-size: 1.5rem; + } + + .start-building-subtitle { + font-size: 1rem; + margin: 0; + padding: 0 0.6rem; + } + + .start-building-button { + padding: 0.75rem 1.5rem; + font-size: 0.95rem; + } +} \ No newline at end of file diff --git a/src/components/landing/StartBuilding/StartBuilding.vue b/src/components/landing/StartBuilding/StartBuilding.vue new file mode 100644 index 0000000..5d881ab --- /dev/null +++ b/src/components/landing/StartBuilding/StartBuilding.vue @@ -0,0 +1,18 @@ + + + \ No newline at end of file diff --git a/src/components/layouts/CategoryLayout.vue b/src/components/layouts/CategoryLayout.vue new file mode 100644 index 0000000..7faf18b --- /dev/null +++ b/src/components/layouts/CategoryLayout.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/src/composables/useStars.ts b/src/composables/useStars.ts new file mode 100644 index 0000000..c7500f2 --- /dev/null +++ b/src/composables/useStars.ts @@ -0,0 +1,49 @@ +import { ref, onMounted } from 'vue' +import { getStarsCount } from '@/utils/utils' + +const CACHE_KEY = 'github_stars_cache' +const CACHE_DURATION = 24 * 60 * 60 * 1000 // 24 hours + +export function useStars() { + const stars = ref(0) + + const fetchStars = async () => { + try { + const cachedData = localStorage.getItem(CACHE_KEY) + + if (cachedData) { + const { count, timestamp } = JSON.parse(cachedData) + const now = Date.now() + + if (now - timestamp < CACHE_DURATION) { + stars.value = count + return + } + } + + const count = await getStarsCount() + + localStorage.setItem(CACHE_KEY, JSON.stringify({ + count, + timestamp: Date.now() + })) + + stars.value = count + } catch (error) { + console.error('Error fetching stars:', error) + + // Fall back to cached data if available + const cachedData = localStorage.getItem(CACHE_KEY) + if (cachedData) { + const { count } = JSON.parse(cachedData) + stars.value = count + } + } + } + + onMounted(() => { + fetchStars() + }) + + return stars +} diff --git a/src/content/Animations/CountUp/CountUp.vue b/src/content/Animations/CountUp/CountUp.vue new file mode 100644 index 0000000..2c8717a --- /dev/null +++ b/src/content/Animations/CountUp/CountUp.vue @@ -0,0 +1,163 @@ + + + \ No newline at end of file diff --git a/src/content/Animations/FadeContent/FadeContent.vue b/src/content/Animations/FadeContent/FadeContent.vue new file mode 100644 index 0000000..1279e3c --- /dev/null +++ b/src/content/Animations/FadeContent/FadeContent.vue @@ -0,0 +1,66 @@ + + + \ No newline at end of file diff --git a/src/content/Backgrounds/DotGrid/DotGrid.vue b/src/content/Backgrounds/DotGrid/DotGrid.vue new file mode 100644 index 0000000..3e6512d --- /dev/null +++ b/src/content/Backgrounds/DotGrid/DotGrid.vue @@ -0,0 +1,315 @@ + + + \ No newline at end of file diff --git a/src/content/Backgrounds/LetterGlitch/LetterGlitch.vue b/src/content/Backgrounds/LetterGlitch/LetterGlitch.vue new file mode 100644 index 0000000..2005c1e --- /dev/null +++ b/src/content/Backgrounds/LetterGlitch/LetterGlitch.vue @@ -0,0 +1,246 @@ + + + \ No newline at end of file diff --git a/src/content/Backgrounds/Squares/Squares.vue b/src/content/Backgrounds/Squares/Squares.vue new file mode 100644 index 0000000..6280463 --- /dev/null +++ b/src/content/Backgrounds/Squares/Squares.vue @@ -0,0 +1,197 @@ + + + \ No newline at end of file diff --git a/src/content/TextAnimations/SplitText/SplitText.vue b/src/content/TextAnimations/SplitText/SplitText.vue new file mode 100644 index 0000000..8f2f389 --- /dev/null +++ b/src/content/TextAnimations/SplitText/SplitText.vue @@ -0,0 +1,192 @@ + + + + diff --git a/src/css/base.css b/src/css/base.css index 9f43709..eaf4da4 100644 --- a/src/css/base.css +++ b/src/css/base.css @@ -1,4 +1,5 @@ @import 'tailwindcss'; +@import 'primeicons/primeicons.css'; *, *::before, @@ -7,6 +8,8 @@ } body { + background-color: #0e0e0e; + color: #fff; min-height: 100vh; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; diff --git a/src/css/landing.css b/src/css/landing.css new file mode 100644 index 0000000..f38ea74 --- /dev/null +++ b/src/css/landing.css @@ -0,0 +1,922 @@ +.landing-wrapper { + min-height: 100dvh; + position: relative; + overflow-x: hidden; +} + +.landing-wrapper::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 300px; + height: 100vh; + background: linear-gradient(to right, #0e0e0e, transparent); + z-index: 2; + pointer-events: none; +} + +.landing-wrapper::after { + content: ''; + position: absolute; + top: 0; + right: 0; + width: 300px; + height: 100vh; + background: linear-gradient(to left, #0e0e0e, transparent); + z-index: 2; + pointer-events: none; +} + +.landing-content { + position: relative; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + height: 100%; + max-width: calc(1200px + 6em); + margin: 0 auto; + padding: 0 4em; + margin-top: 250px; + z-index: 10; +} + +.landing-title { + user-select: none; + white-space: nowrap !important; + font-size: 3.6rem; + font-weight: 500; + position: relative; + z-index: 6; + color: #fff; + margin-bottom: 1rem; + max-width: 22ch; + letter-spacing: -3px; + line-height: 1; + text-shadow: + 0 0 2px rgba(255, 255, 255, 0.1), + 0 0 4px rgba(255, 255, 255, 0.3), + 0 0 8px rgba(255, 255, 255, 0.4), + 0 0 136px rgba(60, 255, 79, 0.4); +} + +.landing-subtitle { + user-select: none; + overflow: visible !important; + font-size: 1.2rem; + text-align: left !important; + font-weight: 300; + line-height: 1.2; + color: #A7EF9E; + max-width: 30ch; + margin-bottom: 2rem; + text-shadow: + 0 0 2px rgba(255, 255, 255, 0.1), + 0 0 4px rgba(255, 255, 255, 0.3), + 0 0 8px rgba(255, 255, 255, 0.4), + 0 0 136px rgba(60, 255, 79, 0.8); + z-index: 6; +} + +.hero-split { + white-space: nowrap !important; + overflow: visible !important; +} + +.landing-button { + position: relative; + background: linear-gradient(135deg, + rgb(30, 160, 63), + rgba(24, 47, 255, 0.6)); + background-size: 200% 200%; + font-weight: 600; + font-size: 1.1rem; + border-radius: 50px; + border: none; + padding: 1rem 1rem 1rem 2.5rem; + color: white; + cursor: pointer; + isolation: isolate; + z-index: 15; + box-shadow: + 0 0 40px rgba(58, 237, 112, 0.4), + 0 0 80px rgba(92, 246, 138, 0.3), + 0 8px 32px rgba(0, 0, 0, 0.3); + transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); + animation: glow-pulse 3s ease-in-out infinite alternate; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); + letter-spacing: 0.5px; + overflow: hidden; + display: flex; + align-items: center; + justify-content: space-between; + gap: 1.6rem; +} + +.button-arrow-circle { + display: flex; + align-items: center; + justify-content: center; + width: 38px; + height: 38px; + background: rgba(255, 255, 255, 0.9); + border-radius: 50%; + color: #1d9559; + transition: all 0.3s ease; + backdrop-filter: blur(10px); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + flex-shrink: 0; +} + +.landing-button:hover .button-arrow-circle { + background: rgba(255, 255, 255, 1); + transform: translateX(4px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.landing-button span { + position: relative; + z-index: 2; + display: inline-block; + transition: all 0.3s ease; +} + +.landing-button:hover span { + transform: scale(1.01); +} + +.landing-button::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, + transparent, + rgba(255, 255, 255, 0.4), + transparent); + transition: left 0.6s ease; + z-index: 1; +} + +.landing-button::after { + content: ''; + position: absolute; + inset: -2px; + background: linear-gradient(45deg, + transparent, + rgba(255, 255, 255, 0.1), + transparent, + rgba(255, 255, 255, 0.1), + transparent); + background-size: 200% 200%; + border-radius: 50px; + z-index: -1; + animation: border-dance 4s linear infinite; + opacity: 0; + transition: opacity 0.3s ease; +} + +.landing-button:hover { + box-shadow: + 0 0 60px rgba(58, 237, 109, 0.2), + 0 0 120px rgba(92, 246, 138, 0.2), + 0 0 180px rgba(40, 217, 90, 0.2), + 0 12px 40px rgba(0, 0, 0, 0.4), + inset 0 2px 0 rgba(255, 255, 255, 0.4), + inset 0 -2px 0 rgba(0, 0, 0, 0.3); + transform: translateY(-4px) scale(1.01); + transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); + animation-duration: 1.5s; +} + +.landing-button:hover::before { + left: 100%; +} + +.landing-button:hover::after { + opacity: 1; +} + +.landing-button:active { + transform: translateY(-2px) scale(1.02); + transition: all 0.1s ease; +} + +@keyframes glow-pulse { + 0% { + filter: brightness(1) saturate(1); + } + + 100% { + filter: brightness(1.1) saturate(1.2); + } +} + +@keyframes border-dance { + 0% { + background-position: 0% 50%; + } + + 50% { + background-position: 100% 50%; + } + + 100% { + background-position: 0% 50%; + } +} + +@keyframes fadeInUp { + 0% { + opacity: 0; + transform: translateY(30px) scale(0.9); + } + + 100% { + opacity: 1; + transform: translateY(0) scale(1); + } +} + +@keyframes fadeInUpRotate1 { + 0% { + opacity: 0; + transform: translateY(30px) scale(0.9) rotate(-13deg); + } + + 100% { + opacity: 1; + transform: translateY(0) scale(1) rotate(-13deg); + } +} + +@keyframes fadeInUpRotate2 { + 0% { + opacity: 0; + transform: translateY(30px) scale(0.9) rotate(10deg); + } + + 100% { + opacity: 1; + transform: translateY(0) scale(1) rotate(10deg); + } +} + +@keyframes fadeInUpRotate3 { + 0% { + opacity: 0; + transform: translateY(30px) scale(0.9) rotate(-5deg); + } + + 100% { + opacity: 1; + transform: translateY(0) scale(1) rotate(-5deg); + } +} + +@keyframes fadeInUpMobile { + 0% { + opacity: 0; + transform: translateY(30px) scale(0.9); + } + + 100% { + opacity: 1; + transform: translateY(0) scale(1); + } +} + +@keyframes fadeInUpMobileRotate1 { + 0% { + opacity: 0; + transform: translateY(30px) scale(0.9) rotate(-13deg); + } + + 100% { + opacity: 1; + transform: translateY(0) scale(1) rotate(-13deg); + } +} + +@keyframes fadeInUpMobileRotate2 { + 0% { + opacity: 0; + transform: translateY(30px) scale(0.9) rotate(10deg); + } + + 100% { + opacity: 1; + transform: translateY(0) scale(1) rotate(10deg); + } +} + +@keyframes fadeInUpMobileRotate3 { + 0% { + opacity: 0; + transform: translateY(30px) scale(0.9) rotate(-5deg); + } + + 100% { + opacity: 1; + transform: translateY(0) scale(1) rotate(-5deg); + } +} + +.hero-main-content { + flex: 1; + display: flex; + flex-direction: column; + align-items: flex-start; + max-width: 60%; +} + +.hero-cards-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 2.4rem; + max-width: 40%; + margin-left: .6rem; +} + +.hero-cards-row { + display: flex; + gap: 2.4rem; +} + +.hero-glitch { + mix-blend-mode: screen; + border-radius: 30px !important; +} + +.hero-dot-grid { + overflow: hidden !important; + transform: translateY(5px) translateX(5px); +} + +.hero-metaballs { + mix-blend-mode: screen; + opacity: 1; +} + +.hero-falling-text .falling-text-canvas { + width: 100% !important; + height: 100% !important; +} + +.hero-lines { + width: 100% !important; + height: 100% !important; +} + +.hero-card { + width: 200px; + height: 200px; + background: linear-gradient(135deg, rgba(58, 237, 109, 0.2), rgba(40, 217, 72, 0.2)); + border: 2px solid rgba(255, 255, 255, 0.2); + border-radius: 30px; + box-shadow: + 0 30px 100px rgba(0, 16, 5, 0.95), + 0 20px 70px rgba(0, 16, 5, 0.9), + 0 15px 50px rgba(0, 16, 5, 0.8), + 0 10px 30px rgba(0, 16, 7, 0.7), + 0 8px 32px rgba(58, 237, 121, 0.4), + inset 0 1px 0 rgba(255, 255, 255, 0.2); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + transition: all 0.3s ease; + position: relative; + overflow: hidden; + cursor: pointer; + opacity: 0; +} + +.hero-card-1 { + animation: fadeInUpRotate1 0.8s ease-out forwards; + animation-delay: 0.2s; + transform: translateY(0) scale(1) rotate(-13deg); +} + +.hero-card-2 { + animation: fadeInUpRotate2 0.8s ease-out forwards; + animation-delay: 0.4s; + transform: translateY(0) scale(1) rotate(10deg); +} + +.hero-card-3 { + animation: fadeInUpRotate3 0.8s ease-out forwards; + animation-delay: 0.6s; + transform: translateY(0) scale(1) rotate(-5deg); +} + +.hero-card:hover { + filter: grayscale(50%); + box-shadow: + 0 50px 140px rgba(0, 16, 5, 0.98), + 0 35px 100px rgba(0, 16, 4, 0.95), + 0 25px 70px rgba(0, 16, 4, 0.9), + 0 15px 50px rgba(0, 16, 4, 0.8), + 0 12px 40px rgba(58, 237, 115, 0.6), + inset 0 1px 0 rgba(255, 255, 255, 0.3); + backdrop-filter: blur(25px); + -webkit-backdrop-filter: blur(25px); +} + +.hero-card::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); + transition: left 0.5s ease; +} + +.hero-card:hover::before { + left: 100%; +} + +@media (max-width: 1440px) { + .landing-title { + font-size: 3.6rem; + } + + .landing-subtitle { + font-size: 1.3rem; + } + + .landing-content { + margin-top: 250px; + } +} + +@media (max-width: 1366px) { + .landing-title { + font-size: 3.6rem; + } + + .landing-subtitle { + font-size: 1.2rem; + } + + .landing-content { + margin-top: 250px; + } +} + +@media (max-width: 1200px) { + .landing-title { + font-size: 3.6rem; + } + + .landing-subtitle { + font-size: 1.1rem; + } + + .landing-content { + margin-top: 250px; + } +} + +@media (max-width: 1100px) { + .landing-title { + font-size: 3.6rem; + } + + .landing-subtitle { + font-size: 1rem; + } + + .landing-content { + margin-top: 250px; + } +} + +@media (max-width: 1024px) { + .landing-title { + font-size: 3.6rem; + } + + .landing-subtitle { + font-size: 0.95rem; + } + + .landing-content { + margin-top: 300px; + padding: 0 2em; + max-width: calc(1200px + 2em); + flex-direction: column; + align-items: center; + } + + .hero-main-content { + max-width: 100%; + align-items: center; + text-align: center; + margin-bottom: 2rem; + } + + .hero-cards-container { + max-width: 100%; + width: 100%; + margin-left: 0; + margin-top: 2rem; + flex-direction: row; + gap: 1.5rem; + justify-content: space-between; + } + + .hero-cards-row { + display: contents; + } + + .hero-card { + flex: 1; + height: 120px; + max-width: calc(33.333% - 1rem); + } + + .hero-card-1 { + animation: fadeInUpMobileRotate1 0.8s ease-out forwards; + animation-delay: 0.2s; + transform: translateY(0) scale(1) rotate(-13deg); + } + + .hero-card-2 { + animation: fadeInUpMobileRotate2 0.8s ease-out forwards; + animation-delay: 0.4s; + transform: translateY(0) scale(1) rotate(10deg); + } + + .hero-card-3 { + animation: fadeInUpMobileRotate3 0.8s ease-out forwards; + animation-delay: 0.6s; + transform: translateY(0) scale(1) rotate(-5deg); + } + + .landing-wrapper>div[style*="position: absolute"][style*="width: 100vw"][style*="height: 100vh"] { + opacity: 0.7; + } +} + +@media (max-width: 950px) { + .landing-title { + font-size: 3.6rem; + } + + .landing-subtitle { + font-size: 0.9rem; + text-align: center !important; + } + + .landing-content { + margin-top: 290px; + } +} + +@media (max-width: 900px) { + .landing-title { + font-size: 3.6rem; + } + + .landing-subtitle { + font-size: 0.85rem; + text-align: center !important; + } + + .landing-content { + margin-top: 280px; + } + + .landing-wrapper::before { + width: 100px; + } + + .landing-wrapper::after { + width: 100px; + } +} + +@media (max-width: 820px) { + .landing-title { + font-size: 3.4rem; + } + + .landing-subtitle { + font-size: 0.8rem; + } + + .landing-content { + margin-top: 270px; + } +} + +@media (max-width: 768px) { + .landing-title { + font-size: 3.2rem; + text-align: center; + max-width: 100%; + } + + .landing-subtitle { + font-size: 0.75rem; + text-align: center !important; + max-width: 100%; + } + + .landing-content { + margin-top: 260px; + align-items: center; + padding: 0 1.5rem; + } + + .landing-button { + padding: 0.8rem 0.8rem 0.8rem 1.8rem; + font-size: 1rem; + gap: 1.2rem; + } + + .button-arrow-circle { + width: 32px; + height: 32px; + } + + .hero-cards-container { + flex-direction: row; + gap: 1.2rem; + width: 100%; + justify-content: space-between; + } + + .hero-cards-row { + display: contents; + } + + .hero-card { + flex: 1; + height: 120px; + max-width: calc(33.333% - 0.8rem); + } + + .hero-card-1 { + animation: fadeInUpMobileRotate1 0.8s ease-out forwards; + animation-delay: 0.2s; + transform: translateY(0) scale(1) rotate(-13deg); + } + + .hero-card-2 { + animation: fadeInUpMobileRotate2 0.8s ease-out forwards; + animation-delay: 0.4s; + transform: translateY(0) scale(1) rotate(10deg); + } + + .hero-card-3 { + animation: fadeInUpMobileRotate3 0.8s ease-out forwards; + animation-delay: 0.6s; + transform: translateY(0) scale(1) rotate(-5deg); + } + + .landing-wrapper>div[style*="position: absolute"][style*="width: 100vw"][style*="height: 100vh"] { + opacity: 0.5; + } +} + +@media (max-width: 700px) { + .landing-title { + font-size: 2.6rem; + margin-bottom: 2rem; + text-align: center; + max-width: 100%; + } + + .landing-subtitle { + font-size: 1rem; + text-align: center !important; + max-width: 100%; + } + + .landing-content { + margin-top: 250px; + align-items: center; + padding: 0 1.5rem; + } +} + +@media (max-width: 640px) { + .landing-title { + font-size: 2.4rem; + text-align: center; + max-width: 100%; + } + + .landing-subtitle { + text-align: center !important; + max-width: 100%; + } + + .landing-content { + margin-top: 240px; + align-items: center; + padding: 0 1.5rem; + } +} + +@media (max-width: 580px) { + .landing-title { + font-size: 2.2rem; + text-align: center; + max-width: 100%; + } + + .landing-subtitle { + text-align: center !important; + max-width: 100%; + } + + .landing-content { + margin-top: 230px; + align-items: center; + padding: 0 1.5rem; + } +} + +@media (max-width: 520px) { + .landing-title { + font-size: 2rem; + text-align: center; + max-width: 100%; + } + + .landing-subtitle { + text-align: center !important; + max-width: 100%; + } + + .landing-content { + margin-top: 220px; + align-items: center; + padding: 0 1.5rem; + } +} + +@media (max-width: 480px) { + .landing-title { + font-size: 1.8rem; + text-align: center; + max-width: 100%; + } + + .landing-subtitle { + text-align: center !important; + max-width: 100%; + } + + .landing-content { + margin-top: 210px; + align-items: center; + padding: 0 1.5rem; + } + + .landing-button { + padding: 0.7rem 0.7rem 0.7rem 1.5rem; + font-size: 0.95rem; + gap: 1rem; + } + + .button-arrow-circle { + width: 28px; + height: 28px; + } + + .hero-cards-container { + flex-direction: row; + gap: 1rem; + width: 100%; + justify-content: space-between; + } + + .hero-cards-row { + display: contents; + } + + .hero-card { + flex: 1; + height: 120px; + max-width: calc(33.333% - 0.666rem); + } + + .hero-card-1 { + animation: fadeInUpMobileRotate1 0.8s ease-out forwards; + animation-delay: 0.2s; + transform: translateY(0) scale(1) rotate(-13deg); + } + + .hero-card-2 { + animation: fadeInUpMobileRotate2 0.8s ease-out forwards; + animation-delay: 0.4s; + transform: translateY(0) scale(1) rotate(10deg); + } + + .hero-card-3 { + animation: fadeInUpMobileRotate3 0.8s ease-out forwards; + animation-delay: 0.6s; + transform: translateY(0) scale(1) rotate(-5deg); + } + + .landing-wrapper>div[style*="position: absolute"][style*="width: 100vw"][style*="height: 100vh"] { + opacity: 0.3; + } +} + +@media (max-width: 430px) { + .landing-title { + font-size: 1.6rem; + letter-spacing: -1px; + text-align: center; + max-width: 100%; + } + + .landing-subtitle { + text-align: center !important; + max-width: 100%; + } + + .landing-content { + margin-top: 205px; + align-items: center; + padding: 0 1.5rem; + } +} + +@media (max-width: 390px) { + .landing-title { + font-size: 1.8rem; + letter-spacing: -1px; + text-align: center; + max-width: 100%; + } + + .landing-subtitle { + text-align: center !important; + max-width: 100%; + } + + .landing-content { + margin-top: 202px; + align-items: center; + padding: 0 1.5rem; + } +} + +@media (max-width: 375px) { + .landing-title { + font-size: 1.6rem; + letter-spacing: -1px; + text-align: center; + max-width: 100%; + } + + .landing-subtitle { + text-align: center !important; + max-width: 100%; + } + + .landing-content { + margin-top: 150px; + align-items: center; + padding: 0 1.5rem; + } + + .landing-button { + padding: 0.6rem 0.6rem 0.6rem 1.2rem; + font-size: 0.9rem; + gap: 0.8rem; + } + + .button-arrow-circle { + width: 26px; + height: 26px; + } +} + +/* Mobile hero background styles */ +.mobile-hero-background-container { + position: absolute; + inset: 0; + overflow: hidden; + width: 100vw; + height: 100vh; + z-index: -1; +} + +.mobile-hero-background-image { + width: 100%; + height: 100%; + object-fit: cover; + opacity: 0.6; +} \ No newline at end of file diff --git a/src/css/main.css b/src/css/main.css index 08fbe90..3e7cf8d 100644 --- a/src/css/main.css +++ b/src/css/main.css @@ -1,2 +1,3 @@ @import './base.css'; +@import './landing.css'; diff --git a/src/pages/CategoryPage.vue b/src/pages/CategoryPage.vue new file mode 100644 index 0000000..d8fe378 --- /dev/null +++ b/src/pages/CategoryPage.vue @@ -0,0 +1,11 @@ + + + diff --git a/src/pages/LandingPage.vue b/src/pages/LandingPage.vue new file mode 100644 index 0000000..8b200ea --- /dev/null +++ b/src/pages/LandingPage.vue @@ -0,0 +1,38 @@ + + + diff --git a/src/router/index.ts b/src/router/index.ts index b7cb91b..5b6cd6b 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,5 +1,7 @@ import { createRouter, createWebHistory } from 'vue-router' -import App from '@/App.vue' +import LandingPage from '@/pages/LandingPage.vue' +import CategoryPage from '@/pages/CategoryPage.vue' +import CategoryLayout from '@/components/layouts/CategoryLayout.vue' const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), @@ -7,7 +9,18 @@ const router = createRouter({ { path: '/', name: 'home', - component: App, + component: LandingPage, + }, + { + path: '/:category/:subcategory', + name: 'category', + component: CategoryLayout, + children: [ + { + path: '', + component: CategoryPage, + } + ] } ], }) diff --git a/src/utils/utils.ts b/src/utils/utils.ts new file mode 100644 index 0000000..740eca8 --- /dev/null +++ b/src/utils/utils.ts @@ -0,0 +1,20 @@ +/** + * Fetches the star count for a GitHub repository + * @param repo - Repository in format "owner/repo" + * @returns Promise - The star count + */ +export const getStarsCount = async (repo: string = 'DavidHDev/vue-bits'): Promise => { + try { + const response = await fetch(`https://api.github.com/repos/${repo}`) + + if (!response.ok) { + throw new Error(`GitHub API error: ${response.status}`) + } + + const data = await response.json() + return data.stargazers_count || 0 + } catch (error) { + console.error('Error fetching GitHub stars:', error) + throw error + } +} diff --git a/tsconfig.app.json b/tsconfig.app.json index 913b8f2..0c7dc61 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -1,12 +1,19 @@ { "extends": "@vue/tsconfig/tsconfig.dom.json", - "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], - "exclude": ["src/**/__tests__/*"], + "include": [ + "env.d.ts", + "src/**/*", + "src/**/*.vue" + ], + "exclude": [ + "src/**/__tests__/*" + ], "compilerOptions": { "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "paths": { - "@/*": ["./src/*"] + "@/*": [ + "./src/*" + ] } } -} +} \ No newline at end of file