@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,29 @@
|
|
|
1
|
+
export function ContactForm() {
|
|
2
|
+
return (
|
|
3
|
+
<section id="contact" className="contact-section">
|
|
4
|
+
<h2>Get In Touch</h2>
|
|
5
|
+
<p className="section-subtitle">Have a project in mind? Let's work together.</p>
|
|
6
|
+
<form className="contact-form" onSubmit={(e) => e.preventDefault()}>
|
|
7
|
+
<div className="form-row">
|
|
8
|
+
<div className="form-group">
|
|
9
|
+
<label htmlFor="name">Name</label>
|
|
10
|
+
<input type="text" id="name" placeholder="Your name" />
|
|
11
|
+
</div>
|
|
12
|
+
<div className="form-group">
|
|
13
|
+
<label htmlFor="email">Email</label>
|
|
14
|
+
<input type="email" id="email" placeholder="your@email.com" />
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
<div className="form-group">
|
|
18
|
+
<label htmlFor="subject">Subject</label>
|
|
19
|
+
<input type="text" id="subject" placeholder="Project inquiry" />
|
|
20
|
+
</div>
|
|
21
|
+
<div className="form-group">
|
|
22
|
+
<label htmlFor="message">Message</label>
|
|
23
|
+
<textarea id="message" rows={5} placeholder="Tell me about your project..." />
|
|
24
|
+
</div>
|
|
25
|
+
<button type="submit" className="btn btn-primary">Send Message</button>
|
|
26
|
+
</form>
|
|
27
|
+
</section>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function HeroSection() {
|
|
2
|
+
return (
|
|
3
|
+
<header className="portfolio-hero">
|
|
4
|
+
<nav className="portfolio-nav">
|
|
5
|
+
<div className="logo">{{projectName}}</div>
|
|
6
|
+
<div className="nav-links">
|
|
7
|
+
<a href="#projects">Projects</a>
|
|
8
|
+
<a href="#skills">Skills</a>
|
|
9
|
+
<a href="#contact">Contact</a>
|
|
10
|
+
</div>
|
|
11
|
+
</nav>
|
|
12
|
+
<div className="hero-content">
|
|
13
|
+
<span className="hero-greeting">Hi, I'm</span>
|
|
14
|
+
<h1>Beknur</h1>
|
|
15
|
+
<p className="hero-role">Frontend Developer & Software Engineer</p>
|
|
16
|
+
<p className="hero-desc">I craft pixel-perfect, user-centric web experiences with modern technologies. Passionate about clean code and great design.</p>
|
|
17
|
+
<div className="hero-actions">
|
|
18
|
+
<a href="#projects" className="btn btn-primary">View My Work</a>
|
|
19
|
+
<a href="#contact" className="btn btn-outline">Get In Touch</a>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</header>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function PortfolioFooter() {
|
|
2
|
+
return (
|
|
3
|
+
<footer className="portfolio-footer">
|
|
4
|
+
<div className="footer-content">
|
|
5
|
+
<div className="footer-links">
|
|
6
|
+
<a href="https://github.com/beknurakhmed" target="_blank" rel="noopener noreferrer">GitHub</a>
|
|
7
|
+
<a href="#">LinkedIn</a>
|
|
8
|
+
<a href="#">Twitter</a>
|
|
9
|
+
</div>
|
|
10
|
+
<p>© 2025 {{projectName}}. All rights reserved.</p>
|
|
11
|
+
</div>
|
|
12
|
+
</footer>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const projects = [
|
|
2
|
+
{ title: 'E-commerce Platform', description: 'A full-featured online store with cart, checkout, and payment integration.', tags: ['React', 'Node.js', 'Stripe'], image: '🛒' },
|
|
3
|
+
{ title: 'Task Management App', description: 'Collaborative task management with real-time updates and team features.', tags: ['Vue.js', 'Firebase', 'Tailwind'], image: '📋' },
|
|
4
|
+
{ title: 'Weather Dashboard', description: 'Beautiful weather visualization with 5-day forecasts and location search.', tags: ['TypeScript', 'API', 'Chart.js'], image: '🌤️' },
|
|
5
|
+
{ title: 'Social Media App', description: 'Social networking platform with posts, comments, and real-time messaging.', tags: ['Next.js', 'PostgreSQL', 'WebSocket'], image: '💬' },
|
|
6
|
+
{ title: 'Portfolio Website', description: 'Responsive portfolio with animations and dark mode support.', tags: ['React', 'Framer Motion', 'SCSS'], image: '🎨' },
|
|
7
|
+
{ title: 'Blog CMS', description: 'Content management system with markdown editor and SEO optimization.', tags: ['Nuxt', 'MongoDB', 'Markdown'], image: '📝' },
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
export function Projects() {
|
|
11
|
+
return (
|
|
12
|
+
<section id="projects" className="projects-section">
|
|
13
|
+
<h2>Featured Projects</h2>
|
|
14
|
+
<p className="section-subtitle">A selection of my recent work</p>
|
|
15
|
+
<div className="projects-grid">
|
|
16
|
+
{projects.map((project, i) => (
|
|
17
|
+
<div key={i} className="project-card">
|
|
18
|
+
<div className="project-image">{project.image}</div>
|
|
19
|
+
<div className="project-info">
|
|
20
|
+
<h3>{project.title}</h3>
|
|
21
|
+
<p>{project.description}</p>
|
|
22
|
+
<div className="project-tags">
|
|
23
|
+
{project.tags.map((tag, j) => (
|
|
24
|
+
<span key={j} className="tag">{tag}</span>
|
|
25
|
+
))}
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
))}
|
|
30
|
+
</div>
|
|
31
|
+
</section>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const skillGroups = [
|
|
2
|
+
{ category: 'Frontend', skills: ['React', 'Vue.js', 'Angular', 'TypeScript', 'Next.js', 'Nuxt'] },
|
|
3
|
+
{ category: 'Styling', skills: ['Tailwind CSS', 'SCSS', 'Material UI', 'Styled Components', 'CSS Modules'] },
|
|
4
|
+
{ category: 'Backend', skills: ['Node.js', 'Express', 'PostgreSQL', 'MongoDB', 'REST API', 'GraphQL'] },
|
|
5
|
+
{ category: 'Tools', skills: ['Git', 'Docker', 'Vite', 'Webpack', 'Figma', 'VS Code'] },
|
|
6
|
+
];
|
|
7
|
+
|
|
8
|
+
export function Skills() {
|
|
9
|
+
return (
|
|
10
|
+
<section id="skills" className="skills-section">
|
|
11
|
+
<h2>Skills & Technologies</h2>
|
|
12
|
+
<p className="section-subtitle">Technologies I work with on a daily basis</p>
|
|
13
|
+
<div className="skills-grid">
|
|
14
|
+
{skillGroups.map((group, i) => (
|
|
15
|
+
<div key={i} className="skill-group">
|
|
16
|
+
<h3>{group.category}</h3>
|
|
17
|
+
<div className="skill-tags">
|
|
18
|
+
{group.skills.map((skill, j) => (
|
|
19
|
+
<span key={j} className="skill-tag">{skill}</span>
|
|
20
|
+
))}
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
))}
|
|
24
|
+
</div>
|
|
25
|
+
</section>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>{{projectName}}</title>
|
|
7
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="root"></div>
|
|
11
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"react": "^19.0.0",
|
|
13
|
+
"react-dom": "^19.0.0"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@vitejs/plugin-react": "^4.3.0",
|
|
17
|
+
"vite": "^6.0.0"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFBD4F"></stop><stop offset="100%" stop-color="#FF9640"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
3
|
+
line-height: 1.5;
|
|
4
|
+
font-weight: 400;
|
|
5
|
+
color: #213547;
|
|
6
|
+
background-color: #ffffff;
|
|
7
|
+
font-synthesis: none;
|
|
8
|
+
text-rendering: optimizeLegibility;
|
|
9
|
+
-webkit-font-smoothing: antialiased;
|
|
10
|
+
-moz-osx-font-smoothing: grayscale;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
*,
|
|
14
|
+
*::before,
|
|
15
|
+
*::after {
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
margin: 0;
|
|
18
|
+
padding: 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
body {
|
|
22
|
+
min-height: 100vh;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
a {
|
|
26
|
+
color: #646cff;
|
|
27
|
+
text-decoration: inherit;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
a:hover {
|
|
31
|
+
color: #535bf2;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@media (prefers-color-scheme: dark) {
|
|
35
|
+
:root {
|
|
36
|
+
color: rgba(255, 255, 255, 0.87);
|
|
37
|
+
background-color: #242424;
|
|
38
|
+
}
|
|
39
|
+
a:hover {
|
|
40
|
+
color: #747bff;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { makeAutoObservable } from 'mobx';
|
|
2
|
+
|
|
3
|
+
class AppStore {
|
|
4
|
+
count = 0;
|
|
5
|
+
|
|
6
|
+
constructor() {
|
|
7
|
+
makeAutoObservable(this);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
increment() { this.count++; }
|
|
11
|
+
decrement() { this.count--; }
|
|
12
|
+
reset() { this.count = 0; }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const appStore = new AppStore();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createAction, createReducer, createFeatureSelector, createSelector, on } from '@ngrx/store';
|
|
2
|
+
|
|
3
|
+
// Actions
|
|
4
|
+
export const increment = createAction('[Counter] Increment');
|
|
5
|
+
export const decrement = createAction('[Counter] Decrement');
|
|
6
|
+
export const reset = createAction('[Counter] Reset');
|
|
7
|
+
|
|
8
|
+
// State
|
|
9
|
+
export interface CounterState { count: number; }
|
|
10
|
+
const initialState: CounterState = { count: 0 };
|
|
11
|
+
|
|
12
|
+
// Reducer
|
|
13
|
+
export const counterReducer = createReducer(
|
|
14
|
+
initialState,
|
|
15
|
+
on(increment, (state) => ({ ...state, count: state.count + 1 })),
|
|
16
|
+
on(decrement, (state) => ({ ...state, count: state.count - 1 })),
|
|
17
|
+
on(reset, () => initialState)
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
// Selectors
|
|
21
|
+
export const selectCounter = createFeatureSelector<CounterState>('counter');
|
|
22
|
+
export const selectCount = createSelector(selectCounter, (state) => state.count);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineStore } from 'pinia';
|
|
2
|
+
|
|
3
|
+
export const useAppStore = defineStore('app', {
|
|
4
|
+
state: () => ({
|
|
5
|
+
count: 0,
|
|
6
|
+
}),
|
|
7
|
+
getters: {
|
|
8
|
+
doubleCount: (state) => state.count * 2,
|
|
9
|
+
},
|
|
10
|
+
actions: {
|
|
11
|
+
increment() { this.count++; },
|
|
12
|
+
decrement() { this.count--; },
|
|
13
|
+
reset() { this.count = 0; },
|
|
14
|
+
},
|
|
15
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
|
|
2
|
+
|
|
3
|
+
interface CounterState {
|
|
4
|
+
value: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const initialState: CounterState = { value: 0 };
|
|
8
|
+
|
|
9
|
+
const counterSlice = createSlice({
|
|
10
|
+
name: 'counter',
|
|
11
|
+
initialState,
|
|
12
|
+
reducers: {
|
|
13
|
+
increment: (state) => { state.value += 1; },
|
|
14
|
+
decrement: (state) => { state.value -= 1; },
|
|
15
|
+
incrementByAmount: (state, action: PayloadAction<number>) => { state.value += action.payload; },
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
|
|
20
|
+
export default counterSlice.reducer;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { configureStore } from '@reduxjs/toolkit';
|
|
2
|
+
import counterReducer from './counterSlice';
|
|
3
|
+
|
|
4
|
+
export const store = configureStore({
|
|
5
|
+
reducer: {
|
|
6
|
+
counter: counterReducer,
|
|
7
|
+
},
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export type RootState = ReturnType<typeof store.getState>;
|
|
11
|
+
export type AppDispatch = typeof store.dispatch;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { BehaviorSubject } from 'rxjs';
|
|
3
|
+
|
|
4
|
+
interface AppState {
|
|
5
|
+
count: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
@Injectable({ providedIn: 'root' })
|
|
9
|
+
export class AppStateService {
|
|
10
|
+
private state$ = new BehaviorSubject<AppState>({ count: 0 });
|
|
11
|
+
|
|
12
|
+
get state() { return this.state$.asObservable(); }
|
|
13
|
+
get currentState() { return this.state$.getValue(); }
|
|
14
|
+
|
|
15
|
+
increment() { this.state$.next({ ...this.currentState, count: this.currentState.count + 1 }); }
|
|
16
|
+
decrement() { this.state$.next({ ...this.currentState, count: this.currentState.count - 1 }); }
|
|
17
|
+
reset() { this.state$.next({ count: 0 }); }
|
|
18
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { create } from 'zustand';
|
|
2
|
+
|
|
3
|
+
interface AppState {
|
|
4
|
+
count: number;
|
|
5
|
+
increment: () => void;
|
|
6
|
+
decrement: () => void;
|
|
7
|
+
reset: () => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const useStore = create<AppState>((set) => ({
|
|
11
|
+
count: 0,
|
|
12
|
+
increment: () => set((state) => ({ count: state.count + 1 })),
|
|
13
|
+
decrement: () => set((state) => ({ count: state.count - 1 })),
|
|
14
|
+
reset: () => set({ count: 0 }),
|
|
15
|
+
}));
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>{{projectName}}</title>
|
|
7
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/src/main.ts"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
3
|
+
line-height: 1.5;
|
|
4
|
+
font-weight: 400;
|
|
5
|
+
color: #213547;
|
|
6
|
+
background-color: #ffffff;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
*, *::before, *::after {
|
|
10
|
+
box-sizing: border-box;
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
body {
|
|
16
|
+
min-height: 100vh;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.app {
|
|
20
|
+
max-width: 1280px;
|
|
21
|
+
margin: 0 auto;
|
|
22
|
+
padding: 2rem;
|
|
23
|
+
text-align: center;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
h1 {
|
|
27
|
+
font-size: 3.2em;
|
|
28
|
+
line-height: 1.1;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@media (prefers-color-scheme: dark) {
|
|
32
|
+
:root {
|
|
33
|
+
color: rgba(255, 255, 255, 0.87);
|
|
34
|
+
background-color: #242424;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>{{projectName}}</title>
|
|
7
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/src/main.ts"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"vue": "^3.5.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@vitejs/plugin-vue": "^5.2.0",
|
|
16
|
+
"vite": "^6.0.0"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
</script>
|
|
3
|
+
|
|
4
|
+
<template>
|
|
5
|
+
<div class="app">
|
|
6
|
+
<h1>{{projectName}}</h1>
|
|
7
|
+
<p>Welcome to your new project!</p>
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<style scoped>
|
|
12
|
+
.app {
|
|
13
|
+
max-width: 1280px;
|
|
14
|
+
margin: 0 auto;
|
|
15
|
+
padding: 2rem;
|
|
16
|
+
text-align: center;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
h1 {
|
|
20
|
+
font-size: 3.2em;
|
|
21
|
+
line-height: 1.1;
|
|
22
|
+
}
|
|
23
|
+
</style>
|