create-ng-tailwind 2.1.1 → 3.0.1
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/CHANGELOG.md +66 -0
- package/README.md +35 -1
- package/lib/managers/ProjectManager.js +17 -25
- package/lib/templates/starter/advanced-features.js +9 -10
- package/lib/templates/starter/features.js +180 -55
- package/lib/templates/starter/index.js +176 -230
- package/lib/templates/starter/seo-assets.js +6 -6
- package/lib/templates/starter/ui-features.js +1 -2
- package/lib/utils/ai-config.js +16 -20
- package/package.json +1 -1
|
@@ -27,11 +27,7 @@ const {
|
|
|
27
27
|
createTooltipDirective,
|
|
28
28
|
} = require('./ui-features');
|
|
29
29
|
|
|
30
|
-
const {
|
|
31
|
-
createSEOService,
|
|
32
|
-
createStructuredDataUtil,
|
|
33
|
-
createRobotsTxt,
|
|
34
|
-
} = require('./seo-features');
|
|
30
|
+
const { createSEOService, createStructuredDataUtil, createRobotsTxt } = require('./seo-features');
|
|
35
31
|
|
|
36
32
|
const {
|
|
37
33
|
createDefaultOGImage,
|
|
@@ -68,7 +64,7 @@ const starter = {
|
|
|
68
64
|
'API, Auth, Storage, Loading, Cache, SEO services',
|
|
69
65
|
'TypeScript interfaces and models',
|
|
70
66
|
'Responsive Tailwind design system',
|
|
71
|
-
'ESLint + Prettier
|
|
67
|
+
'ESLint + Prettier configured',
|
|
72
68
|
'PWA-ready with service worker configuration',
|
|
73
69
|
'Icons library (@ng-icons/heroicons)',
|
|
74
70
|
],
|
|
@@ -117,10 +113,10 @@ const starter = {
|
|
|
117
113
|
await this.setupLinting(config);
|
|
118
114
|
await this.setupPWA(config);
|
|
119
115
|
await this.formatCode(config);
|
|
120
|
-
|
|
116
|
+
|
|
121
117
|
// Stop spinner and show summary
|
|
122
118
|
if (spinner) spinner.stop();
|
|
123
|
-
|
|
119
|
+
|
|
124
120
|
// Show minimal, professional summary
|
|
125
121
|
console.log('');
|
|
126
122
|
completeStep('Angular 20+ project created');
|
|
@@ -133,7 +129,7 @@ const starter = {
|
|
|
133
129
|
completeStep('Utility pipes & directives');
|
|
134
130
|
completeStep('Authentication pages & guards');
|
|
135
131
|
completeStep('PWA support configured');
|
|
136
|
-
completeStep('ESLint + Prettier
|
|
132
|
+
completeStep('ESLint + Prettier');
|
|
137
133
|
console.log('');
|
|
138
134
|
},
|
|
139
135
|
|
|
@@ -583,24 +579,15 @@ export class StorageService {
|
|
|
583
579
|
|
|
584
580
|
// Create robots.txt in public folder
|
|
585
581
|
const robotsTxt = createRobotsTxt();
|
|
586
|
-
await fs.writeFile(
|
|
587
|
-
path.join(config.fullPath, 'public/robots.txt'),
|
|
588
|
-
robotsTxt
|
|
589
|
-
);
|
|
582
|
+
await fs.writeFile(path.join(config.fullPath, 'public/robots.txt'), robotsTxt);
|
|
590
583
|
|
|
591
584
|
// Create default OG image (SVG as placeholder)
|
|
592
585
|
const ogImage = createDefaultOGImage(config.projectName);
|
|
593
|
-
await fs.writeFile(
|
|
594
|
-
path.join(config.fullPath, 'public/assets/images/og-default.svg'),
|
|
595
|
-
ogImage
|
|
596
|
-
);
|
|
586
|
+
await fs.writeFile(path.join(config.fullPath, 'public/assets/images/og-default.svg'), ogImage);
|
|
597
587
|
|
|
598
588
|
// Create favicon
|
|
599
589
|
const favicon = createFavicon(config.projectName);
|
|
600
|
-
await fs.writeFile(
|
|
601
|
-
path.join(config.fullPath, 'public/favicon.svg'),
|
|
602
|
-
favicon
|
|
603
|
-
);
|
|
590
|
+
await fs.writeFile(path.join(config.fullPath, 'public/favicon.svg'), favicon);
|
|
604
591
|
|
|
605
592
|
// Create Apple Touch Icon (SVG as placeholder)
|
|
606
593
|
const appleTouchIcon = createAppleTouchIcon(config.projectName);
|
|
@@ -624,10 +611,7 @@ export class StorageService {
|
|
|
624
611
|
|
|
625
612
|
// Create logo
|
|
626
613
|
const logo = createLogo(config.projectName);
|
|
627
|
-
await fs.writeFile(
|
|
628
|
-
path.join(config.fullPath, 'public/assets/images/logo.svg'),
|
|
629
|
-
logo
|
|
630
|
-
);
|
|
614
|
+
await fs.writeFile(path.join(config.fullPath, 'public/assets/images/logo.svg'), logo);
|
|
631
615
|
},
|
|
632
616
|
|
|
633
617
|
async createHttpInterceptors(config) {
|
|
@@ -1122,8 +1106,7 @@ export class TranslationService {
|
|
|
1122
1106
|
'Built with Angular and Tailwind CSS. A modern, fast, and responsive web application starter template.',
|
|
1123
1107
|
quickLinks: 'Quick Links',
|
|
1124
1108
|
builtWith: 'Built With',
|
|
1125
|
-
copyright: '© {{year}} {{name}}.
|
|
1126
|
-
madeWith: 'Made with ❤️ by developers, for developers',
|
|
1109
|
+
copyright: '© {{year}} {{name}}. All rights reserved.',
|
|
1127
1110
|
},
|
|
1128
1111
|
language: {
|
|
1129
1112
|
select: 'Select Language',
|
|
@@ -1439,8 +1422,7 @@ export class TranslationService {
|
|
|
1439
1422
|
description: 'مبني بـ Angular و Tailwind CSS. قالب تطبيق ويب حديث وسريع ومتجاوب.',
|
|
1440
1423
|
quickLinks: 'روابط سريعة',
|
|
1441
1424
|
builtWith: 'مبني بـ',
|
|
1442
|
-
copyright: '© {{year}} {{name}}.
|
|
1443
|
-
madeWith: 'صُنع بـ ❤️ من قبل المطورين، للمطورين',
|
|
1425
|
+
copyright: '© {{year}} {{name}}. جميع الحقوق محفوظة.',
|
|
1444
1426
|
},
|
|
1445
1427
|
language: {
|
|
1446
1428
|
select: 'اختر اللغة',
|
|
@@ -1518,7 +1500,6 @@ export const roleGuard = (requiredRole: string): CanActivateFn => {
|
|
|
1518
1500
|
async createSharedComponents(config) {
|
|
1519
1501
|
// Button Component
|
|
1520
1502
|
const buttonComponent = `import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
1521
|
-
import { CommonModule } from '@angular/common';
|
|
1522
1503
|
|
|
1523
1504
|
export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger';
|
|
1524
1505
|
export type ButtonSize = 'sm' | 'md' | 'lg';
|
|
@@ -1526,7 +1507,7 @@ export type ButtonSize = 'sm' | 'md' | 'lg';
|
|
|
1526
1507
|
@Component({
|
|
1527
1508
|
selector: 'app-button',
|
|
1528
1509
|
standalone: true,
|
|
1529
|
-
imports: [
|
|
1510
|
+
imports: [],
|
|
1530
1511
|
template: \`
|
|
1531
1512
|
<button
|
|
1532
1513
|
[class]="buttonClasses"
|
|
@@ -1556,7 +1537,7 @@ export class ButtonComponent {
|
|
|
1556
1537
|
@Output() clicked = new EventEmitter<Event>();
|
|
1557
1538
|
|
|
1558
1539
|
get buttonClasses(): string {
|
|
1559
|
-
const baseClasses = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-
|
|
1540
|
+
const baseClasses = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50';
|
|
1560
1541
|
|
|
1561
1542
|
const sizeClasses = {
|
|
1562
1543
|
sm: 'text-sm px-3 py-2 h-9',
|
|
@@ -1565,11 +1546,11 @@ export class ButtonComponent {
|
|
|
1565
1546
|
};
|
|
1566
1547
|
|
|
1567
1548
|
const variantClasses = {
|
|
1568
|
-
primary: 'bg-
|
|
1569
|
-
secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',
|
|
1570
|
-
outline: 'border-2 border-
|
|
1571
|
-
ghost: 'hover:bg-gray-100 hover:text-gray-900',
|
|
1572
|
-
danger: 'bg-
|
|
1549
|
+
primary: 'bg-primary-600 text-white hover:bg-primary-700 focus:ring-primary-500',
|
|
1550
|
+
secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300 focus:ring-gray-400',
|
|
1551
|
+
outline: 'border-2 border-primary-600 text-primary-600 hover:bg-primary-600 hover:text-white focus:ring-primary-500',
|
|
1552
|
+
ghost: 'hover:bg-gray-100 hover:text-gray-900 focus:ring-gray-400',
|
|
1553
|
+
danger: 'bg-danger-600 text-white hover:bg-danger-700 focus:ring-danger-500'
|
|
1573
1554
|
};
|
|
1574
1555
|
|
|
1575
1556
|
const widthClass = this.fullWidth ? 'w-full' : '';
|
|
@@ -1591,12 +1572,11 @@ export class ButtonComponent {
|
|
|
1591
1572
|
|
|
1592
1573
|
// Card Component
|
|
1593
1574
|
const cardComponent = `import { Component, Input } from '@angular/core';
|
|
1594
|
-
import { CommonModule } from '@angular/common';
|
|
1595
1575
|
|
|
1596
1576
|
@Component({
|
|
1597
1577
|
selector: 'app-card',
|
|
1598
1578
|
standalone: true,
|
|
1599
|
-
imports: [
|
|
1579
|
+
imports: [],
|
|
1600
1580
|
template: \`
|
|
1601
1581
|
<div [class]="cardClasses">
|
|
1602
1582
|
@if (title || subtitle) {
|
|
@@ -1654,14 +1634,13 @@ export class CardComponent {
|
|
|
1654
1634
|
|
|
1655
1635
|
// Loading Spinner Component
|
|
1656
1636
|
const spinnerComponent = `import { Component, Input } from '@angular/core';
|
|
1657
|
-
import { CommonModule } from '@angular/common';
|
|
1658
1637
|
|
|
1659
1638
|
export type SpinnerSize = 'sm' | 'md' | 'lg' | 'xl';
|
|
1660
1639
|
|
|
1661
1640
|
@Component({
|
|
1662
1641
|
selector: 'app-loading-spinner',
|
|
1663
1642
|
standalone: true,
|
|
1664
|
-
imports: [
|
|
1643
|
+
imports: [],
|
|
1665
1644
|
template: \`
|
|
1666
1645
|
<div [class]="containerClasses">
|
|
1667
1646
|
<svg [class]="spinnerClasses" fill="none" viewBox="0 0 24 24">
|
|
@@ -1687,7 +1666,7 @@ export class LoadingSpinnerComponent {
|
|
|
1687
1666
|
@Input() size: SpinnerSize = 'md';
|
|
1688
1667
|
@Input() text?: string;
|
|
1689
1668
|
@Input() centered = false;
|
|
1690
|
-
@Input() color = '
|
|
1669
|
+
@Input() color = 'primary';
|
|
1691
1670
|
|
|
1692
1671
|
private readonly sizeClasses = {
|
|
1693
1672
|
sm: 'h-4 w-4',
|
|
@@ -1697,11 +1676,15 @@ export class LoadingSpinnerComponent {
|
|
|
1697
1676
|
} as const;
|
|
1698
1677
|
|
|
1699
1678
|
private readonly colorClasses = {
|
|
1700
|
-
|
|
1679
|
+
primary: 'text-primary-600',
|
|
1680
|
+
secondary: 'text-secondary-600',
|
|
1681
|
+
accent: 'text-accent-600',
|
|
1682
|
+
success: 'text-success-600',
|
|
1683
|
+
danger: 'text-danger-600',
|
|
1684
|
+
warning: 'text-warning-600',
|
|
1685
|
+
info: 'text-info-600',
|
|
1701
1686
|
gray: 'text-gray-600',
|
|
1702
|
-
white: 'text-white'
|
|
1703
|
-
green: 'text-green-600',
|
|
1704
|
-
red: 'text-red-600'
|
|
1687
|
+
white: 'text-white'
|
|
1705
1688
|
} as const;
|
|
1706
1689
|
|
|
1707
1690
|
protected readonly textClasses = 'text-sm text-gray-600';
|
|
@@ -1716,7 +1699,7 @@ export class LoadingSpinnerComponent {
|
|
|
1716
1699
|
|
|
1717
1700
|
get spinnerClasses(): string {
|
|
1718
1701
|
const baseClasses = 'animate-spin';
|
|
1719
|
-
return \`\${baseClasses} \${this.sizeClasses[this.size]} \${this.colorClasses[this.color as keyof typeof this.colorClasses] || this.colorClasses.
|
|
1702
|
+
return \`\${baseClasses} \${this.sizeClasses[this.size]} \${this.colorClasses[this.color as keyof typeof this.colorClasses] || this.colorClasses.primary}\`.trim();
|
|
1720
1703
|
}
|
|
1721
1704
|
}`;
|
|
1722
1705
|
|
|
@@ -1892,7 +1875,6 @@ export interface ContactFormData {
|
|
|
1892
1875
|
async createLayout(config) {
|
|
1893
1876
|
// Header Component with Authentication and Language Switcher
|
|
1894
1877
|
const headerComponentTs = `import { Component, inject, OnInit } from '@angular/core';
|
|
1895
|
-
import { CommonModule } from '@angular/common';
|
|
1896
1878
|
import { RouterModule, Router } from '@angular/router';
|
|
1897
1879
|
import { NgIconComponent, provideIcons } from '@ng-icons/core';
|
|
1898
1880
|
import { heroHome, heroInformationCircle, heroEnvelope, heroUser, heroBars3, heroXMark, heroChevronDown, heroLanguage } from '@ng-icons/heroicons/outline';
|
|
@@ -1910,7 +1892,7 @@ interface User {
|
|
|
1910
1892
|
@Component({
|
|
1911
1893
|
selector: 'app-header',
|
|
1912
1894
|
standalone: true,
|
|
1913
|
-
imports: [
|
|
1895
|
+
imports: [RouterModule, NgIconComponent, TranslateModule],
|
|
1914
1896
|
viewProviders: [provideIcons({ heroHome, heroInformationCircle, heroEnvelope, heroUser, heroBars3, heroXMark, heroChevronDown, heroLanguage })],
|
|
1915
1897
|
templateUrl: './header.component.html'
|
|
1916
1898
|
})
|
|
@@ -1977,7 +1959,8 @@ export class HeaderComponent implements OnInit {
|
|
|
1977
1959
|
<!-- Logo -->
|
|
1978
1960
|
<div class="flex items-center space-x-4">
|
|
1979
1961
|
<a routerLink="/" class="flex items-center space-x-3">
|
|
1980
|
-
|
|
1962
|
+
<div class="flex rounded-lg">
|
|
1963
|
+
<img src="assets/images/logo.svg" alt="Logo" class="h-10 w-10" />
|
|
1981
1964
|
<span class="text-white font-bold text-sm">{{ projectName.charAt(0).toUpperCase() }}</span>
|
|
1982
1965
|
</div>
|
|
1983
1966
|
<span class="text-xl font-semibold text-gray-900">
|
|
@@ -1991,23 +1974,23 @@ export class HeaderComponent implements OnInit {
|
|
|
1991
1974
|
<div class="ml-10 flex items-center space-x-8">
|
|
1992
1975
|
<a
|
|
1993
1976
|
routerLink="/"
|
|
1994
|
-
routerLinkActive="text-
|
|
1977
|
+
routerLinkActive="text-primary-600"
|
|
1995
1978
|
[routerLinkActiveOptions]="{exact: true}"
|
|
1996
|
-
class="flex items-center gap-1.5 text-gray-700 hover:text-
|
|
1979
|
+
class="flex items-center gap-1.5 text-gray-700 hover:text-primary-600 transition-colors font-medium">
|
|
1997
1980
|
<ng-icon name="heroHome" size="18"></ng-icon>
|
|
1998
1981
|
{{ 'nav.home' | translate }}
|
|
1999
1982
|
</a>
|
|
2000
1983
|
<a
|
|
2001
1984
|
routerLink="/about"
|
|
2002
|
-
routerLinkActive="text-
|
|
2003
|
-
class="flex items-center gap-1.5 text-gray-700 hover:text-
|
|
1985
|
+
routerLinkActive="text-primary-600"
|
|
1986
|
+
class="flex items-center gap-1.5 text-gray-700 hover:text-primary-600 transition-colors font-medium">
|
|
2004
1987
|
<ng-icon name="heroInformationCircle" size="18"></ng-icon>
|
|
2005
1988
|
{{ 'nav.about' | translate }}
|
|
2006
1989
|
</a>
|
|
2007
1990
|
<a
|
|
2008
1991
|
routerLink="/contact"
|
|
2009
|
-
routerLinkActive="text-
|
|
2010
|
-
class="flex items-center gap-1.5 text-gray-700 hover:text-
|
|
1992
|
+
routerLinkActive="text-primary-600"
|
|
1993
|
+
class="flex items-center gap-1.5 text-gray-700 hover:text-primary-600 transition-colors font-medium">
|
|
2011
1994
|
<ng-icon name="heroEnvelope" size="18"></ng-icon>
|
|
2012
1995
|
{{ 'nav.contact' | translate }}
|
|
2013
1996
|
</a>
|
|
@@ -2021,8 +2004,8 @@ export class HeaderComponent implements OnInit {
|
|
|
2021
2004
|
<div class="hidden md:block relative">
|
|
2022
2005
|
<button
|
|
2023
2006
|
(click)="langMenuOpen = !langMenuOpen"
|
|
2024
|
-
class="flex items-center space-x-2 text-gray-700 hover:text-
|
|
2025
|
-
[class.text-
|
|
2007
|
+
class="flex items-center space-x-2 text-gray-700 hover:text-primary-600 transition-colors px-3 py-2 rounded-lg hover:bg-gray-100"
|
|
2008
|
+
[class.text-primary-600]="langMenuOpen"
|
|
2026
2009
|
[class.bg-gray-100]="langMenuOpen">
|
|
2027
2010
|
<ng-icon name="heroLanguage" size="20"></ng-icon>
|
|
2028
2011
|
<span class="font-medium text-sm">{{ currentLanguage.nativeName }}</span>
|
|
@@ -2037,8 +2020,8 @@ export class HeaderComponent implements OnInit {
|
|
|
2037
2020
|
<button
|
|
2038
2021
|
(click)="changeLanguage(lang.code)"
|
|
2039
2022
|
class="w-full text-left px-4 py-2 text-sm transition-colors flex items-center justify-between"
|
|
2040
|
-
[class.bg-
|
|
2041
|
-
[class.text-
|
|
2023
|
+
[class.bg-primary-50]="currentLang === lang.code"
|
|
2024
|
+
[class.text-primary-600]="currentLang === lang.code"
|
|
2042
2025
|
[class.text-gray-700]="currentLang !== lang.code"
|
|
2043
2026
|
[class.hover:bg-gray-100]="currentLang !== lang.code">
|
|
2044
2027
|
<span class="flex items-center space-x-2">
|
|
@@ -2063,12 +2046,12 @@ export class HeaderComponent implements OnInit {
|
|
|
2063
2046
|
@if (!isAuthenticated) {
|
|
2064
2047
|
<a
|
|
2065
2048
|
routerLink="/auth/login"
|
|
2066
|
-
class="text-gray-700 hover:text-
|
|
2049
|
+
class="text-gray-700 hover:text-primary-600 transition-colors font-medium">
|
|
2067
2050
|
{{ 'nav.login' | translate }}
|
|
2068
2051
|
</a>
|
|
2069
2052
|
<a
|
|
2070
2053
|
routerLink="/auth/register"
|
|
2071
|
-
class="bg-
|
|
2054
|
+
class="bg-primary-600 hover:bg-primary-700 text-white px-4 py-2 rounded-lg transition-colors font-medium">
|
|
2072
2055
|
{{ 'nav.register' | translate }}
|
|
2073
2056
|
</a>
|
|
2074
2057
|
}
|
|
@@ -2078,9 +2061,9 @@ export class HeaderComponent implements OnInit {
|
|
|
2078
2061
|
<div class="relative">
|
|
2079
2062
|
<button
|
|
2080
2063
|
(click)="userMenuOpen = !userMenuOpen"
|
|
2081
|
-
class="flex items-center space-x-2 text-gray-700 hover:text-
|
|
2082
|
-
[class.text-
|
|
2083
|
-
<div class="h-8 w-8 bg-
|
|
2064
|
+
class="flex items-center space-x-2 text-gray-700 hover:text-primary-600 transition-colors"
|
|
2065
|
+
[class.text-primary-600]="userMenuOpen">
|
|
2066
|
+
<div class="h-8 w-8 bg-primary-600 rounded-full flex items-center justify-center">
|
|
2084
2067
|
<ng-icon name="heroUser" size="16" style="color: white;"></ng-icon>
|
|
2085
2068
|
</div>
|
|
2086
2069
|
<span class="font-medium">{{ currentUser?.firstName || 'User' }}</span>
|
|
@@ -2105,7 +2088,7 @@ export class HeaderComponent implements OnInit {
|
|
|
2105
2088
|
<hr class="my-1">
|
|
2106
2089
|
<button
|
|
2107
2090
|
(click)="onLogout()"
|
|
2108
|
-
class="w-full text-left px-4 py-2 text-sm text-
|
|
2091
|
+
class="w-full text-left px-4 py-2 text-sm text-danger-600 hover:bg-danger-50 transition-colors">
|
|
2109
2092
|
{{ 'nav.logout' | translate }}
|
|
2110
2093
|
</button>
|
|
2111
2094
|
</div>
|
|
@@ -2136,24 +2119,24 @@ export class HeaderComponent implements OnInit {
|
|
|
2136
2119
|
<!-- Navigation Links -->
|
|
2137
2120
|
<a
|
|
2138
2121
|
routerLink="/"
|
|
2139
|
-
routerLinkActive="text-
|
|
2122
|
+
routerLinkActive="text-primary-600 bg-primary-50"
|
|
2140
2123
|
[routerLinkActiveOptions]="{exact: true}"
|
|
2141
2124
|
(click)="mobileMenuOpen = false"
|
|
2142
|
-
class="px-3 py-2 rounded-lg text-gray-700 hover:text-
|
|
2125
|
+
class="px-3 py-2 rounded-lg text-gray-700 hover:text-primary-600 hover:bg-gray-100 transition-colors font-medium">
|
|
2143
2126
|
{{ 'nav.home' | translate }}
|
|
2144
2127
|
</a>
|
|
2145
2128
|
<a
|
|
2146
2129
|
routerLink="/about"
|
|
2147
|
-
routerLinkActive="text-
|
|
2130
|
+
routerLinkActive="text-primary-600 bg-primary-50"
|
|
2148
2131
|
(click)="mobileMenuOpen = false"
|
|
2149
|
-
class="px-3 py-2 rounded-lg text-gray-700 hover:text-
|
|
2132
|
+
class="px-3 py-2 rounded-lg text-gray-700 hover:text-primary-600 hover:bg-gray-100 transition-colors font-medium">
|
|
2150
2133
|
{{ 'nav.about' | translate }}
|
|
2151
2134
|
</a>
|
|
2152
2135
|
<a
|
|
2153
2136
|
routerLink="/contact"
|
|
2154
|
-
routerLinkActive="text-
|
|
2137
|
+
routerLinkActive="text-primary-600 bg-primary-50"
|
|
2155
2138
|
(click)="mobileMenuOpen = false"
|
|
2156
|
-
class="px-3 py-2 rounded-lg text-gray-700 hover:text-
|
|
2139
|
+
class="px-3 py-2 rounded-lg text-gray-700 hover:text-primary-600 hover:bg-gray-100 transition-colors font-medium">
|
|
2157
2140
|
{{ 'nav.contact' | translate }}
|
|
2158
2141
|
</a>
|
|
2159
2142
|
|
|
@@ -2166,8 +2149,8 @@ export class HeaderComponent implements OnInit {
|
|
|
2166
2149
|
<button
|
|
2167
2150
|
(click)="changeLanguage(lang.code)"
|
|
2168
2151
|
class="w-full text-left px-3 py-2 rounded-lg text-sm transition-colors flex items-center justify-between"
|
|
2169
|
-
[class.bg-
|
|
2170
|
-
[class.text-
|
|
2152
|
+
[class.bg-primary-50]="currentLang === lang.code"
|
|
2153
|
+
[class.text-primary-600]="currentLang === lang.code"
|
|
2171
2154
|
[class.text-gray-700]="currentLang !== lang.code"
|
|
2172
2155
|
[class.hover:bg-gray-100]="currentLang !== lang.code">
|
|
2173
2156
|
<span class="flex items-center space-x-2">
|
|
@@ -2190,13 +2173,13 @@ export class HeaderComponent implements OnInit {
|
|
|
2190
2173
|
<a
|
|
2191
2174
|
routerLink="/auth/login"
|
|
2192
2175
|
(click)="mobileMenuOpen = false"
|
|
2193
|
-
class="px-3 py-2 rounded-lg text-gray-700 hover:text-
|
|
2176
|
+
class="px-3 py-2 rounded-lg text-gray-700 hover:text-primary-600 hover:bg-gray-100 transition-colors font-medium">
|
|
2194
2177
|
{{ 'nav.login' | translate }}
|
|
2195
2178
|
</a>
|
|
2196
2179
|
<a
|
|
2197
2180
|
routerLink="/auth/register"
|
|
2198
2181
|
(click)="mobileMenuOpen = false"
|
|
2199
|
-
class="px-3 py-2 rounded-lg bg-
|
|
2182
|
+
class="px-3 py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 transition-colors font-medium text-center">
|
|
2200
2183
|
{{ 'nav.register' | translate }}
|
|
2201
2184
|
</a>
|
|
2202
2185
|
}
|
|
@@ -2211,7 +2194,7 @@ export class HeaderComponent implements OnInit {
|
|
|
2211
2194
|
</button>
|
|
2212
2195
|
<button
|
|
2213
2196
|
(click)="onLogout(); mobileMenuOpen = false"
|
|
2214
|
-
class="w-full text-left px-3 py-2 rounded-lg text-
|
|
2197
|
+
class="w-full text-left px-3 py-2 rounded-lg text-danger-600 hover:bg-danger-50 transition-colors">
|
|
2215
2198
|
{{ 'nav.logout' | translate }}
|
|
2216
2199
|
</button>
|
|
2217
2200
|
}
|
|
@@ -2245,13 +2228,12 @@ export class HeaderComponent implements OnInit {
|
|
|
2245
2228
|
|
|
2246
2229
|
// Footer Component
|
|
2247
2230
|
const footerComponentTs = `import { Component } from '@angular/core';
|
|
2248
|
-
import { CommonModule } from '@angular/common';
|
|
2249
2231
|
import { TranslateModule } from '@ngx-translate/core';
|
|
2250
2232
|
|
|
2251
2233
|
@Component({
|
|
2252
2234
|
selector: 'app-footer',
|
|
2253
2235
|
standalone: true,
|
|
2254
|
-
imports: [
|
|
2236
|
+
imports: [TranslateModule],
|
|
2255
2237
|
templateUrl: './footer.component.html'
|
|
2256
2238
|
})
|
|
2257
2239
|
export class FooterComponent {
|
|
@@ -2266,8 +2248,7 @@ export class FooterComponent {
|
|
|
2266
2248
|
<!-- Company Info -->
|
|
2267
2249
|
<div>
|
|
2268
2250
|
<div class="flex items-center space-x-3 mb-4">
|
|
2269
|
-
<
|
|
2270
|
-
</div>
|
|
2251
|
+
<img src="assets/images/logo.svg" alt="Logo" class="h-10 w-10" />
|
|
2271
2252
|
<span class="text-xl font-semibold text-gray-900">
|
|
2272
2253
|
{{ projectName }}
|
|
2273
2254
|
</span>
|
|
@@ -2284,17 +2265,17 @@ export class FooterComponent {
|
|
|
2284
2265
|
</h3>
|
|
2285
2266
|
<ul class="space-y-2">
|
|
2286
2267
|
<li>
|
|
2287
|
-
<a href="/" class="text-gray-600 hover:text-
|
|
2268
|
+
<a href="/" class="text-gray-600 hover:text-primary-600 transition-colors text-sm">
|
|
2288
2269
|
{{ 'nav.home' | translate }}
|
|
2289
2270
|
</a>
|
|
2290
2271
|
</li>
|
|
2291
2272
|
<li>
|
|
2292
|
-
<a href="/about" class="text-gray-600 hover:text-
|
|
2273
|
+
<a href="/about" class="text-gray-600 hover:text-primary-600 transition-colors text-sm">
|
|
2293
2274
|
{{ 'nav.about' | translate }}
|
|
2294
2275
|
</a>
|
|
2295
2276
|
</li>
|
|
2296
2277
|
<li>
|
|
2297
|
-
<a href="/contact" class="text-gray-600 hover:text-
|
|
2278
|
+
<a href="/contact" class="text-gray-600 hover:text-primary-600 transition-colors text-sm">
|
|
2298
2279
|
{{ 'nav.contact' | translate }}
|
|
2299
2280
|
</a>
|
|
2300
2281
|
</li>
|
|
@@ -2308,17 +2289,17 @@ export class FooterComponent {
|
|
|
2308
2289
|
</h3>
|
|
2309
2290
|
<ul class="space-y-2">
|
|
2310
2291
|
<li>
|
|
2311
|
-
<a href="https://angular.dev" target="_blank" class="text-gray-600 hover:text-
|
|
2292
|
+
<a href="https://angular.dev" target="_blank" class="text-gray-600 hover:text-primary-600 transition-colors text-sm">
|
|
2312
2293
|
Angular
|
|
2313
2294
|
</a>
|
|
2314
2295
|
</li>
|
|
2315
2296
|
<li>
|
|
2316
|
-
<a href="https://tailwindcss.com" target="_blank" class="text-gray-600 hover:text-
|
|
2297
|
+
<a href="https://tailwindcss.com" target="_blank" class="text-gray-600 hover:text-primary-600 transition-colors text-sm">
|
|
2317
2298
|
Tailwind CSS
|
|
2318
2299
|
</a>
|
|
2319
2300
|
</li>
|
|
2320
2301
|
<li>
|
|
2321
|
-
<a href="https://typescript.org" target="_blank" class="text-gray-600 hover:text-
|
|
2302
|
+
<a href="https://typescript.org" target="_blank" class="text-gray-600 hover:text-primary-600 transition-colors text-sm">
|
|
2322
2303
|
TypeScript
|
|
2323
2304
|
</a>
|
|
2324
2305
|
</li>
|
|
@@ -2327,13 +2308,10 @@ export class FooterComponent {
|
|
|
2327
2308
|
</div>
|
|
2328
2309
|
|
|
2329
2310
|
<!-- Bottom Bar -->
|
|
2330
|
-
<div class="border-t border-gray-200 mt-8 pt-8
|
|
2331
|
-
<p class="text-gray-500 text-sm">
|
|
2311
|
+
<div class="border-t border-gray-200 mt-8 pt-8">
|
|
2312
|
+
<p class="text-gray-500 text-sm text-center">
|
|
2332
2313
|
{{ 'footer.copyright' | translate:{ year: currentYear, name: projectName } }}
|
|
2333
2314
|
</p>
|
|
2334
|
-
<p class="text-gray-500 text-sm mt-2 md:mt-0">
|
|
2335
|
-
{{ 'footer.madeWith' | translate }}
|
|
2336
|
-
</p>
|
|
2337
2315
|
</div>
|
|
2338
2316
|
</div>
|
|
2339
2317
|
</footer>
|
|
@@ -2353,16 +2331,15 @@ export class FooterComponent {
|
|
|
2353
2331
|
async createAuthLayout(config) {
|
|
2354
2332
|
// Auth Layout Component
|
|
2355
2333
|
const authLayoutComponent = `import { Component } from '@angular/core';
|
|
2356
|
-
import { CommonModule } from '@angular/common';
|
|
2357
2334
|
import { RouterOutlet } from '@angular/router';
|
|
2358
2335
|
import { TranslateModule } from '@ngx-translate/core';
|
|
2359
2336
|
|
|
2360
2337
|
@Component({
|
|
2361
2338
|
selector: 'app-auth-layout',
|
|
2362
2339
|
standalone: true,
|
|
2363
|
-
imports: [
|
|
2340
|
+
imports: [RouterOutlet, TranslateModule],
|
|
2364
2341
|
template: \`
|
|
2365
|
-
<div class="min-h-screen bg-linear-to-br from-
|
|
2342
|
+
<div class="min-h-screen bg-linear-to-br from-primary-500 via-accent-600 to-secondary-700 flex items-center justify-center p-4">
|
|
2366
2343
|
<div class="w-full max-w-md">
|
|
2367
2344
|
|
|
2368
2345
|
<!-- Logo/Brand -->
|
|
@@ -2371,7 +2348,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
|
|
2371
2348
|
<span class="text-2xl font-bold text-white">{{ firstLetter }}</span>
|
|
2372
2349
|
</div>
|
|
2373
2350
|
<h1 class="text-2xl font-bold text-white">{{ projectName }}</h1>
|
|
2374
|
-
<p class="text-
|
|
2351
|
+
<p class="text-primary-100 mt-2">{{ 'auth.layout.welcome' | translate }}</p>
|
|
2375
2352
|
</div>
|
|
2376
2353
|
|
|
2377
2354
|
<!-- Auth Form Container -->
|
|
@@ -2380,7 +2357,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
|
|
2380
2357
|
</div>
|
|
2381
2358
|
|
|
2382
2359
|
<!-- Footer -->
|
|
2383
|
-
<div class="text-center mt-8 text-
|
|
2360
|
+
<div class="text-center mt-8 text-primary-100 text-sm">
|
|
2384
2361
|
<p>{{ 'auth.layout.copyright' | translate:{ year: currentYear, name: projectName } }}</p>
|
|
2385
2362
|
</div>
|
|
2386
2363
|
</div>
|
|
@@ -2400,7 +2377,6 @@ export class AuthLayoutComponent {
|
|
|
2400
2377
|
|
|
2401
2378
|
// Login Component
|
|
2402
2379
|
const loginComponentTs = `import { Component, inject } from '@angular/core';
|
|
2403
|
-
import { CommonModule } from '@angular/common';
|
|
2404
2380
|
import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';
|
|
2405
2381
|
import { Router, RouterModule } from '@angular/router';
|
|
2406
2382
|
import { TranslateModule } from '@ngx-translate/core';
|
|
@@ -2409,7 +2385,7 @@ import { ButtonComponent } from '@shared/components/button/button.component';
|
|
|
2409
2385
|
@Component({
|
|
2410
2386
|
selector: 'app-login',
|
|
2411
2387
|
standalone: true,
|
|
2412
|
-
imports: [
|
|
2388
|
+
imports: [ReactiveFormsModule, RouterModule, TranslateModule, ButtonComponent],
|
|
2413
2389
|
templateUrl: './login.component.html'
|
|
2414
2390
|
})
|
|
2415
2391
|
export class LoginComponent {
|
|
@@ -2476,11 +2452,12 @@ export class LoginComponent {
|
|
|
2476
2452
|
id="email"
|
|
2477
2453
|
type="email"
|
|
2478
2454
|
formControlName="email"
|
|
2455
|
+
autocomplete="email"
|
|
2479
2456
|
[placeholder]="'auth.login.email' | translate"
|
|
2480
|
-
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-
|
|
2481
|
-
[class.border-
|
|
2457
|
+
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-colors"
|
|
2458
|
+
[class.border-danger-500]="loginForm.get('email')?.invalid && loginForm.get('email')?.touched">
|
|
2482
2459
|
@if (loginForm.get('email')?.invalid && loginForm.get('email')?.touched) {
|
|
2483
|
-
<div class="mt-1 text-sm text-
|
|
2460
|
+
<div class="mt-1 text-sm text-danger-600">
|
|
2484
2461
|
@if (loginForm.get('email')?.errors?.['required']) {
|
|
2485
2462
|
<span>{{ 'auth.validation.emailRequired' | translate }}</span>
|
|
2486
2463
|
}
|
|
@@ -2501,9 +2478,10 @@ export class LoginComponent {
|
|
|
2501
2478
|
id="password"
|
|
2502
2479
|
[type]="showPassword ? 'text' : 'password'"
|
|
2503
2480
|
formControlName="password"
|
|
2481
|
+
autocomplete="current-password"
|
|
2504
2482
|
[placeholder]="'auth.login.password' | translate"
|
|
2505
|
-
class="w-full px-4 py-3 pr-12 border border-gray-300 rounded-lg focus:ring-2 focus:ring-
|
|
2506
|
-
[class.border-
|
|
2483
|
+
class="w-full px-4 py-3 pr-12 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-colors"
|
|
2484
|
+
[class.border-danger-500]="loginForm.get('password')?.invalid && loginForm.get('password')?.touched">
|
|
2507
2485
|
<button
|
|
2508
2486
|
type="button"
|
|
2509
2487
|
(click)="togglePassword()"
|
|
@@ -2523,7 +2501,7 @@ export class LoginComponent {
|
|
|
2523
2501
|
</button>
|
|
2524
2502
|
</div>
|
|
2525
2503
|
@if (loginForm.get('password')?.invalid && loginForm.get('password')?.touched) {
|
|
2526
|
-
<div class="mt-1 text-sm text-
|
|
2504
|
+
<div class="mt-1 text-sm text-danger-600">
|
|
2527
2505
|
@if (loginForm.get('password')?.errors?.['required']) {
|
|
2528
2506
|
<span>{{ 'auth.validation.passwordRequired' | translate }}</span>
|
|
2529
2507
|
}
|
|
@@ -2540,10 +2518,10 @@ export class LoginComponent {
|
|
|
2540
2518
|
<input
|
|
2541
2519
|
type="checkbox"
|
|
2542
2520
|
formControlName="rememberMe"
|
|
2543
|
-
class="h-4 w-4 text-
|
|
2521
|
+
class="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded">
|
|
2544
2522
|
<span class="ml-2 rtl:mr-2 text-sm text-gray-600">{{ 'auth.login.rememberMe' | translate }}</span>
|
|
2545
2523
|
</label>
|
|
2546
|
-
<a routerLink="/auth/forgot-password" class="text-sm text-
|
|
2524
|
+
<a routerLink="/auth/forgot-password" class="text-sm text-primary-600 hover:text-primary-700">
|
|
2547
2525
|
{{ 'auth.login.forgotPassword' | translate }}
|
|
2548
2526
|
</a>
|
|
2549
2527
|
</div>
|
|
@@ -2559,7 +2537,7 @@ export class LoginComponent {
|
|
|
2559
2537
|
|
|
2560
2538
|
<!-- Error Message -->
|
|
2561
2539
|
@if (errorMessage) {
|
|
2562
|
-
<div class="p-3 bg-
|
|
2540
|
+
<div class="p-3 bg-danger-100 border border-danger-300 text-danger-700 rounded-lg text-sm">
|
|
2563
2541
|
{{ errorMessage }}
|
|
2564
2542
|
</div>
|
|
2565
2543
|
}
|
|
@@ -2569,7 +2547,7 @@ export class LoginComponent {
|
|
|
2569
2547
|
<div class="text-center pt-4 border-t border-gray-200">
|
|
2570
2548
|
<p class="text-sm text-gray-600">
|
|
2571
2549
|
{{ 'auth.login.noAccount' | translate }}
|
|
2572
|
-
<a routerLink="/auth/register" class="text-
|
|
2550
|
+
<a routerLink="/auth/register" class="text-primary-600 hover:text-primary-700 font-medium">
|
|
2573
2551
|
{{ 'auth.login.createAccount' | translate }}
|
|
2574
2552
|
</a>
|
|
2575
2553
|
</p>
|
|
@@ -2589,7 +2567,6 @@ export class LoginComponent {
|
|
|
2589
2567
|
|
|
2590
2568
|
// Register Component
|
|
2591
2569
|
const registerComponentTs = `import { Component, inject } from '@angular/core';
|
|
2592
|
-
import { CommonModule } from '@angular/common';
|
|
2593
2570
|
import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';
|
|
2594
2571
|
import { RouterModule } from '@angular/router';
|
|
2595
2572
|
import { TranslateModule } from '@ngx-translate/core';
|
|
@@ -2598,7 +2575,7 @@ import { ButtonComponent } from '@shared/components/button/button.component';
|
|
|
2598
2575
|
@Component({
|
|
2599
2576
|
selector: 'app-register',
|
|
2600
2577
|
standalone: true,
|
|
2601
|
-
imports: [
|
|
2578
|
+
imports: [ReactiveFormsModule, RouterModule, TranslateModule, ButtonComponent],
|
|
2602
2579
|
templateUrl: './register.component.html'
|
|
2603
2580
|
})
|
|
2604
2581
|
export class RegisterComponent {
|
|
@@ -2622,29 +2599,33 @@ export class RegisterComponent {
|
|
|
2622
2599
|
<input
|
|
2623
2600
|
type="text"
|
|
2624
2601
|
formControlName="firstName"
|
|
2602
|
+
autocomplete="given-name"
|
|
2625
2603
|
[placeholder]="'auth.register.firstName' | translate"
|
|
2626
|
-
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-
|
|
2604
|
+
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent">
|
|
2627
2605
|
<input
|
|
2628
2606
|
type="text"
|
|
2629
2607
|
formControlName="lastName"
|
|
2608
|
+
autocomplete="family-name"
|
|
2630
2609
|
[placeholder]="'auth.register.lastName' | translate"
|
|
2631
|
-
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-
|
|
2610
|
+
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent">
|
|
2632
2611
|
</div>
|
|
2633
2612
|
<input
|
|
2634
2613
|
type="email"
|
|
2635
2614
|
formControlName="email"
|
|
2615
|
+
autocomplete="email"
|
|
2636
2616
|
[placeholder]="'auth.register.email' | translate"
|
|
2637
|
-
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-
|
|
2617
|
+
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent">
|
|
2638
2618
|
<input
|
|
2639
2619
|
type="password"
|
|
2640
2620
|
formControlName="password"
|
|
2621
|
+
autocomplete="new-password"
|
|
2641
2622
|
[placeholder]="'auth.register.password' | translate"
|
|
2642
|
-
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-
|
|
2623
|
+
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent">
|
|
2643
2624
|
<app-button type="submit" [fullWidth]="true" [disabled]="registerForm.invalid">
|
|
2644
2625
|
{{ 'auth.register.submit' | translate }}
|
|
2645
2626
|
</app-button>
|
|
2646
2627
|
<div class="text-center">
|
|
2647
|
-
<a routerLink="/auth/login" class="text-
|
|
2628
|
+
<a routerLink="/auth/login" class="text-primary-600 hover:text-primary-700">
|
|
2648
2629
|
{{ 'auth.register.hasAccount' | translate }}
|
|
2649
2630
|
</a>
|
|
2650
2631
|
</div>
|
|
@@ -2664,7 +2645,6 @@ export class RegisterComponent {
|
|
|
2664
2645
|
|
|
2665
2646
|
// Forgot Password Component
|
|
2666
2647
|
const forgotPasswordComponentTs = `import { Component, inject } from '@angular/core';
|
|
2667
|
-
import { CommonModule } from '@angular/common';
|
|
2668
2648
|
import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';
|
|
2669
2649
|
import { RouterModule } from '@angular/router';
|
|
2670
2650
|
import { TranslateModule } from '@ngx-translate/core';
|
|
@@ -2673,7 +2653,7 @@ import { ButtonComponent } from '@shared/components/button/button.component';
|
|
|
2673
2653
|
@Component({
|
|
2674
2654
|
selector: 'app-forgot-password',
|
|
2675
2655
|
standalone: true,
|
|
2676
|
-
imports: [
|
|
2656
|
+
imports: [ReactiveFormsModule, RouterModule, TranslateModule, ButtonComponent],
|
|
2677
2657
|
templateUrl: './forgot-password.component.html'
|
|
2678
2658
|
})
|
|
2679
2659
|
export class ForgotPasswordComponent {
|
|
@@ -2691,13 +2671,14 @@ export class ForgotPasswordComponent {
|
|
|
2691
2671
|
<input
|
|
2692
2672
|
type="email"
|
|
2693
2673
|
formControlName="email"
|
|
2674
|
+
autocomplete="email"
|
|
2694
2675
|
[placeholder]="'auth.forgot.email' | translate"
|
|
2695
|
-
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-
|
|
2676
|
+
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent">
|
|
2696
2677
|
<app-button type="submit" [fullWidth]="true" [disabled]="forgotForm.invalid">
|
|
2697
2678
|
{{ 'auth.forgot.submit' | translate }}
|
|
2698
2679
|
</app-button>
|
|
2699
2680
|
<div class="text-center">
|
|
2700
|
-
<a routerLink="/auth/login" class="text-
|
|
2681
|
+
<a routerLink="/auth/login" class="text-primary-600 hover:text-primary-700">
|
|
2701
2682
|
{{ 'auth.forgot.backToLogin' | translate }}
|
|
2702
2683
|
</a>
|
|
2703
2684
|
</div>
|
|
@@ -2793,6 +2774,8 @@ export class ForgotPasswordComponent {
|
|
|
2793
2774
|
'editor.tabSize': 2,
|
|
2794
2775
|
'prettier.requireConfig': false,
|
|
2795
2776
|
'eslint.validate': ['javascript', 'typescript', 'html'],
|
|
2777
|
+
// Suppress CSS linting warnings for Tailwind CSS directives
|
|
2778
|
+
'css.lint.unknownAtRules': 'ignore',
|
|
2796
2779
|
};
|
|
2797
2780
|
|
|
2798
2781
|
// VSCode extensions recommendations
|
|
@@ -2820,7 +2803,6 @@ export class ForgotPasswordComponent {
|
|
|
2820
2803
|
|
|
2821
2804
|
async createHomeComponent(config) {
|
|
2822
2805
|
const homeComponentTs = `import { Component, OnInit, inject } from '@angular/core';
|
|
2823
|
-
import { CommonModule } from '@angular/common';
|
|
2824
2806
|
import { RouterModule } from '@angular/router';
|
|
2825
2807
|
import { NgIconComponent, provideIcons } from '@ng-icons/core';
|
|
2826
2808
|
import {
|
|
@@ -2847,7 +2829,7 @@ import { SeoService } from '@core/services/seo.service';
|
|
|
2847
2829
|
@Component({
|
|
2848
2830
|
selector: 'app-home',
|
|
2849
2831
|
standalone: true,
|
|
2850
|
-
imports: [
|
|
2832
|
+
imports: [RouterModule, NgIconComponent, TranslateModule, ButtonComponent, CardComponent],
|
|
2851
2833
|
viewProviders: [provideIcons({
|
|
2852
2834
|
heroRocketLaunch,
|
|
2853
2835
|
heroPaintBrush,
|
|
@@ -2922,12 +2904,12 @@ export class HomeComponent implements OnInit {
|
|
|
2922
2904
|
}`;
|
|
2923
2905
|
|
|
2924
2906
|
const homeComponentHtml = `<!-- Hero Section -->
|
|
2925
|
-
<section class="relative py-20 bg-linear-to-br from-
|
|
2907
|
+
<section class="relative py-20 bg-linear-to-br from-primary-600 via-secondary-600 to-accent-700 overflow-hidden">
|
|
2926
2908
|
<!-- Animated Background Elements -->
|
|
2927
2909
|
<div class="absolute inset-0 opacity-20">
|
|
2928
|
-
<div class="absolute top-0 -left-4 w-72 h-72 bg-
|
|
2929
|
-
<div class="absolute top-0 -right-4 w-72 h-72 bg-
|
|
2930
|
-
<div class="absolute -bottom-8 left-20 w-72 h-72 bg-
|
|
2910
|
+
<div class="absolute top-0 -left-4 w-72 h-72 bg-accent-300 rounded-full mix-blend-multiply filter blur-xl animate-blob"></div>
|
|
2911
|
+
<div class="absolute top-0 -right-4 w-72 h-72 bg-warning-300 rounded-full mix-blend-multiply filter blur-xl animate-blob animation-delay-2000"></div>
|
|
2912
|
+
<div class="absolute -bottom-8 left-20 w-72 h-72 bg-accent-400 rounded-full mix-blend-multiply filter blur-xl animate-blob animation-delay-4000"></div>
|
|
2931
2913
|
</div>
|
|
2932
2914
|
|
|
2933
2915
|
<div class="relative container mx-auto px-4 text-center">
|
|
@@ -2935,7 +2917,7 @@ export class HomeComponent implements OnInit {
|
|
|
2935
2917
|
<h1 class="text-4xl md:text-6xl lg:text-7xl font-bold text-white mb-6 drop-shadow-lg">
|
|
2936
2918
|
{{ 'home.hero.title' | translate:{ projectName: projectName } }}
|
|
2937
2919
|
</h1>
|
|
2938
|
-
<p class="text-lg md:text-xl lg:text-2xl text-
|
|
2920
|
+
<p class="text-lg md:text-xl lg:text-2xl text-primary-50 mb-8 max-w-3xl mx-auto leading-relaxed">
|
|
2939
2921
|
{{ 'home.hero.subtitle' | translate }}
|
|
2940
2922
|
</p>
|
|
2941
2923
|
<div class="flex flex-col sm:flex-row gap-4 justify-center animate-slide-up">
|
|
@@ -2974,8 +2956,8 @@ export class HomeComponent implements OnInit {
|
|
|
2974
2956
|
<app-card [hover]="true" [shadow]="true">
|
|
2975
2957
|
<div class="flex items-start space-x-4">
|
|
2976
2958
|
<div class="shrink-0">
|
|
2977
|
-
<div class="w-12 h-12 rounded-lg bg-
|
|
2978
|
-
<ng-icon name="heroRocketLaunch" size="24" style="color:
|
|
2959
|
+
<div class="w-12 h-12 rounded-lg bg-primary-100 flex items-center justify-center">
|
|
2960
|
+
<ng-icon name="heroRocketLaunch" size="24" style="color: var(--color-primary-600);"></ng-icon>
|
|
2979
2961
|
</div>
|
|
2980
2962
|
</div>
|
|
2981
2963
|
<div>
|
|
@@ -2989,8 +2971,8 @@ export class HomeComponent implements OnInit {
|
|
|
2989
2971
|
<app-card [hover]="true" [shadow]="true">
|
|
2990
2972
|
<div class="flex items-start space-x-4">
|
|
2991
2973
|
<div class="shrink-0">
|
|
2992
|
-
<div class="w-12 h-12 rounded-lg bg-
|
|
2993
|
-
<ng-icon name="heroGlobeAlt" size="24" style="color:
|
|
2974
|
+
<div class="w-12 h-12 rounded-lg bg-accent-100 flex items-center justify-center">
|
|
2975
|
+
<ng-icon name="heroGlobeAlt" size="24" style="color: var(--color-accent-600);"></ng-icon>
|
|
2994
2976
|
</div>
|
|
2995
2977
|
</div>
|
|
2996
2978
|
<div>
|
|
@@ -3004,8 +2986,8 @@ export class HomeComponent implements OnInit {
|
|
|
3004
2986
|
<app-card [hover]="true" [shadow]="true">
|
|
3005
2987
|
<div class="flex items-start space-x-4">
|
|
3006
2988
|
<div class="shrink-0">
|
|
3007
|
-
<div class="w-12 h-12 rounded-lg bg-
|
|
3008
|
-
<ng-icon name="heroServer" size="24" style="color:
|
|
2989
|
+
<div class="w-12 h-12 rounded-lg bg-success-100 flex items-center justify-center">
|
|
2990
|
+
<ng-icon name="heroServer" size="24" style="color: var(--color-success-600);"></ng-icon>
|
|
3009
2991
|
</div>
|
|
3010
2992
|
</div>
|
|
3011
2993
|
<div>
|
|
@@ -3019,8 +3001,8 @@ export class HomeComponent implements OnInit {
|
|
|
3019
3001
|
<app-card [hover]="true" [shadow]="true">
|
|
3020
3002
|
<div class="flex items-start space-x-4">
|
|
3021
3003
|
<div class="shrink-0">
|
|
3022
|
-
<div class="w-12 h-12 rounded-lg bg-
|
|
3023
|
-
<ng-icon name="heroPaintBrush" size="24" style="color:
|
|
3004
|
+
<div class="w-12 h-12 rounded-lg bg-secondary-100 flex items-center justify-center">
|
|
3005
|
+
<ng-icon name="heroPaintBrush" size="24" style="color: var(--color-secondary-600);"></ng-icon>
|
|
3024
3006
|
</div>
|
|
3025
3007
|
</div>
|
|
3026
3008
|
<div>
|
|
@@ -3034,8 +3016,8 @@ export class HomeComponent implements OnInit {
|
|
|
3034
3016
|
<app-card [hover]="true" [shadow]="true">
|
|
3035
3017
|
<div class="flex items-start space-x-4">
|
|
3036
3018
|
<div class="shrink-0">
|
|
3037
|
-
<div class="w-12 h-12 rounded-lg bg-
|
|
3038
|
-
<ng-icon name="heroCube" size="24" style="color:
|
|
3019
|
+
<div class="w-12 h-12 rounded-lg bg-accent-100 flex items-center justify-center">
|
|
3020
|
+
<ng-icon name="heroCube" size="24" style="color: var(--color-accent-600);"></ng-icon>
|
|
3039
3021
|
</div>
|
|
3040
3022
|
</div>
|
|
3041
3023
|
<div>
|
|
@@ -3049,8 +3031,8 @@ export class HomeComponent implements OnInit {
|
|
|
3049
3031
|
<app-card [hover]="true" [shadow]="true">
|
|
3050
3032
|
<div class="flex items-start space-x-4">
|
|
3051
3033
|
<div class="shrink-0">
|
|
3052
|
-
<div class="w-12 h-12 rounded-lg bg-
|
|
3053
|
-
<ng-icon name="heroShieldCheck" size="24" style="color:
|
|
3034
|
+
<div class="w-12 h-12 rounded-lg bg-primary-100 flex items-center justify-center">
|
|
3035
|
+
<ng-icon name="heroShieldCheck" size="24" style="color: var(--color-primary-600);"></ng-icon>
|
|
3054
3036
|
</div>
|
|
3055
3037
|
</div>
|
|
3056
3038
|
<div>
|
|
@@ -3067,35 +3049,35 @@ export class HomeComponent implements OnInit {
|
|
|
3067
3049
|
<app-card [title]="'home.coreServices.title' | translate" [shadow]="true">
|
|
3068
3050
|
<ul class="space-y-2 text-gray-700">
|
|
3069
3051
|
<li class="flex items-start">
|
|
3070
|
-
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color:
|
|
3052
|
+
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color: var(--color-success-500);"></ng-icon>
|
|
3071
3053
|
<span>{{ 'home.coreServices.authService' | translate }}</span>
|
|
3072
3054
|
</li>
|
|
3073
3055
|
<li class="flex items-start">
|
|
3074
|
-
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color:
|
|
3056
|
+
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color: var(--color-success-500);"></ng-icon>
|
|
3075
3057
|
<span>{{ 'home.coreServices.apiService' | translate }}</span>
|
|
3076
3058
|
</li>
|
|
3077
3059
|
<li class="flex items-start">
|
|
3078
|
-
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color:
|
|
3060
|
+
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color: var(--color-success-500);"></ng-icon>
|
|
3079
3061
|
<span>{{ 'home.coreServices.toastService' | translate }}</span>
|
|
3080
3062
|
</li>
|
|
3081
3063
|
<li class="flex items-start">
|
|
3082
|
-
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color:
|
|
3064
|
+
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color: var(--color-success-500);"></ng-icon>
|
|
3083
3065
|
<span>{{ 'home.coreServices.modalService' | translate }}</span>
|
|
3084
3066
|
</li>
|
|
3085
3067
|
<li class="flex items-start">
|
|
3086
|
-
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color:
|
|
3068
|
+
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color: var(--color-success-500);"></ng-icon>
|
|
3087
3069
|
<span>{{ 'home.coreServices.loadingService' | translate }}</span>
|
|
3088
3070
|
</li>
|
|
3089
3071
|
<li class="flex items-start">
|
|
3090
|
-
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color:
|
|
3072
|
+
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color: var(--color-success-500);"></ng-icon>
|
|
3091
3073
|
<span>{{ 'home.coreServices.cacheService' | translate }}</span>
|
|
3092
3074
|
</li>
|
|
3093
3075
|
<li class="flex items-start">
|
|
3094
|
-
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color:
|
|
3076
|
+
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color: var(--color-success-500);"></ng-icon>
|
|
3095
3077
|
<span>{{ 'home.coreServices.storageService' | translate }}</span>
|
|
3096
3078
|
</li>
|
|
3097
3079
|
<li class="flex items-start">
|
|
3098
|
-
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color:
|
|
3080
|
+
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color: var(--color-success-500);"></ng-icon>
|
|
3099
3081
|
<span>{{ 'home.coreServices.i18nService' | translate }}</span>
|
|
3100
3082
|
</li>
|
|
3101
3083
|
</ul>
|
|
@@ -3105,31 +3087,31 @@ export class HomeComponent implements OnInit {
|
|
|
3105
3087
|
<app-card [title]="'home.sharedComponents.title' | translate" [shadow]="true">
|
|
3106
3088
|
<ul class="space-y-2 text-gray-700">
|
|
3107
3089
|
<li class="flex items-start">
|
|
3108
|
-
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color:
|
|
3090
|
+
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color: var(--color-primary-500);"></ng-icon>
|
|
3109
3091
|
<span>{{ 'home.sharedComponents.button' | translate }}</span>
|
|
3110
3092
|
</li>
|
|
3111
3093
|
<li class="flex items-start">
|
|
3112
|
-
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color:
|
|
3094
|
+
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color: var(--color-primary-500);"></ng-icon>
|
|
3113
3095
|
<span>{{ 'home.sharedComponents.card' | translate }}</span>
|
|
3114
3096
|
</li>
|
|
3115
3097
|
<li class="flex items-start">
|
|
3116
|
-
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color:
|
|
3098
|
+
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color: var(--color-primary-500);"></ng-icon>
|
|
3117
3099
|
<span>{{ 'home.sharedComponents.spinner' | translate }}</span>
|
|
3118
3100
|
</li>
|
|
3119
3101
|
<li class="flex items-start">
|
|
3120
|
-
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color:
|
|
3102
|
+
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color: var(--color-primary-500);"></ng-icon>
|
|
3121
3103
|
<span>{{ 'home.sharedComponents.toast' | translate }}</span>
|
|
3122
3104
|
</li>
|
|
3123
3105
|
<li class="flex items-start">
|
|
3124
|
-
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color:
|
|
3106
|
+
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color: var(--color-primary-500);"></ng-icon>
|
|
3125
3107
|
<span>{{ 'home.sharedComponents.modal' | translate }}</span>
|
|
3126
3108
|
</li>
|
|
3127
3109
|
<li class="flex items-start">
|
|
3128
|
-
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color:
|
|
3110
|
+
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color: var(--color-primary-500);"></ng-icon>
|
|
3129
3111
|
<span>{{ 'home.sharedComponents.pipes' | translate }}</span>
|
|
3130
3112
|
</li>
|
|
3131
3113
|
<li class="flex items-start">
|
|
3132
|
-
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color:
|
|
3114
|
+
<ng-icon name="heroCheckCircle" size="20" class="mr-2 mt-0.5" style="color: var(--color-primary-500);"></ng-icon>
|
|
3133
3115
|
<span>{{ 'home.sharedComponents.directives' | translate }}</span>
|
|
3134
3116
|
</li>
|
|
3135
3117
|
</ul>
|
|
@@ -3188,10 +3170,6 @@ export class HomeComponent implements OnInit {
|
|
|
3188
3170
|
<span class="font-mono text-gray-700">Prettier</span>
|
|
3189
3171
|
<span class="text-gray-500">{{ 'home.preConfigured.formatting' | translate }}</span>
|
|
3190
3172
|
</div>
|
|
3191
|
-
<div class="flex justify-between items-center p-2 bg-gray-50 rounded">
|
|
3192
|
-
<span class="font-mono text-gray-700">Husky</span>
|
|
3193
|
-
<span class="text-gray-500">{{ 'home.preConfigured.gitHooks' | translate }}</span>
|
|
3194
|
-
</div>
|
|
3195
3173
|
<div class="flex justify-between items-center p-2 bg-gray-50 rounded">
|
|
3196
3174
|
<span class="font-mono text-gray-700">TypeScript</span>
|
|
3197
3175
|
<span class="text-gray-500">{{ 'home.preConfigured.typeSafety' | translate }}</span>
|
|
@@ -3209,16 +3187,16 @@ export class HomeComponent implements OnInit {
|
|
|
3209
3187
|
<app-card [title]="'home.pathAliases.title' | translate" [shadow]="true">
|
|
3210
3188
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm">
|
|
3211
3189
|
<div class="bg-gray-50 p-3 rounded font-mono">
|
|
3212
|
-
<span
|
|
3190
|
+
<span style="color: var(--color-accent-600);">{{ 'home.pathAliases.core' | translate }}</span>
|
|
3213
3191
|
</div>
|
|
3214
3192
|
<div class="bg-gray-50 p-3 rounded font-mono">
|
|
3215
|
-
<span
|
|
3193
|
+
<span style="color: var(--color-accent-600);">{{ 'home.pathAliases.shared' | translate }}</span>
|
|
3216
3194
|
</div>
|
|
3217
3195
|
<div class="bg-gray-50 p-3 rounded font-mono">
|
|
3218
|
-
<span
|
|
3196
|
+
<span style="color: var(--color-accent-600);">{{ 'home.pathAliases.features' | translate }}</span>
|
|
3219
3197
|
</div>
|
|
3220
3198
|
<div class="bg-gray-50 p-3 rounded font-mono">
|
|
3221
|
-
<span
|
|
3199
|
+
<span style="color: var(--color-accent-600);">{{ 'home.pathAliases.environments' | translate }}</span>
|
|
3222
3200
|
</div>
|
|
3223
3201
|
</div>
|
|
3224
3202
|
</app-card>
|
|
@@ -3243,7 +3221,7 @@ export class HomeComponent implements OnInit {
|
|
|
3243
3221
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 text-sm font-mono">
|
|
3244
3222
|
<div>
|
|
3245
3223
|
<div class="flex items-center mb-2">
|
|
3246
|
-
<ng-icon name="heroFolder" size="18" class="mr-2" style="color:
|
|
3224
|
+
<ng-icon name="heroFolder" size="18" class="mr-2" style="color: var(--color-primary-500);"></ng-icon>
|
|
3247
3225
|
<span class="font-semibold">src/app/core/</span>
|
|
3248
3226
|
</div>
|
|
3249
3227
|
<ul class="ml-6 space-y-1 text-gray-600">
|
|
@@ -3256,7 +3234,7 @@ export class HomeComponent implements OnInit {
|
|
|
3256
3234
|
|
|
3257
3235
|
<div>
|
|
3258
3236
|
<div class="flex items-center mb-2">
|
|
3259
|
-
<ng-icon name="heroFolder" size="18" class="mr-2" style="color:
|
|
3237
|
+
<ng-icon name="heroFolder" size="18" class="mr-2" style="color: var(--color-accent-500);"></ng-icon>
|
|
3260
3238
|
<span class="font-semibold">src/app/shared/</span>
|
|
3261
3239
|
</div>
|
|
3262
3240
|
<ul class="ml-6 space-y-1 text-gray-600">
|
|
@@ -3269,7 +3247,7 @@ export class HomeComponent implements OnInit {
|
|
|
3269
3247
|
|
|
3270
3248
|
<div>
|
|
3271
3249
|
<div class="flex items-center mb-2">
|
|
3272
|
-
<ng-icon name="heroFolder" size="18" class="mr-2" style="color:
|
|
3250
|
+
<ng-icon name="heroFolder" size="18" class="mr-2" style="color: var(--color-success-500);"></ng-icon>
|
|
3273
3251
|
<span class="font-semibold">src/app/features/</span>
|
|
3274
3252
|
</div>
|
|
3275
3253
|
<ul class="ml-6 space-y-1 text-gray-600">
|
|
@@ -3282,7 +3260,7 @@ export class HomeComponent implements OnInit {
|
|
|
3282
3260
|
|
|
3283
3261
|
<div>
|
|
3284
3262
|
<div class="flex items-center mb-2">
|
|
3285
|
-
<ng-icon name="heroFolder" size="18" class="mr-2" style="color:
|
|
3263
|
+
<ng-icon name="heroFolder" size="18" class="mr-2" style="color: var(--color-warning-500);"></ng-icon>
|
|
3286
3264
|
<span class="font-semibold">src/app/layout/</span>
|
|
3287
3265
|
</div>
|
|
3288
3266
|
<ul class="ml-6 space-y-1 text-gray-600">
|
|
@@ -3300,7 +3278,7 @@ export class HomeComponent implements OnInit {
|
|
|
3300
3278
|
<section class="py-20 bg-gray-50">
|
|
3301
3279
|
<div class="container mx-auto px-4">
|
|
3302
3280
|
<div class="text-center mb-12 animate-fade-in">
|
|
3303
|
-
<div class="inline-flex items-center justify-center w-14 h-14 rounded-xl bg-
|
|
3281
|
+
<div class="inline-flex items-center justify-center w-14 h-14 rounded-xl bg-primary-600 mb-4">
|
|
3304
3282
|
<ng-icon name="heroBolt" size="28" style="color: white;"></ng-icon>
|
|
3305
3283
|
</div>
|
|
3306
3284
|
<h2 class="text-3xl md:text-4xl font-bold text-gray-900 mb-3">
|
|
@@ -3318,7 +3296,7 @@ export class HomeComponent implements OnInit {
|
|
|
3318
3296
|
<div class="animate-slide-up">
|
|
3319
3297
|
<div class="flex items-center gap-3 mb-5">
|
|
3320
3298
|
<div class="w-10 h-10 rounded-lg bg-gray-100 flex items-center justify-center">
|
|
3321
|
-
<ng-icon name="heroCheckCircle" size="20"
|
|
3299
|
+
<ng-icon name="heroCheckCircle" size="20" class="text-gray-700"></ng-icon>
|
|
3322
3300
|
</div>
|
|
3323
3301
|
<div>
|
|
3324
3302
|
<h3 class="text-xl font-semibold text-gray-900">
|
|
@@ -3364,7 +3342,7 @@ export class HomeComponent implements OnInit {
|
|
|
3364
3342
|
<div class="animate-slide-up animation-delay-200">
|
|
3365
3343
|
<div class="flex items-center gap-3 mb-5">
|
|
3366
3344
|
<div class="w-10 h-10 rounded-lg bg-gray-100 flex items-center justify-center">
|
|
3367
|
-
<ng-icon name="heroCube" size="20"
|
|
3345
|
+
<ng-icon name="heroCube" size="20" class="text-gray-700"></ng-icon>
|
|
3368
3346
|
</div>
|
|
3369
3347
|
<div>
|
|
3370
3348
|
<h3 class="text-xl font-semibold text-gray-900">
|
|
@@ -3393,10 +3371,10 @@ export class HomeComponent implements OnInit {
|
|
|
3393
3371
|
</div>
|
|
3394
3372
|
|
|
3395
3373
|
<!-- Pro Tip -->
|
|
3396
|
-
<div class="bg-
|
|
3374
|
+
<div class="bg-info-50 rounded-lg p-5 border border-info-100">
|
|
3397
3375
|
<div class="flex items-start gap-3">
|
|
3398
3376
|
<div class="shrink-0">
|
|
3399
|
-
<div class="w-8 h-8 rounded-lg bg-
|
|
3377
|
+
<div class="w-8 h-8 rounded-lg bg-primary-600 flex items-center justify-center">
|
|
3400
3378
|
<ng-icon name="heroBolt" size="16" style="color: white;"></ng-icon>
|
|
3401
3379
|
</div>
|
|
3402
3380
|
</div>
|
|
@@ -3448,7 +3426,6 @@ export class HomeComponent implements OnInit {
|
|
|
3448
3426
|
|
|
3449
3427
|
async createAboutComponent(config) {
|
|
3450
3428
|
const aboutComponentTs = `import { Component, OnInit, inject } from '@angular/core';
|
|
3451
|
-
import { CommonModule } from '@angular/common';
|
|
3452
3429
|
import { RouterModule } from '@angular/router';
|
|
3453
3430
|
import { NgIconComponent, provideIcons } from '@ng-icons/core';
|
|
3454
3431
|
import {
|
|
@@ -3466,7 +3443,7 @@ import { SeoService } from '@core/services/seo.service';
|
|
|
3466
3443
|
@Component({
|
|
3467
3444
|
selector: 'app-about',
|
|
3468
3445
|
standalone: true,
|
|
3469
|
-
imports: [
|
|
3446
|
+
imports: [RouterModule, NgIconComponent, TranslateModule, ButtonComponent],
|
|
3470
3447
|
viewProviders: [provideIcons({
|
|
3471
3448
|
heroRocketLaunch,
|
|
3472
3449
|
heroPaintBrush,
|
|
@@ -3493,11 +3470,11 @@ export class AboutComponent implements OnInit {
|
|
|
3493
3470
|
}`;
|
|
3494
3471
|
|
|
3495
3472
|
const aboutComponentHtml = `<!-- Hero Section -->
|
|
3496
|
-
<section class="relative py-16 bg-linear-to-br from-
|
|
3473
|
+
<section class="relative py-16 bg-linear-to-br from-primary-600 via-accent-600 to-secondary-600 overflow-hidden">
|
|
3497
3474
|
<div class="absolute inset-0 opacity-10">
|
|
3498
3475
|
<div class="absolute top-0 left-0 w-96 h-96 bg-white rounded-full mix-blend-multiply filter blur-3xl animate-blob"></div>
|
|
3499
|
-
<div class="absolute top-0 right-0 w-96 h-96 bg-
|
|
3500
|
-
<div class="absolute bottom-0 left-1/2 w-96 h-96 bg-
|
|
3476
|
+
<div class="absolute top-0 right-0 w-96 h-96 bg-warning-200 rounded-full mix-blend-multiply filter blur-3xl animate-blob animation-delay-2000"></div>
|
|
3477
|
+
<div class="absolute bottom-0 left-1/2 w-96 h-96 bg-accent-200 rounded-full mix-blend-multiply filter blur-3xl animate-blob animation-delay-4000"></div>
|
|
3501
3478
|
</div>
|
|
3502
3479
|
|
|
3503
3480
|
<div class="relative container mx-auto px-4 text-center">
|
|
@@ -3505,7 +3482,7 @@ export class AboutComponent implements OnInit {
|
|
|
3505
3482
|
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold text-white mb-4 drop-shadow-lg">
|
|
3506
3483
|
{{ 'about.title' | translate:{ projectName: projectName } }}
|
|
3507
3484
|
</h1>
|
|
3508
|
-
<p class="text-lg md:text-xl text-
|
|
3485
|
+
<p class="text-lg md:text-xl text-accent-50 max-w-3xl mx-auto leading-relaxed">
|
|
3509
3486
|
{{ 'about.subtitle' | translate }}
|
|
3510
3487
|
</p>
|
|
3511
3488
|
</div>
|
|
@@ -3518,9 +3495,9 @@ export class AboutComponent implements OnInit {
|
|
|
3518
3495
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-12 max-w-6xl mx-auto">
|
|
3519
3496
|
<!-- Project Overview Card -->
|
|
3520
3497
|
<div class="animate-slide-up">
|
|
3521
|
-
<div class="bg-linear-to-br from-
|
|
3498
|
+
<div class="bg-linear-to-br from-primary-50 to-accent-50 rounded-2xl p-8 border border-primary-100 h-full">
|
|
3522
3499
|
<div class="flex items-center gap-3 mb-6">
|
|
3523
|
-
<div class="w-12 h-12 rounded-lg bg-linear-to-br from-
|
|
3500
|
+
<div class="w-12 h-12 rounded-lg bg-linear-to-br from-primary-500 to-accent-600 flex items-center justify-center shadow-lg">
|
|
3524
3501
|
<ng-icon name="heroRocketLaunch" size="24" style="color: white;"></ng-icon>
|
|
3525
3502
|
</div>
|
|
3526
3503
|
<h2 class="text-2xl font-bold text-gray-900">
|
|
@@ -3538,9 +3515,9 @@ export class AboutComponent implements OnInit {
|
|
|
3538
3515
|
|
|
3539
3516
|
<!-- Features Card -->
|
|
3540
3517
|
<div class="animate-slide-up animation-delay-200">
|
|
3541
|
-
<div class="bg-linear-to-br from-
|
|
3518
|
+
<div class="bg-linear-to-br from-accent-50 to-secondary-50 rounded-2xl p-8 border border-accent-100 h-full">
|
|
3542
3519
|
<div class="flex items-center gap-3 mb-6">
|
|
3543
|
-
<div class="w-12 h-12 rounded-lg bg-linear-to-br from-
|
|
3520
|
+
<div class="w-12 h-12 rounded-lg bg-linear-to-br from-accent-500 to-secondary-600 flex items-center justify-center shadow-lg">
|
|
3544
3521
|
<ng-icon name="heroCheckCircle" size="24" style="color: white;"></ng-icon>
|
|
3545
3522
|
</div>
|
|
3546
3523
|
<h2 class="text-2xl font-bold text-gray-900">
|
|
@@ -3549,32 +3526,32 @@ export class AboutComponent implements OnInit {
|
|
|
3549
3526
|
</div>
|
|
3550
3527
|
<ul class="space-y-4">
|
|
3551
3528
|
<li class="flex items-start gap-3">
|
|
3552
|
-
<div class="shrink-0 w-6 h-6 rounded-full bg-
|
|
3553
|
-
<ng-icon name="heroCheckCircle" size="16" style="color:
|
|
3529
|
+
<div class="shrink-0 w-6 h-6 rounded-full bg-success-100 flex items-center justify-center mt-0.5">
|
|
3530
|
+
<ng-icon name="heroCheckCircle" size="16" style="color: var(--color-success-600);"></ng-icon>
|
|
3554
3531
|
</div>
|
|
3555
3532
|
<span class="text-gray-700">{{ 'about.features.standalone' | translate }}</span>
|
|
3556
3533
|
</li>
|
|
3557
3534
|
<li class="flex items-start gap-3">
|
|
3558
|
-
<div class="shrink-0 w-6 h-6 rounded-full bg-
|
|
3559
|
-
<ng-icon name="heroCheckCircle" size="16" style="color:
|
|
3535
|
+
<div class="shrink-0 w-6 h-6 rounded-full bg-success-100 flex items-center justify-center mt-0.5">
|
|
3536
|
+
<ng-icon name="heroCheckCircle" size="16" style="color: var(--color-success-600);"></ng-icon>
|
|
3560
3537
|
</div>
|
|
3561
3538
|
<span class="text-gray-700">{{ 'about.features.tailwind' | translate }}</span>
|
|
3562
3539
|
</li>
|
|
3563
3540
|
<li class="flex items-start gap-3">
|
|
3564
|
-
<div class="shrink-0 w-6 h-6 rounded-full bg-
|
|
3565
|
-
<ng-icon name="heroCheckCircle" size="16" style="color:
|
|
3541
|
+
<div class="shrink-0 w-6 h-6 rounded-full bg-success-100 flex items-center justify-center mt-0.5">
|
|
3542
|
+
<ng-icon name="heroCheckCircle" size="16" style="color: var(--color-success-600);"></ng-icon>
|
|
3566
3543
|
</div>
|
|
3567
3544
|
<span class="text-gray-700">{{ 'about.features.responsive' | translate }}</span>
|
|
3568
3545
|
</li>
|
|
3569
3546
|
<li class="flex items-start gap-3">
|
|
3570
|
-
<div class="shrink-0 w-6 h-6 rounded-full bg-
|
|
3571
|
-
<ng-icon name="heroCheckCircle" size="16" style="color:
|
|
3547
|
+
<div class="shrink-0 w-6 h-6 rounded-full bg-success-100 flex items-center justify-center mt-0.5">
|
|
3548
|
+
<ng-icon name="heroCheckCircle" size="16" style="color: var(--color-success-600);"></ng-icon>
|
|
3572
3549
|
</div>
|
|
3573
3550
|
<span class="text-gray-700">{{ 'about.features.typescript' | translate }}</span>
|
|
3574
3551
|
</li>
|
|
3575
3552
|
<li class="flex items-start gap-3">
|
|
3576
|
-
<div class="shrink-0 w-6 h-6 rounded-full bg-
|
|
3577
|
-
<ng-icon name="heroCheckCircle" size="16" style="color:
|
|
3553
|
+
<div class="shrink-0 w-6 h-6 rounded-full bg-success-100 flex items-center justify-center mt-0.5">
|
|
3554
|
+
<ng-icon name="heroCheckCircle" size="16" style="color: var(--color-success-600);"></ng-icon>
|
|
3578
3555
|
</div>
|
|
3579
3556
|
<span class="text-gray-700">{{ 'about.features.production' | translate }}</span>
|
|
3580
3557
|
</li>
|
|
@@ -3601,8 +3578,8 @@ export class AboutComponent implements OnInit {
|
|
|
3601
3578
|
<!-- Angular -->
|
|
3602
3579
|
<div class="bg-white rounded-xl p-6 shadow-lg hover:shadow-xl border border-gray-100 transform hover:-translate-y-1 transition-all">
|
|
3603
3580
|
<div class="flex items-center gap-4 mb-4">
|
|
3604
|
-
<div class="w-12 h-12 rounded-lg bg-
|
|
3605
|
-
<ng-icon name="heroCodeBracket" size="24" style="color:
|
|
3581
|
+
<div class="w-12 h-12 rounded-lg bg-danger-100 flex items-center justify-center">
|
|
3582
|
+
<ng-icon name="heroCodeBracket" size="24" style="color: var(--color-danger-600);"></ng-icon>
|
|
3606
3583
|
</div>
|
|
3607
3584
|
<h3 class="text-xl font-bold text-gray-900">{{ 'home.techStack.angular.title' | translate }}</h3>
|
|
3608
3585
|
</div>
|
|
@@ -3614,8 +3591,8 @@ export class AboutComponent implements OnInit {
|
|
|
3614
3591
|
<!-- Tailwind CSS -->
|
|
3615
3592
|
<div class="bg-white rounded-xl p-6 shadow-lg hover:shadow-xl border border-gray-100 transform hover:-translate-y-1 transition-all">
|
|
3616
3593
|
<div class="flex items-center gap-4 mb-4">
|
|
3617
|
-
<div class="w-12 h-12 rounded-lg bg-
|
|
3618
|
-
<ng-icon name="heroPaintBrush" size="24" style="color:
|
|
3594
|
+
<div class="w-12 h-12 rounded-lg bg-secondary-100 flex items-center justify-center">
|
|
3595
|
+
<ng-icon name="heroPaintBrush" size="24" style="color: var(--color-secondary-600);"></ng-icon>
|
|
3619
3596
|
</div>
|
|
3620
3597
|
<h3 class="text-xl font-bold text-gray-900">{{ 'home.techStack.tailwind.title' | translate }}</h3>
|
|
3621
3598
|
</div>
|
|
@@ -3627,8 +3604,8 @@ export class AboutComponent implements OnInit {
|
|
|
3627
3604
|
<!-- TypeScript -->
|
|
3628
3605
|
<div class="bg-white rounded-xl p-6 shadow-lg hover:shadow-xl border border-gray-100 transform hover:-translate-y-1 transition-all">
|
|
3629
3606
|
<div class="flex items-center gap-4 mb-4">
|
|
3630
|
-
<div class="w-12 h-12 rounded-lg bg-
|
|
3631
|
-
<ng-icon name="heroShieldCheck" size="24" style="color:
|
|
3607
|
+
<div class="w-12 h-12 rounded-lg bg-primary-100 flex items-center justify-center">
|
|
3608
|
+
<ng-icon name="heroShieldCheck" size="24" style="color: var(--color-primary-600);"></ng-icon>
|
|
3632
3609
|
</div>
|
|
3633
3610
|
<h3 class="text-xl font-bold text-gray-900">{{ 'home.techStack.typescript.title' | translate }}</h3>
|
|
3634
3611
|
</div>
|
|
@@ -3746,8 +3723,6 @@ export class AboutComponent implements OnInit {
|
|
|
3746
3723
|
prettier: '^3.5.3',
|
|
3747
3724
|
'eslint-config-prettier': '^10.1.2',
|
|
3748
3725
|
'prettier-plugin-tailwindcss': '^0.6.11',
|
|
3749
|
-
husky: '^9.0.11',
|
|
3750
|
-
'lint-staged': '^15.2.0',
|
|
3751
3726
|
};
|
|
3752
3727
|
|
|
3753
3728
|
// Add enhanced scripts
|
|
@@ -3759,7 +3734,6 @@ export class AboutComponent implements OnInit {
|
|
|
3759
3734
|
'format:ts': 'prettier --write "**/*.ts"',
|
|
3760
3735
|
'code:check': 'npm run format:check && npm run lint',
|
|
3761
3736
|
'code:fix': 'npm run format && npm run lint:fix',
|
|
3762
|
-
prepare: 'husky install || true',
|
|
3763
3737
|
};
|
|
3764
3738
|
|
|
3765
3739
|
// Add prettier configuration
|
|
@@ -3915,6 +3889,8 @@ module.exports = tseslint.config(
|
|
|
3915
3889
|
'files.eol': '\\n',
|
|
3916
3890
|
'files.trimTrailingWhitespace': true,
|
|
3917
3891
|
'files.insertFinalNewline': true,
|
|
3892
|
+
// Suppress CSS linting warnings for Tailwind CSS directives
|
|
3893
|
+
'css.lint.unknownAtRules': 'ignore',
|
|
3918
3894
|
};
|
|
3919
3895
|
|
|
3920
3896
|
await fs.writeFile(
|
|
@@ -3943,7 +3919,6 @@ node_modules/
|
|
|
3943
3919
|
// Install linting packages if not skipping install
|
|
3944
3920
|
if (!config.skipInstall) {
|
|
3945
3921
|
await this.installLintingPackages(config);
|
|
3946
|
-
await this.setupHusky(config);
|
|
3947
3922
|
}
|
|
3948
3923
|
},
|
|
3949
3924
|
|
|
@@ -3976,8 +3951,6 @@ node_modules/
|
|
|
3976
3951
|
'prettier@^3.5.3',
|
|
3977
3952
|
'eslint-config-prettier@^10.1.2',
|
|
3978
3953
|
'prettier-plugin-tailwindcss@^0.6.11',
|
|
3979
|
-
'husky@^9.0.11',
|
|
3980
|
-
'lint-staged@^15.2.0',
|
|
3981
3954
|
];
|
|
3982
3955
|
|
|
3983
3956
|
await execa.command(`npm install ${packages.join(' ')} --save-dev`, {
|
|
@@ -4008,33 +3981,6 @@ node_modules/
|
|
|
4008
3981
|
}
|
|
4009
3982
|
},
|
|
4010
3983
|
|
|
4011
|
-
async setupHusky(config) {
|
|
4012
|
-
const execa = require('execa');
|
|
4013
|
-
|
|
4014
|
-
try {
|
|
4015
|
-
// Initialize husky
|
|
4016
|
-
await execa.command('npx husky install', {
|
|
4017
|
-
cwd: config.fullPath,
|
|
4018
|
-
stdio: 'pipe',
|
|
4019
|
-
});
|
|
4020
|
-
|
|
4021
|
-
// Create pre-commit hook
|
|
4022
|
-
const preCommitHook = `#!/usr/bin/env sh
|
|
4023
|
-
. "$(dirname -- "$0")/_/husky.sh"
|
|
4024
|
-
|
|
4025
|
-
npx lint-staged
|
|
4026
|
-
`;
|
|
4027
|
-
|
|
4028
|
-
await fs.ensureDir(path.join(config.fullPath, '.husky'));
|
|
4029
|
-
await fs.writeFile(path.join(config.fullPath, '.husky/pre-commit'), preCommitHook, {
|
|
4030
|
-
mode: 0o755,
|
|
4031
|
-
});
|
|
4032
|
-
} catch (error) {
|
|
4033
|
-
// If husky setup fails, it's not critical
|
|
4034
|
-
// Silent failure - user can run "npm run prepare" later
|
|
4035
|
-
}
|
|
4036
|
-
},
|
|
4037
|
-
|
|
4038
3984
|
async setupPWA(config) {
|
|
4039
3985
|
// Create manifest.json
|
|
4040
3986
|
const manifest = {
|