@beknurakhmed/webforge-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +212 -0
- package/dist/index.js +386 -0
- package/package.json +63 -0
- package/templates/angular/angular.json +36 -0
- package/templates/angular/package.json +29 -0
- package/templates/angular/src/app/app.component.ts +27 -0
- package/templates/angular/src/index.html +11 -0
- package/templates/angular/src/main.ts +4 -0
- package/templates/angular/src/styles.css +24 -0
- package/templates/angular/tsconfig.json +27 -0
- package/templates/base/README.md +16 -0
- package/templates/base/_gitignore +11 -0
- package/templates/extras/eslint/config/eslint.config.js +18 -0
- package/templates/extras/eslint/deps.json +7 -0
- package/templates/extras/prettier/config/.prettierignore +6 -0
- package/templates/extras/prettier/config/.prettierrc +7 -0
- package/templates/extras/prettier/deps.json +5 -0
- package/templates/nextjs/next.config.ts +5 -0
- package/templates/nextjs/package.json +16 -0
- package/templates/nextjs/src/app/globals.css +36 -0
- package/templates/nextjs/src/app/layout.tsx +19 -0
- package/templates/nextjs/src/app/page.tsx +8 -0
- package/templates/nextjs/tsconfig.json +21 -0
- package/templates/nuxt/app.vue +3 -0
- package/templates/nuxt/assets/css/main.css +24 -0
- package/templates/nuxt/nuxt.config.ts +5 -0
- package/templates/nuxt/package.json +17 -0
- package/templates/nuxt/pages/index.vue +20 -0
- package/templates/nuxt/tsconfig.json +3 -0
- package/templates/overlays/blog/react/src/App.css +41 -0
- package/templates/overlays/blog/react/src/App.tsx +39 -0
- package/templates/overlays/blog/react/src/components/BlogFooter.tsx +7 -0
- package/templates/overlays/blog/react/src/components/BlogHeader.tsx +15 -0
- package/templates/overlays/blog/react/src/components/BlogSidebar.tsx +26 -0
- package/templates/overlays/blog/react/src/components/PostList.tsx +27 -0
- package/templates/overlays/crm/react/src/App.css +48 -0
- package/templates/overlays/crm/react/src/App.tsx +49 -0
- package/templates/overlays/crm/react/src/components/ContactsTable.tsx +40 -0
- package/templates/overlays/crm/react/src/components/Filters.tsx +22 -0
- package/templates/overlays/crm/react/src/components/Sidebar.tsx +25 -0
- package/templates/overlays/crm/react/src/components/StatsCards.tsx +26 -0
- package/templates/overlays/dashboard/react/src/App.css +64 -0
- package/templates/overlays/dashboard/react/src/App.tsx +30 -0
- package/templates/overlays/dashboard/react/src/components/ChartPlaceholder.tsx +18 -0
- package/templates/overlays/dashboard/react/src/components/DataTable.tsx +44 -0
- package/templates/overlays/dashboard/react/src/components/KPICards.tsx +22 -0
- package/templates/overlays/dashboard/react/src/components/Sidebar.tsx +24 -0
- package/templates/overlays/ecommerce/react/src/App.css +82 -0
- package/templates/overlays/ecommerce/react/src/App.tsx +68 -0
- package/templates/overlays/ecommerce/react/src/components/Cart.tsx +47 -0
- package/templates/overlays/ecommerce/react/src/components/Footer.tsx +29 -0
- package/templates/overlays/ecommerce/react/src/components/Header.tsx +26 -0
- package/templates/overlays/ecommerce/react/src/components/ProductGrid.tsx +32 -0
- package/templates/overlays/ecommerce/vue/src/App.vue +44 -0
- package/templates/overlays/ecommerce/vue/src/components/CartPanel.vue +46 -0
- package/templates/overlays/ecommerce/vue/src/components/ProductGrid.vue +40 -0
- package/templates/overlays/ecommerce/vue/src/components/StoreFooter.vue +17 -0
- package/templates/overlays/ecommerce/vue/src/components/StoreHeader.vue +33 -0
- package/templates/overlays/landing/angular/src/app/app.component.ts +21 -0
- package/templates/overlays/landing/angular/src/app/components/cta.component.ts +24 -0
- package/templates/overlays/landing/angular/src/app/components/features.component.ts +42 -0
- package/templates/overlays/landing/angular/src/app/components/footer.component.ts +45 -0
- package/templates/overlays/landing/angular/src/app/components/hero.component.ts +41 -0
- package/templates/overlays/landing/nextjs/src/app/components/CTA.tsx +12 -0
- package/templates/overlays/landing/nextjs/src/app/components/Features.tsx +26 -0
- package/templates/overlays/landing/nextjs/src/app/components/Footer.tsx +27 -0
- package/templates/overlays/landing/nextjs/src/app/components/Hero.tsx +22 -0
- package/templates/overlays/landing/nextjs/src/app/globals.css +49 -0
- package/templates/overlays/landing/nextjs/src/app/page.tsx +15 -0
- package/templates/overlays/landing/nuxt/components/LandingCta.vue +18 -0
- package/templates/overlays/landing/nuxt/components/LandingFeatures.vue +36 -0
- package/templates/overlays/landing/nuxt/components/LandingFooter.vue +29 -0
- package/templates/overlays/landing/nuxt/components/LandingHero.vue +35 -0
- package/templates/overlays/landing/nuxt/pages/index.vue +15 -0
- package/templates/overlays/landing/react/src/App.css +70 -0
- package/templates/overlays/landing/react/src/App.tsx +18 -0
- package/templates/overlays/landing/react/src/components/CTA.tsx +14 -0
- package/templates/overlays/landing/react/src/components/Features.tsx +50 -0
- package/templates/overlays/landing/react/src/components/Footer.tsx +34 -0
- package/templates/overlays/landing/react/src/components/Hero.tsx +22 -0
- package/templates/overlays/landing/vanilla/src/main.ts +68 -0
- package/templates/overlays/landing/vanilla/src/style.css +43 -0
- package/templates/overlays/landing/vue/src/App.vue +19 -0
- package/templates/overlays/landing/vue/src/components/AppFooter.vue +44 -0
- package/templates/overlays/landing/vue/src/components/CTA.vue +21 -0
- package/templates/overlays/landing/vue/src/components/Features.vue +36 -0
- package/templates/overlays/landing/vue/src/components/Hero.vue +35 -0
- package/templates/overlays/portfolio/react/src/App.css +81 -0
- package/templates/overlays/portfolio/react/src/App.tsx +20 -0
- package/templates/overlays/portfolio/react/src/components/ContactForm.tsx +29 -0
- package/templates/overlays/portfolio/react/src/components/HeroSection.tsx +24 -0
- package/templates/overlays/portfolio/react/src/components/PortfolioFooter.tsx +14 -0
- package/templates/overlays/portfolio/react/src/components/Projects.tsx +33 -0
- package/templates/overlays/portfolio/react/src/components/Skills.tsx +27 -0
- package/templates/react/index.html +13 -0
- package/templates/react/package.json +19 -0
- package/templates/react/public/vite.svg +1 -0
- package/templates/react/src/App.css +11 -0
- package/templates/react/src/App.tsx +12 -0
- package/templates/react/src/index.css +42 -0
- package/templates/react/src/main.tsx +10 -0
- package/templates/react/vite.config.ts +6 -0
- package/templates/state/mobx/deps.json +6 -0
- package/templates/state/mobx/react/src/store/AppStore.ts +15 -0
- package/templates/state/ngrx/angular/src/app/store/app.state.ts +22 -0
- package/templates/state/ngrx/deps.json +7 -0
- package/templates/state/pinia/deps.json +5 -0
- package/templates/state/pinia/vue/src/store/useAppStore.ts +15 -0
- package/templates/state/redux/deps.json +6 -0
- package/templates/state/redux/react/src/store/counterSlice.ts +20 -0
- package/templates/state/redux/react/src/store/index.ts +11 -0
- package/templates/state/rxjs/angular/src/app/services/app-state.service.ts +18 -0
- package/templates/state/rxjs/deps.json +3 -0
- package/templates/state/zustand/deps.json +5 -0
- package/templates/state/zustand/react/src/store/useStore.ts +15 -0
- package/templates/styling/angular-material/deps.json +6 -0
- package/templates/styling/ant-design/deps.json +5 -0
- package/templates/styling/chakra-ui/deps.json +5 -0
- package/templates/styling/css-modules/deps.json +3 -0
- package/templates/styling/material-ui/deps.json +7 -0
- package/templates/styling/scss/deps.json +5 -0
- package/templates/styling/styled-components/deps.json +5 -0
- package/templates/styling/tailwind/config/postcss.config.js +5 -0
- package/templates/styling/tailwind/config/tailwind.config.js +11 -0
- package/templates/styling/tailwind/deps.json +6 -0
- package/templates/vanilla/index.html +13 -0
- package/templates/vanilla/package.json +14 -0
- package/templates/vanilla/src/main.ts +9 -0
- package/templates/vanilla/src/style.css +36 -0
- package/templates/vanilla/vite.config.ts +3 -0
- package/templates/vue/index.html +13 -0
- package/templates/vue/package.json +18 -0
- package/templates/vue/src/App.vue +23 -0
- package/templates/vue/src/main.ts +5 -0
- package/templates/vue/src/style.css +39 -0
- package/templates/vue/vite.config.ts +6 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Product } from '../App';
|
|
2
|
+
|
|
3
|
+
interface ProductGridProps {
|
|
4
|
+
products: Product[];
|
|
5
|
+
onAddToCart: (product: Product) => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function ProductGrid({ products, onAddToCart }: ProductGridProps) {
|
|
9
|
+
return (
|
|
10
|
+
<section className="product-section">
|
|
11
|
+
<h2>All Products</h2>
|
|
12
|
+
<div className="product-grid">
|
|
13
|
+
{products.map((product) => (
|
|
14
|
+
<div key={product.id} className="product-card">
|
|
15
|
+
<div className="product-image">{product.image}</div>
|
|
16
|
+
<div className="product-info">
|
|
17
|
+
<span className="product-category">{product.category}</span>
|
|
18
|
+
<h3>{product.name}</h3>
|
|
19
|
+
<p>{product.description}</p>
|
|
20
|
+
<div className="product-footer">
|
|
21
|
+
<span className="product-price">${product.price.toFixed(2)}</span>
|
|
22
|
+
<button className="add-to-cart" onClick={() => onAddToCart(product)}>
|
|
23
|
+
Add to Cart
|
|
24
|
+
</button>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
))}
|
|
29
|
+
</div>
|
|
30
|
+
</section>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, computed } from 'vue';
|
|
3
|
+
import StoreHeader from './components/StoreHeader.vue';
|
|
4
|
+
import ProductGrid from './components/ProductGrid.vue';
|
|
5
|
+
import CartPanel from './components/CartPanel.vue';
|
|
6
|
+
import StoreFooter from './components/StoreFooter.vue';
|
|
7
|
+
|
|
8
|
+
interface Product { id: number; name: string; price: number; image: string; category: string; description: string; }
|
|
9
|
+
interface CartItem extends Product { quantity: number; }
|
|
10
|
+
|
|
11
|
+
const products: Product[] = [
|
|
12
|
+
{ id: 1, name: 'Wireless Headphones', price: 79.99, image: '🎧', category: 'Electronics', description: 'Premium sound with noise cancellation.' },
|
|
13
|
+
{ id: 2, name: 'Smart Watch', price: 199.99, image: '⌚', category: 'Electronics', description: 'Track fitness and stay connected.' },
|
|
14
|
+
{ id: 3, name: 'Laptop Stand', price: 49.99, image: '💻', category: 'Accessories', description: 'Ergonomic aluminum stand.' },
|
|
15
|
+
{ id: 4, name: 'Mechanical Keyboard', price: 129.99, image: '⌨️', category: 'Electronics', description: 'Tactile switches with RGB.' },
|
|
16
|
+
{ id: 5, name: 'USB-C Hub', price: 39.99, image: '🔌', category: 'Accessories', description: '7-in-1 hub with 4K HDMI.' },
|
|
17
|
+
{ id: 6, name: 'Webcam HD', price: 69.99, image: '📷', category: 'Electronics', description: '1080p with built-in mic.' },
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const cartItems = ref<CartItem[]>([]);
|
|
21
|
+
const isCartOpen = ref(false);
|
|
22
|
+
const cartCount = computed(() => cartItems.value.reduce((sum, item) => sum + item.quantity, 0));
|
|
23
|
+
|
|
24
|
+
function addToCart(product: Product) {
|
|
25
|
+
const existing = cartItems.value.find((item) => item.id === product.id);
|
|
26
|
+
if (existing) { existing.quantity++; }
|
|
27
|
+
else { cartItems.value.push({ ...product, quantity: 1 }); }
|
|
28
|
+
}
|
|
29
|
+
function removeFromCart(id: number) { cartItems.value = cartItems.value.filter((item) => item.id !== id); }
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<template>
|
|
33
|
+
<div class="ecommerce">
|
|
34
|
+
<StoreHeader :cart-count="cartCount" @toggle-cart="isCartOpen = !isCartOpen" />
|
|
35
|
+
<main class="main"><ProductGrid :products="products" @add-to-cart="addToCart" /></main>
|
|
36
|
+
<CartPanel v-if="isCartOpen" :items="cartItems" @remove="removeFromCart" @close="isCartOpen = false" />
|
|
37
|
+
<StoreFooter />
|
|
38
|
+
</div>
|
|
39
|
+
</template>
|
|
40
|
+
|
|
41
|
+
<style>
|
|
42
|
+
.ecommerce { min-height: 100vh; display: flex; flex-direction: column; }
|
|
43
|
+
.main { flex: 1; max-width: 1200px; margin: 0 auto; padding: 2rem; width: 100%; }
|
|
44
|
+
</style>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
interface CartItem { id: number; name: string; price: number; image: string; quantity: number; }
|
|
4
|
+
const props = defineProps<{ items: CartItem[] }>();
|
|
5
|
+
defineEmits<{ remove: [id: number]; close: [] }>();
|
|
6
|
+
const total = computed(() => props.items.reduce((sum, item) => sum + item.price * item.quantity, 0));
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<div class="cart-overlay" @click="$emit('close')">
|
|
11
|
+
<div class="cart-panel" @click.stop>
|
|
12
|
+
<div class="cart-header"><h2>Shopping Cart</h2><button @click="$emit('close')">X</button></div>
|
|
13
|
+
<p v-if="items.length === 0" class="cart-empty">Your cart is empty</p>
|
|
14
|
+
<template v-else>
|
|
15
|
+
<div class="cart-items">
|
|
16
|
+
<div v-for="item in items" :key="item.id" class="cart-item">
|
|
17
|
+
<span>{{ item.image }}</span>
|
|
18
|
+
<div><h4>{{ item.name }}</h4><p>Qty: {{ item.quantity }} x ${{ item.price.toFixed(2) }}</p></div>
|
|
19
|
+
<button @click="$emit('remove', item.id)">Remove</button>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="cart-footer">
|
|
23
|
+
<div class="cart-total"><span>Total:</span><strong>${{ total.toFixed(2) }}</strong></div>
|
|
24
|
+
<button class="checkout-btn">Checkout</button>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<style scoped>
|
|
32
|
+
.cart-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.4); z-index: 50; }
|
|
33
|
+
.cart-panel { position: fixed; top: 0; right: 0; bottom: 0; width: 400px; max-width: 100%; background: white; box-shadow: -4px 0 25px rgba(0,0,0,0.1); display: flex; flex-direction: column; }
|
|
34
|
+
.cart-header { display: flex; justify-content: space-between; align-items: center; padding: 1.5rem; border-bottom: 1px solid #e5e7eb; }
|
|
35
|
+
.cart-header h2 { margin: 0; font-size: 1.25rem; }
|
|
36
|
+
.cart-header button { background: none; border: none; font-size: 1.25rem; cursor: pointer; }
|
|
37
|
+
.cart-empty { text-align: center; padding: 3rem; color: #9ca3af; }
|
|
38
|
+
.cart-items { flex: 1; overflow-y: auto; padding: 1rem; }
|
|
39
|
+
.cart-item { display: flex; align-items: center; gap: 1rem; padding: 1rem 0; border-bottom: 1px solid #f3f4f6; }
|
|
40
|
+
.cart-item h4 { margin: 0; font-size: 0.95rem; }
|
|
41
|
+
.cart-item p { color: #6b7280; font-size: 0.85rem; margin: 0; }
|
|
42
|
+
.cart-item button { background: none; border: none; color: #ef4444; cursor: pointer; margin-left: auto; }
|
|
43
|
+
.cart-footer { padding: 1.5rem; border-top: 1px solid #e5e7eb; }
|
|
44
|
+
.cart-total { display: flex; justify-content: space-between; margin-bottom: 1rem; font-size: 1.1rem; }
|
|
45
|
+
.checkout-btn { width: 100%; background: #4f46e5; color: white; border: none; padding: 0.75rem; border-radius: 8px; font-size: 1rem; font-weight: 600; cursor: pointer; }
|
|
46
|
+
</style>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
interface Product { id: number; name: string; price: number; image: string; category: string; description: string; }
|
|
3
|
+
defineProps<{ products: Product[] }>();
|
|
4
|
+
defineEmits<{ 'add-to-cart': [product: Product] }>();
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<section class="product-section">
|
|
9
|
+
<h2>All Products</h2>
|
|
10
|
+
<div class="product-grid">
|
|
11
|
+
<div v-for="p in products" :key="p.id" class="product-card">
|
|
12
|
+
<div class="product-image">{{ p.image }}</div>
|
|
13
|
+
<div class="product-info">
|
|
14
|
+
<span class="product-category">{{ p.category }}</span>
|
|
15
|
+
<h3>{{ p.name }}</h3>
|
|
16
|
+
<p>{{ p.description }}</p>
|
|
17
|
+
<div class="product-footer">
|
|
18
|
+
<span class="product-price">${{ p.price.toFixed(2) }}</span>
|
|
19
|
+
<button class="add-to-cart" @click="$emit('add-to-cart', p)">Add to Cart</button>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
</section>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<style scoped>
|
|
28
|
+
.product-section h2 { font-size: 1.75rem; font-weight: 700; margin-bottom: 1.5rem; }
|
|
29
|
+
.product-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 1.5rem; }
|
|
30
|
+
.product-card { border: 1px solid #e5e7eb; border-radius: 12px; overflow: hidden; transition: all 0.2s; }
|
|
31
|
+
.product-card:hover { box-shadow: 0 8px 25px rgba(0,0,0,0.08); transform: translateY(-2px); }
|
|
32
|
+
.product-image { font-size: 4rem; text-align: center; padding: 2rem; background: #f9fafb; }
|
|
33
|
+
.product-info { padding: 1.25rem; }
|
|
34
|
+
.product-category { font-size: 0.75rem; color: #4f46e5; font-weight: 600; text-transform: uppercase; }
|
|
35
|
+
.product-info h3 { font-size: 1.1rem; margin: 0.25rem 0; }
|
|
36
|
+
.product-info p { color: #6b7280; font-size: 0.9rem; margin-bottom: 1rem; }
|
|
37
|
+
.product-footer { display: flex; justify-content: space-between; align-items: center; }
|
|
38
|
+
.product-price { font-size: 1.25rem; font-weight: 700; }
|
|
39
|
+
.add-to-cart { background: #4f46e5; color: white; border: none; padding: 0.5rem 1rem; border-radius: 6px; cursor: pointer; font-weight: 500; }
|
|
40
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<footer class="store-footer">
|
|
3
|
+
<div class="footer-content">
|
|
4
|
+
<h3>{{projectName}}</h3>
|
|
5
|
+
<p>Your one-stop shop for quality products.</p>
|
|
6
|
+
</div>
|
|
7
|
+
<div class="footer-bottom"><p>© 2025 {{projectName}}. All rights reserved.</p></div>
|
|
8
|
+
</footer>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<style scoped>
|
|
12
|
+
.store-footer { background: #111827; color: #d1d5db; padding: 3rem 2rem 1.5rem; margin-top: auto; }
|
|
13
|
+
.footer-content { max-width: 1200px; margin: 0 auto; }
|
|
14
|
+
.footer-content h3 { color: white; margin-bottom: 0.5rem; }
|
|
15
|
+
.footer-bottom { border-top: 1px solid #374151; margin-top: 2rem; padding-top: 1rem; text-align: center; }
|
|
16
|
+
.footer-bottom p { font-size: 0.8rem; color: #6b7280; }
|
|
17
|
+
</style>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
defineProps<{ cartCount: number }>();
|
|
3
|
+
defineEmits<{ 'toggle-cart': [] }>();
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<template>
|
|
7
|
+
<header class="store-header">
|
|
8
|
+
<div class="header-content">
|
|
9
|
+
<h1 class="store-logo">{{projectName}}</h1>
|
|
10
|
+
<nav class="store-nav">
|
|
11
|
+
<a href="#" class="active">All Products</a>
|
|
12
|
+
<a href="#">Electronics</a>
|
|
13
|
+
<a href="#">Accessories</a>
|
|
14
|
+
</nav>
|
|
15
|
+
<div class="header-actions">
|
|
16
|
+
<input type="text" class="search-input" placeholder="Search products..." />
|
|
17
|
+
<button class="cart-btn" @click="$emit('toggle-cart')">Cart ({{ cartCount }})</button>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</header>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<style scoped>
|
|
24
|
+
.store-header { background: white; border-bottom: 1px solid #e5e7eb; position: sticky; top: 0; z-index: 10; }
|
|
25
|
+
.header-content { max-width: 1200px; margin: 0 auto; padding: 1rem 2rem; display: flex; align-items: center; gap: 2rem; flex-wrap: wrap; }
|
|
26
|
+
.store-logo { font-size: 1.5rem; color: #4f46e5; margin: 0; }
|
|
27
|
+
.store-nav { display: flex; gap: 1.5rem; }
|
|
28
|
+
.store-nav a { text-decoration: none; color: #6b7280; font-weight: 500; }
|
|
29
|
+
.store-nav a.active { color: #4f46e5; }
|
|
30
|
+
.header-actions { display: flex; gap: 1rem; margin-left: auto; align-items: center; }
|
|
31
|
+
.search-input { padding: 0.5rem 1rem; border: 1px solid #d1d5db; border-radius: 8px; }
|
|
32
|
+
.cart-btn { background: #4f46e5; color: white; border: none; padding: 0.5rem 1.25rem; border-radius: 8px; cursor: pointer; font-weight: 600; }
|
|
33
|
+
</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { HeroComponent } from './components/hero.component';
|
|
3
|
+
import { FeaturesComponent } from './components/features.component';
|
|
4
|
+
import { CtaComponent } from './components/cta.component';
|
|
5
|
+
import { FooterComponent } from './components/footer.component';
|
|
6
|
+
|
|
7
|
+
@Component({
|
|
8
|
+
selector: 'app-root',
|
|
9
|
+
standalone: true,
|
|
10
|
+
imports: [HeroComponent, FeaturesComponent, CtaComponent, FooterComponent],
|
|
11
|
+
template: `
|
|
12
|
+
<div class="landing">
|
|
13
|
+
<app-hero />
|
|
14
|
+
<app-features />
|
|
15
|
+
<app-cta />
|
|
16
|
+
<app-footer />
|
|
17
|
+
</div>
|
|
18
|
+
`,
|
|
19
|
+
styles: [`.landing { min-height: 100vh; }`]
|
|
20
|
+
})
|
|
21
|
+
export class AppComponent {}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Component({
|
|
4
|
+
selector: 'app-cta',
|
|
5
|
+
standalone: true,
|
|
6
|
+
template: `
|
|
7
|
+
<section id="cta" class="cta">
|
|
8
|
+
<h2>Ready to Get Started?</h2>
|
|
9
|
+
<p>Join thousands of developers building amazing products.</p>
|
|
10
|
+
<button class="btn btn-primary btn-large">Start Free Trial</button>
|
|
11
|
+
<p class="note">No credit card required</p>
|
|
12
|
+
</section>
|
|
13
|
+
`,
|
|
14
|
+
styles: [`
|
|
15
|
+
.cta { background: #f9fafb; padding: 5rem 2rem; text-align: center; }
|
|
16
|
+
.cta h2 { font-size: 2.5rem; font-weight: 700; margin-bottom: 1rem; }
|
|
17
|
+
.cta p { color: #6b7280; margin-bottom: 2rem; }
|
|
18
|
+
.note { font-size: 0.875rem; color: #9ca3af; }
|
|
19
|
+
.btn { padding: 0.75rem 1.5rem; border-radius: 8px; font-size: 1rem; font-weight: 600; cursor: pointer; border: none; }
|
|
20
|
+
.btn-primary { background: #4f46e5; color: white; }
|
|
21
|
+
.btn-large { padding: 1rem 2.5rem; font-size: 1.1rem; }
|
|
22
|
+
`]
|
|
23
|
+
})
|
|
24
|
+
export class CtaComponent {}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { NgFor } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'app-features',
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [NgFor],
|
|
8
|
+
template: `
|
|
9
|
+
<section id="features" class="features">
|
|
10
|
+
<h2>Features</h2>
|
|
11
|
+
<p class="subtitle">Everything you need to build a modern web application</p>
|
|
12
|
+
<div class="grid">
|
|
13
|
+
<div *ngFor="let f of features" class="card">
|
|
14
|
+
<span class="icon">{{ f.icon }}</span>
|
|
15
|
+
<h3>{{ f.title }}</h3>
|
|
16
|
+
<p>{{ f.description }}</p>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</section>
|
|
20
|
+
`,
|
|
21
|
+
styles: [`
|
|
22
|
+
.features { padding: 5rem 2rem; max-width: 1200px; margin: 0 auto; text-align: center; }
|
|
23
|
+
.features h2 { font-size: 2.5rem; font-weight: 700; margin-bottom: 0.5rem; }
|
|
24
|
+
.subtitle { color: #6b7280; margin-bottom: 3rem; }
|
|
25
|
+
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem; text-align: left; }
|
|
26
|
+
.card { padding: 2rem; border-radius: 12px; border: 1px solid #e5e7eb; transition: all 0.2s; }
|
|
27
|
+
.card:hover { box-shadow: 0 10px 25px rgba(0,0,0,0.08); transform: translateY(-2px); }
|
|
28
|
+
.icon { font-size: 2rem; display: block; margin-bottom: 1rem; }
|
|
29
|
+
.card h3 { font-size: 1.25rem; font-weight: 600; margin-bottom: 0.5rem; }
|
|
30
|
+
.card p { color: #6b7280; line-height: 1.6; }
|
|
31
|
+
`]
|
|
32
|
+
})
|
|
33
|
+
export class FeaturesComponent {
|
|
34
|
+
features = [
|
|
35
|
+
{ icon: '⚡', title: 'Lightning Fast', description: 'Optimized for performance with lazy loading and code splitting.' },
|
|
36
|
+
{ icon: '🎨', title: 'Beautiful Design', description: 'Clean, modern UI with responsive layouts.' },
|
|
37
|
+
{ icon: '🔒', title: 'Secure by Default', description: 'Built with security best practices.' },
|
|
38
|
+
{ icon: '🧩', title: 'Modular Architecture', description: 'Component-based structure for easy customization.' },
|
|
39
|
+
{ icon: '📱', title: 'Mobile First', description: 'Designed for mobile, scaled up for desktop.' },
|
|
40
|
+
{ icon: '🚀', title: 'Easy Deployment', description: 'Deploy anywhere in minutes.' },
|
|
41
|
+
];
|
|
42
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Component({
|
|
4
|
+
selector: 'app-footer',
|
|
5
|
+
standalone: true,
|
|
6
|
+
template: `
|
|
7
|
+
<footer class="footer">
|
|
8
|
+
<div class="footer-content">
|
|
9
|
+
<div class="brand">
|
|
10
|
+
<h3>{{projectName}}</h3>
|
|
11
|
+
<p>Building the future of the web.</p>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="links">
|
|
14
|
+
<div class="col">
|
|
15
|
+
<h4>Product</h4>
|
|
16
|
+
<a href="#features">Features</a>
|
|
17
|
+
<a href="#cta">Pricing</a>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="col">
|
|
20
|
+
<h4>Company</h4>
|
|
21
|
+
<a href="#">About</a>
|
|
22
|
+
<a href="#">Blog</a>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="bottom">
|
|
27
|
+
<p>© 2025 {{projectName}}. All rights reserved.</p>
|
|
28
|
+
</div>
|
|
29
|
+
</footer>
|
|
30
|
+
`,
|
|
31
|
+
styles: [`
|
|
32
|
+
.footer { background: #111827; color: #d1d5db; padding: 4rem 2rem 2rem; }
|
|
33
|
+
.footer-content { display: flex; justify-content: space-between; max-width: 1200px; margin: 0 auto; gap: 4rem; flex-wrap: wrap; }
|
|
34
|
+
.brand h3 { color: white; font-size: 1.5rem; margin-bottom: 0.5rem; }
|
|
35
|
+
.brand p { max-width: 300px; }
|
|
36
|
+
.links { display: flex; gap: 4rem; }
|
|
37
|
+
.col { display: flex; flex-direction: column; gap: 0.5rem; }
|
|
38
|
+
.col h4 { color: white; font-size: 0.875rem; text-transform: uppercase; margin-bottom: 0.5rem; }
|
|
39
|
+
.col a { color: #9ca3af; text-decoration: none; }
|
|
40
|
+
.col a:hover { color: white; }
|
|
41
|
+
.bottom { border-top: 1px solid #374151; margin-top: 3rem; padding-top: 1.5rem; text-align: center; }
|
|
42
|
+
.bottom p { font-size: 0.875rem; color: #6b7280; }
|
|
43
|
+
`]
|
|
44
|
+
})
|
|
45
|
+
export class FooterComponent {}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Component({
|
|
4
|
+
selector: 'app-hero',
|
|
5
|
+
standalone: true,
|
|
6
|
+
template: `
|
|
7
|
+
<header class="hero">
|
|
8
|
+
<nav class="nav">
|
|
9
|
+
<div class="logo">{{projectName}}</div>
|
|
10
|
+
<div class="nav-links">
|
|
11
|
+
<a href="#features">Features</a>
|
|
12
|
+
<a href="#cta">Pricing</a>
|
|
13
|
+
<a href="#contact">Contact</a>
|
|
14
|
+
</div>
|
|
15
|
+
</nav>
|
|
16
|
+
<div class="hero-content">
|
|
17
|
+
<h1>Build Something Amazing</h1>
|
|
18
|
+
<p>A modern landing page template to kickstart your next project.</p>
|
|
19
|
+
<div class="hero-actions">
|
|
20
|
+
<button class="btn btn-primary">Get Started</button>
|
|
21
|
+
<button class="btn btn-secondary">Learn More</button>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
</header>
|
|
25
|
+
`,
|
|
26
|
+
styles: [`
|
|
27
|
+
.hero { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding-bottom: 4rem; }
|
|
28
|
+
.nav { display: flex; justify-content: space-between; align-items: center; padding: 1rem 2rem; max-width: 1200px; margin: 0 auto; }
|
|
29
|
+
.logo { font-size: 1.5rem; font-weight: 700; }
|
|
30
|
+
.nav-links { display: flex; gap: 2rem; }
|
|
31
|
+
.nav-links a { color: rgba(255,255,255,0.9); text-decoration: none; font-weight: 500; }
|
|
32
|
+
.hero-content { text-align: center; padding: 4rem 2rem; max-width: 800px; margin: 0 auto; }
|
|
33
|
+
.hero-content h1 { font-size: 3.5rem; font-weight: 800; margin-bottom: 1.5rem; }
|
|
34
|
+
.hero-content p { font-size: 1.25rem; opacity: 0.9; margin-bottom: 2rem; }
|
|
35
|
+
.hero-actions { display: flex; gap: 1rem; justify-content: center; }
|
|
36
|
+
.btn { padding: 0.75rem 1.5rem; border-radius: 8px; font-size: 1rem; font-weight: 600; cursor: pointer; border: 2px solid transparent; }
|
|
37
|
+
.btn-primary { background: #4f46e5; color: white; border-color: #4f46e5; }
|
|
38
|
+
.btn-secondary { background: transparent; color: white; border-color: rgba(255,255,255,0.5); }
|
|
39
|
+
`]
|
|
40
|
+
})
|
|
41
|
+
export class HeroComponent {}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function CTA() {
|
|
2
|
+
return (
|
|
3
|
+
<section id="cta" className="cta">
|
|
4
|
+
<div className="cta-content">
|
|
5
|
+
<h2>Ready to Get Started?</h2>
|
|
6
|
+
<p>Join thousands of developers building amazing products.</p>
|
|
7
|
+
<button className="btn btn-primary btn-large">Start Free Trial</button>
|
|
8
|
+
<p className="cta-note">No credit card required</p>
|
|
9
|
+
</div>
|
|
10
|
+
</section>
|
|
11
|
+
);
|
|
12
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const features = [
|
|
2
|
+
{ icon: '⚡', title: 'Lightning Fast', description: 'Optimized for performance with lazy loading and code splitting.' },
|
|
3
|
+
{ icon: '🎨', title: 'Beautiful Design', description: 'Clean, modern UI with responsive layouts.' },
|
|
4
|
+
{ icon: '🔒', title: 'Secure by Default', description: 'Built with security best practices.' },
|
|
5
|
+
{ icon: '🧩', title: 'Modular Architecture', description: 'Component-based structure for easy customization.' },
|
|
6
|
+
{ icon: '📱', title: 'Mobile First', description: 'Designed for mobile, scaled up for desktop.' },
|
|
7
|
+
{ icon: '🚀', title: 'Easy Deployment', description: 'Deploy anywhere in minutes.' },
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
export function Features() {
|
|
11
|
+
return (
|
|
12
|
+
<section id="features" className="features">
|
|
13
|
+
<h2>Features</h2>
|
|
14
|
+
<p className="features-subtitle">Everything you need to build a modern web application</p>
|
|
15
|
+
<div className="feature-grid">
|
|
16
|
+
{features.map((f, i) => (
|
|
17
|
+
<div key={i} className="feature-card">
|
|
18
|
+
<span className="feature-icon">{f.icon}</span>
|
|
19
|
+
<h3>{f.title}</h3>
|
|
20
|
+
<p>{f.description}</p>
|
|
21
|
+
</div>
|
|
22
|
+
))}
|
|
23
|
+
</div>
|
|
24
|
+
</section>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function Footer() {
|
|
2
|
+
return (
|
|
3
|
+
<footer className="footer">
|
|
4
|
+
<div className="footer-content">
|
|
5
|
+
<div className="footer-brand">
|
|
6
|
+
<h3>{{projectName}}</h3>
|
|
7
|
+
<p>Building the future of the web.</p>
|
|
8
|
+
</div>
|
|
9
|
+
<div className="footer-links">
|
|
10
|
+
<div className="footer-col">
|
|
11
|
+
<h4>Product</h4>
|
|
12
|
+
<a href="#features">Features</a>
|
|
13
|
+
<a href="#cta">Pricing</a>
|
|
14
|
+
</div>
|
|
15
|
+
<div className="footer-col">
|
|
16
|
+
<h4>Company</h4>
|
|
17
|
+
<a href="#">About</a>
|
|
18
|
+
<a href="#">Blog</a>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
<div className="footer-bottom">
|
|
23
|
+
<p>© 2025 {{projectName}}. All rights reserved.</p>
|
|
24
|
+
</div>
|
|
25
|
+
</footer>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function Hero() {
|
|
2
|
+
return (
|
|
3
|
+
<header className="hero">
|
|
4
|
+
<nav className="nav">
|
|
5
|
+
<div className="logo">{{projectName}}</div>
|
|
6
|
+
<div className="nav-links">
|
|
7
|
+
<a href="#features">Features</a>
|
|
8
|
+
<a href="#cta">Pricing</a>
|
|
9
|
+
<a href="#contact">Contact</a>
|
|
10
|
+
</div>
|
|
11
|
+
</nav>
|
|
12
|
+
<div className="hero-content">
|
|
13
|
+
<h1>Build Something Amazing</h1>
|
|
14
|
+
<p>A modern landing page template to kickstart your next project.</p>
|
|
15
|
+
<div className="hero-actions">
|
|
16
|
+
<button className="btn btn-primary">Get Started</button>
|
|
17
|
+
<button className="btn btn-secondary">Learn More</button>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</header>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
.landing { min-height: 100vh; }
|
|
2
|
+
.nav { display: flex; justify-content: space-between; align-items: center; padding: 1rem 2rem; max-width: 1200px; margin: 0 auto; }
|
|
3
|
+
.logo { font-size: 1.5rem; font-weight: 700; color: white; }
|
|
4
|
+
.nav-links { display: flex; gap: 2rem; }
|
|
5
|
+
.nav-links a { color: rgba(255,255,255,0.9); text-decoration: none; font-weight: 500; }
|
|
6
|
+
.hero { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding-bottom: 4rem; }
|
|
7
|
+
.hero-content { text-align: center; padding: 4rem 2rem; max-width: 800px; margin: 0 auto; }
|
|
8
|
+
.hero-content h1 { font-size: 3.5rem; font-weight: 800; margin-bottom: 1.5rem; line-height: 1.1; }
|
|
9
|
+
.hero-content p { font-size: 1.25rem; opacity: 0.9; margin-bottom: 2rem; }
|
|
10
|
+
.hero-actions { display: flex; gap: 1rem; justify-content: center; }
|
|
11
|
+
.btn { padding: 0.75rem 1.5rem; border-radius: 8px; font-size: 1rem; font-weight: 600; cursor: pointer; border: 2px solid transparent; }
|
|
12
|
+
.btn-primary { background: #4f46e5; color: white; border-color: #4f46e5; }
|
|
13
|
+
.btn-secondary { background: transparent; color: white; border-color: rgba(255,255,255,0.5); }
|
|
14
|
+
.btn-large { padding: 1rem 2.5rem; font-size: 1.1rem; }
|
|
15
|
+
.features { padding: 5rem 2rem; max-width: 1200px; margin: 0 auto; text-align: center; }
|
|
16
|
+
.features h2 { font-size: 2.5rem; font-weight: 700; margin-bottom: 0.5rem; }
|
|
17
|
+
.features-subtitle { color: #6b7280; margin-bottom: 3rem; }
|
|
18
|
+
.feature-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem; text-align: left; }
|
|
19
|
+
.feature-card { padding: 2rem; border-radius: 12px; border: 1px solid #e5e7eb; transition: all 0.2s; }
|
|
20
|
+
.feature-card:hover { box-shadow: 0 10px 25px rgba(0,0,0,0.08); transform: translateY(-2px); }
|
|
21
|
+
.feature-icon { font-size: 2rem; display: block; margin-bottom: 1rem; }
|
|
22
|
+
.feature-card h3 { font-size: 1.25rem; font-weight: 600; margin-bottom: 0.5rem; }
|
|
23
|
+
.feature-card p { color: #6b7280; line-height: 1.6; }
|
|
24
|
+
.cta { background: #f9fafb; padding: 5rem 2rem; text-align: center; }
|
|
25
|
+
.cta-content { max-width: 600px; margin: 0 auto; }
|
|
26
|
+
.cta h2 { font-size: 2.5rem; font-weight: 700; margin-bottom: 1rem; }
|
|
27
|
+
.cta p { color: #6b7280; margin-bottom: 2rem; }
|
|
28
|
+
.cta-note { font-size: 0.875rem; color: #9ca3af; }
|
|
29
|
+
.footer { background: #111827; color: #d1d5db; padding: 4rem 2rem 2rem; }
|
|
30
|
+
.footer-content { display: flex; justify-content: space-between; max-width: 1200px; margin: 0 auto; gap: 4rem; flex-wrap: wrap; }
|
|
31
|
+
.footer-brand h3 { color: white; font-size: 1.5rem; margin-bottom: 0.5rem; }
|
|
32
|
+
.footer-links { display: flex; gap: 4rem; }
|
|
33
|
+
.footer-col { display: flex; flex-direction: column; gap: 0.5rem; }
|
|
34
|
+
.footer-col h4 { color: white; font-size: 0.875rem; text-transform: uppercase; margin-bottom: 0.5rem; }
|
|
35
|
+
.footer-col a { color: #9ca3af; text-decoration: none; }
|
|
36
|
+
.footer-col a:hover { color: white; }
|
|
37
|
+
.footer-bottom { border-top: 1px solid #374151; margin-top: 3rem; padding-top: 1.5rem; text-align: center; }
|
|
38
|
+
.footer-bottom p { font-size: 0.875rem; color: #6b7280; }
|
|
39
|
+
|
|
40
|
+
:root { font-family: Inter, system-ui, sans-serif; line-height: 1.5; color: #213547; background: #fff; }
|
|
41
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
42
|
+
body { min-height: 100vh; }
|
|
43
|
+
|
|
44
|
+
@media (prefers-color-scheme: dark) {
|
|
45
|
+
:root { color: rgba(255,255,255,0.87); background: #242424; }
|
|
46
|
+
.features h2, .feature-card h3, .cta h2 { color: rgba(255,255,255,0.87); }
|
|
47
|
+
.feature-card { border-color: #374151; }
|
|
48
|
+
.cta { background: #1f2937; }
|
|
49
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Hero } from './components/Hero';
|
|
2
|
+
import { Features } from './components/Features';
|
|
3
|
+
import { CTA } from './components/CTA';
|
|
4
|
+
import { Footer } from './components/Footer';
|
|
5
|
+
|
|
6
|
+
export default function Home() {
|
|
7
|
+
return (
|
|
8
|
+
<div className="landing">
|
|
9
|
+
<Hero />
|
|
10
|
+
<Features />
|
|
11
|
+
<CTA />
|
|
12
|
+
<Footer />
|
|
13
|
+
</div>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<section id="cta" class="cta">
|
|
3
|
+
<h2>Ready to Get Started?</h2>
|
|
4
|
+
<p>Join thousands of developers building amazing products.</p>
|
|
5
|
+
<button class="btn btn-primary btn-large">Start Free Trial</button>
|
|
6
|
+
<p class="note">No credit card required</p>
|
|
7
|
+
</section>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<style scoped>
|
|
11
|
+
.cta { background: #f9fafb; padding: 5rem 2rem; text-align: center; }
|
|
12
|
+
.cta h2 { font-size: 2.5rem; font-weight: 700; margin-bottom: 1rem; }
|
|
13
|
+
.cta p { color: #6b7280; margin-bottom: 2rem; }
|
|
14
|
+
.note { font-size: 0.875rem; color: #9ca3af; }
|
|
15
|
+
.btn { padding: 0.75rem 1.5rem; border-radius: 8px; font-size: 1rem; font-weight: 600; cursor: pointer; border: none; }
|
|
16
|
+
.btn-primary { background: #4f46e5; color: white; }
|
|
17
|
+
.btn-large { padding: 1rem 2.5rem; font-size: 1.1rem; }
|
|
18
|
+
</style>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const features = [
|
|
3
|
+
{ icon: '⚡', title: 'Lightning Fast', desc: 'Optimized for performance with lazy loading and code splitting.' },
|
|
4
|
+
{ icon: '🎨', title: 'Beautiful Design', desc: 'Clean, modern UI with responsive layouts.' },
|
|
5
|
+
{ icon: '🔒', title: 'Secure by Default', desc: 'Built with security best practices.' },
|
|
6
|
+
{ icon: '🧩', title: 'Modular Architecture', desc: 'Component-based structure for easy customization.' },
|
|
7
|
+
{ icon: '📱', title: 'Mobile First', desc: 'Designed for mobile, scaled up for desktop.' },
|
|
8
|
+
{ icon: '🚀', title: 'Easy Deployment', desc: 'Deploy anywhere in minutes.' },
|
|
9
|
+
];
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<section id="features" class="features">
|
|
14
|
+
<h2>Features</h2>
|
|
15
|
+
<p class="subtitle">Everything you need to build a modern web application</p>
|
|
16
|
+
<div class="grid">
|
|
17
|
+
<div v-for="(f, i) in features" :key="i" class="card">
|
|
18
|
+
<span class="icon">{{ f.icon }}</span>
|
|
19
|
+
<h3>{{ f.title }}</h3>
|
|
20
|
+
<p>{{ f.desc }}</p>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</section>
|
|
24
|
+
</template>
|
|
25
|
+
|
|
26
|
+
<style scoped>
|
|
27
|
+
.features { padding: 5rem 2rem; max-width: 1200px; margin: 0 auto; text-align: center; }
|
|
28
|
+
.features h2 { font-size: 2.5rem; font-weight: 700; margin-bottom: 0.5rem; }
|
|
29
|
+
.subtitle { color: #6b7280; margin-bottom: 3rem; }
|
|
30
|
+
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem; text-align: left; }
|
|
31
|
+
.card { padding: 2rem; border-radius: 12px; border: 1px solid #e5e7eb; transition: all 0.2s; }
|
|
32
|
+
.card:hover { box-shadow: 0 10px 25px rgba(0,0,0,0.08); transform: translateY(-2px); }
|
|
33
|
+
.icon { font-size: 2rem; display: block; margin-bottom: 1rem; }
|
|
34
|
+
.card h3 { font-size: 1.25rem; font-weight: 600; margin-bottom: 0.5rem; }
|
|
35
|
+
.card p { color: #6b7280; line-height: 1.6; }
|
|
36
|
+
</style>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<footer class="footer">
|
|
3
|
+
<div class="footer-content">
|
|
4
|
+
<div class="brand">
|
|
5
|
+
<h3>{{projectName}}</h3>
|
|
6
|
+
<p>Building the future of the web.</p>
|
|
7
|
+
</div>
|
|
8
|
+
<div class="links">
|
|
9
|
+
<div class="col"><h4>Product</h4><a href="#features">Features</a><a href="#cta">Pricing</a></div>
|
|
10
|
+
<div class="col"><h4>Company</h4><a href="#">About</a><a href="#">Blog</a></div>
|
|
11
|
+
<div class="col"><h4>Legal</h4><a href="#">Privacy</a><a href="#">Terms</a></div>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="bottom"><p>© 2025 {{projectName}}. All rights reserved.</p></div>
|
|
15
|
+
</footer>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<style scoped>
|
|
19
|
+
.footer { background: #111827; color: #d1d5db; padding: 4rem 2rem 2rem; }
|
|
20
|
+
.footer-content { display: flex; justify-content: space-between; max-width: 1200px; margin: 0 auto; gap: 4rem; flex-wrap: wrap; }
|
|
21
|
+
.brand h3 { color: white; font-size: 1.5rem; margin-bottom: 0.5rem; }
|
|
22
|
+
.links { display: flex; gap: 4rem; }
|
|
23
|
+
.col { display: flex; flex-direction: column; gap: 0.5rem; }
|
|
24
|
+
.col h4 { color: white; font-size: 0.875rem; text-transform: uppercase; margin-bottom: 0.5rem; }
|
|
25
|
+
.col a { color: #9ca3af; text-decoration: none; }
|
|
26
|
+
.col a:hover { color: white; }
|
|
27
|
+
.bottom { border-top: 1px solid #374151; margin-top: 3rem; padding-top: 1.5rem; text-align: center; }
|
|
28
|
+
.bottom p { font-size: 0.875rem; color: #6b7280; }
|
|
29
|
+
</style>
|