create-nala 3.1.1 → 3.1.2

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.
@@ -0,0 +1,258 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+ import { computed } from 'vue'
4
+ import { cn } from '@/lib/utils'
5
+
6
+ export type BrandIconName =
7
+ | 'google'
8
+ | 'github'
9
+ | 'microsoft'
10
+ | 'apple'
11
+ | 'x'
12
+ | 'twitter'
13
+ | 'tiktok'
14
+ | 'pinterest'
15
+ | 'youtube'
16
+ | 'instagram'
17
+ | 'facebook'
18
+ | 'linkedin'
19
+ | 'threads'
20
+ | 'discord'
21
+ | 'slack'
22
+ | 'telegram'
23
+ | 'whatsapp'
24
+ | 'reddit'
25
+ | 'twitch'
26
+ | 'figma'
27
+ | 'gitlab'
28
+ | 'spotify'
29
+ | 'notion'
30
+ | 'dribbble'
31
+
32
+ const props = withDefaults(
33
+ defineProps<{
34
+ name: BrandIconName
35
+ colored?: boolean
36
+ class?: HTMLAttributes['class']
37
+ }>(),
38
+ {
39
+ colored: false,
40
+ class: undefined,
41
+ },
42
+ )
43
+
44
+ const normalizedName = computed(() => props.name.toLowerCase() as BrandIconName)
45
+ </script>
46
+
47
+ <template>
48
+ <svg
49
+ xmlns="http://www.w3.org/2000/svg"
50
+ viewBox="0 0 24 24"
51
+ aria-hidden="true"
52
+ :class="cn('size-4 shrink-0 inline-block align-middle', props.class)"
53
+ >
54
+ <!-- Google -->
55
+ <template v-if="normalizedName === 'google'">
56
+ <template v-if="colored">
57
+ <path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" />
58
+ <path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" />
59
+ <path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.06H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.94l2.85-2.22.81-.63z" />
60
+ <path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.06l3.66 2.84c.87-2.6 3.3-4.52 6.16-4.52z" />
61
+ </template>
62
+ <path
63
+ v-else
64
+ fill="currentColor"
65
+ d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
66
+ />
67
+ </template>
68
+
69
+ <!-- GitHub -->
70
+ <path
71
+ v-else-if="normalizedName === 'github'"
72
+ fill="currentColor"
73
+ d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"
74
+ />
75
+
76
+ <!-- Microsoft -->
77
+ <template v-else-if="normalizedName === 'microsoft'">
78
+ <template v-if="colored">
79
+ <rect x="1" y="1" width="10" height="10" fill="#F25022" />
80
+ <rect x="13" y="1" width="10" height="10" fill="#7FBA00" />
81
+ <rect x="1" y="13" width="10" height="10" fill="#00A4EF" />
82
+ <rect x="13" y="13" width="10" height="10" fill="#FFB900" />
83
+ </template>
84
+ <template v-else>
85
+ <rect x="1" y="1" width="10" height="10" fill="currentColor" />
86
+ <rect x="13" y="1" width="10" height="10" fill="currentColor" />
87
+ <rect x="1" y="13" width="10" height="10" fill="currentColor" />
88
+ <rect x="13" y="13" width="10" height="10" fill="currentColor" />
89
+ </template>
90
+ </template>
91
+
92
+ <!-- Apple -->
93
+ <path
94
+ v-else-if="normalizedName === 'apple'"
95
+ fill="currentColor"
96
+ d="M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701"
97
+ />
98
+
99
+ <!-- X / Twitter -->
100
+ <path
101
+ v-else-if="normalizedName === 'x' || normalizedName === 'twitter'"
102
+ fill="currentColor"
103
+ d="M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z"
104
+ />
105
+
106
+ <!-- TikTok -->
107
+ <path
108
+ v-else-if="normalizedName === 'tiktok'"
109
+ :fill="colored ? '#FE2C55' : 'currentColor'"
110
+ d="M12.525.02c1.31-.02 2.61-.01 3.91-.02.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.05-2.89-.35-4.2-.97-.57-.26-1.1-.59-1.62-.93-.01 2.92.01 5.84-.02 8.75-.08 1.4-.54 2.79-1.35 3.94-1.31 1.92-3.58 3.17-5.91 3.21-1.43.08-2.86-.31-4.08-1.03-2.02-1.19-3.44-3.37-3.65-5.71-.02-.5-.03-1-.01-1.49.18-1.9 1.12-3.72 2.58-4.96 1.66-1.44 3.98-2.13 6.15-1.72.02 1.48-.04 2.96-.04 4.44-.99-.32-2.15-.23-3.02.37-.63.41-1.11 1.04-1.36 1.75-.21.51-.15 1.07-.14 1.61.24 1.64 1.82 3.02 3.5 2.87 1.12-.01 2.19-.66 2.77-1.61.19-.33.4-.67.41-1.06.1-1.79.06-3.57.07-5.36.01-4.03-.01-8.05.02-12.07z"
111
+ />
112
+
113
+ <!-- Pinterest -->
114
+ <path
115
+ v-else-if="normalizedName === 'pinterest'"
116
+ :fill="colored ? '#BD081C' : 'currentColor'"
117
+ d="M12.017 0C5.396 0 .029 5.367.029 11.987c0 5.079 3.158 9.417 7.618 11.162-.105-.949-.199-2.403.041-3.439.219-.937 1.406-5.957 1.406-5.957s-.359-.72-.359-1.781c0-1.663.967-2.911 2.168-2.911 1.024 0 1.518.769 1.518 1.688 0 1.029-.653 2.567-.992 3.992-.285 1.193.6 2.165 1.775 2.165 2.128 0 3.768-2.245 3.768-5.487 0-2.861-2.063-4.869-5.008-4.869-3.41 0-5.409 2.562-5.409 5.199 0 1.033.394 2.143.889 2.741.099.12.112.225.085.345-.09.375-.293 1.199-.334 1.363-.053.225-.172.271-.401.165-1.495-.69-2.433-2.878-2.433-4.646 0-3.776 2.748-7.252 7.92-7.252 4.158 0 7.392 2.967 7.392 6.923 0 4.135-2.607 7.462-6.233 7.462-1.214 0-2.354-.629-2.758-1.379l-.749 2.848c-.269 1.045-1.004 2.352-1.498 3.146 1.123.345 2.306.535 3.55.535 6.607 0 11.985-5.365 11.985-11.987C23.97 5.39 18.592.026 11.985.026L12.017 0z"
118
+ />
119
+
120
+ <!-- YouTube -->
121
+ <path
122
+ v-else-if="normalizedName === 'youtube'"
123
+ :fill="colored ? '#FF0000' : 'currentColor'"
124
+ d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"
125
+ />
126
+
127
+ <!-- Instagram -->
128
+ <path
129
+ v-else-if="normalizedName === 'instagram'"
130
+ :fill="colored ? '#E4405F' : 'currentColor'"
131
+ d="M7.0301.084c-1.2768.0602-2.1487.264-2.911.5634-.7888.3075-1.4575.72-2.1228 1.3877-.6652.6677-1.075 1.3368-1.3802 2.127-.2954.7638-.4956 1.6365-.552 2.914-.0564 1.2775-.0689 1.6882-.0626 4.947.0062 3.2586.0206 3.6671.0825 4.9473.061 1.2765.264 2.1482.5635 2.9107.308.7889.72 1.4573 1.388 2.1228.6679.6655 1.3365 1.0743 2.1285 1.38.7632.295 1.6361.4961 2.9134.552 1.2773.056 1.6884.069 4.9462.0627 3.2578-.0062 3.668-.0207 4.9478-.0814 1.28-.0607 2.147-.2652 2.9098-.5633.7889-.3086 1.4578-.72 2.1228-1.3881.665-.6682 1.0745-1.3378 1.3795-2.1284.2957-.7632.4966-1.636.552-2.9124.056-1.2809.0692-1.6898.063-4.948-.0063-3.2583-.021-3.6668-.0817-4.9465-.0607-1.2797-.264-2.1487-.5633-2.9117-.3084-.7889-.72-1.4568-1.3876-2.1228C21.2982 1.33 20.628.9208 19.8378.6165 19.074.321 18.2017.1197 16.9244.0645 15.6471.0093 15.236-.005 11.977.0014 8.718.0076 8.31.0215 7.0301.0839m.1402 21.6932c-1.17-.0509-1.8053-.2453-2.2287-.408-.5606-.216-.96-.4771-1.3819-.895-.422-.4178-.6811-.8186-.9-1.378-.1644-.4234-.3624-1.058-.4171-2.228-.0595-1.2645-.072-1.6442-.079-4.848-.007-3.2037.0053-3.583.0607-4.848.05-1.169.2456-1.805.408-2.2282.216-.5613.4762-.96.895-1.3816.4188-.4217.8184-.6814 1.3783-.9003.423-.1651 1.0575-.3614 2.227-.4171 1.2655-.06 1.6447-.072 4.848-.079 3.2033-.007 3.5835.005 4.8495.0608 1.169.0508 1.8053.2445 2.228.408.5608.216.96.4754 1.3816.895.4217.4194.6816.8176.9005 1.3787.1653.4217.3617 1.056.4169 2.2263.0602 1.2655.0739 1.645.0796 4.848.0058 3.203-.0055 3.5834-.061 4.848-.051 1.17-.245 1.8055-.408 2.2294-.216.5604-.4763.96-.8954 1.3814-.419.4215-.8181.6811-1.3783.9-.4224.1649-1.0577.3617-2.2262.4174-1.2656.0595-1.6448.072-4.8493.079-3.2045.007-3.5825-.006-4.848-.0608M16.953 5.5864A1.44 1.44 0 1 0 18.39 4.144a1.44 1.44 0 0 0-1.437 1.4424M5.8385 12.012c.0067 3.4032 2.7706 6.1557 6.173 6.1493 3.4026-.0065 6.157-2.7701 6.1506-6.1733-.0065-3.4032-2.771-6.1565-6.174-6.1498-3.403.0067-6.156 2.771-6.1496 6.1738M8 12.0077a4 4 0 1 1 4.008 3.9921A3.9996 3.9996 0 0 1 8 12.0077"
132
+ />
133
+
134
+ <!-- Facebook -->
135
+ <path
136
+ v-else-if="normalizedName === 'facebook'"
137
+ :fill="colored ? '#1877F2' : 'currentColor'"
138
+ d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"
139
+ />
140
+
141
+ <!-- LinkedIn -->
142
+ <path
143
+ v-else-if="normalizedName === 'linkedin'"
144
+ :fill="colored ? '#0A66C2' : 'currentColor'"
145
+ d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14m-.5 15.5v-5.3a3.26 3.26 0 0 0-3.26-3.26c-.85 0-1.84.52-2.28 1.3v-1.11h-2.79v8.37h2.79v-4.93c0-.77.62-1.4 1.39-1.4a1.4 1.4 0 0 1 1.4 1.4v4.93h2.75M6.46 8.76a1.4 1.4 0 1 0-1.4-1.4 1.4 1.4 0 0 0 1.4 1.4m1.4 9.74v-8.37H5.06v8.37z"
146
+ />
147
+
148
+ <!-- Discord -->
149
+ <path
150
+ v-else-if="normalizedName === 'discord'"
151
+ :fill="colored ? '#5865F2' : 'currentColor'"
152
+ d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"
153
+ />
154
+
155
+ <!-- Slack -->
156
+ <template v-else-if="normalizedName === 'slack'">
157
+ <template v-if="colored">
158
+ <path fill="#36C5F0" d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zm1.271 0a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313z" />
159
+ <path fill="#2EB67D" d="M8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zm0 1.271a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312z" />
160
+ <path fill="#ECB22E" d="M18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zm-1.268 0a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312z" />
161
+ <path fill="#E01E5A" d="M15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zm0-1.268a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z" />
162
+ </template>
163
+ <path
164
+ v-else
165
+ fill="currentColor"
166
+ d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zm1.271 0a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zm0 1.271a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zm10.122 2.521a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zm-1.268 0a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zm-2.523 10.122a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zm0-1.268a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z"
167
+ />
168
+ </template>
169
+
170
+ <!-- Telegram -->
171
+ <path
172
+ v-else-if="normalizedName === 'telegram'"
173
+ :fill="colored ? '#24A1DE' : 'currentColor'"
174
+ d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"
175
+ />
176
+
177
+ <!-- WhatsApp -->
178
+ <path
179
+ v-else-if="normalizedName === 'whatsapp'"
180
+ :fill="colored ? '#25D366' : 'currentColor'"
181
+ d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z"
182
+ />
183
+
184
+ <!-- Threads -->
185
+ <path
186
+ v-else-if="normalizedName === 'threads'"
187
+ fill="currentColor"
188
+ d="M18.263 11.097c-.03-3.486-1.92-5.586-5.111-5.586-2.13 0-3.922.963-4.863 2.499l2.062 1.438c.535-.843 1.272-1.543 2.628-1.543 1.528 0 2.318.85 2.544 2.431a15 15 0 0 0-2.236-.173c-4.125 0-6.068 1.867-6.068 4.336s1.943 3.99 4.804 3.99c3.139 0 5.013-2.115 5.781-4.735.798.361 1.348 1.204 1.348 2.47 0 3.387-3.907 5.232-7.22 5.232-4.885 0-8.077-3.207-8.077-8.424 0-6.392 4.223-10.487 9.9-10.487 3.808 0 5.69 1.671 6.97 3.914l2.108-1.475C21.44 2.078 18.331 0 13.663 0 6.227 0 1.168 5.277 1.168 12.934c0 7 4.953 11.066 10.856 11.066 4.878 0 9.809-2.846 9.809-7.716 0-2.545-1.46-4.231-3.569-5.187m-6.33 4.855c-1.077 0-2.026-.512-2.026-1.453 0-1.483 1.822-1.934 3.606-1.934.678 0 1.34.045 1.927.173-.422 1.927-1.671 3.215-3.508 3.214Z"
189
+ />
190
+
191
+ <!-- Reddit -->
192
+ <path
193
+ v-else-if="normalizedName === 'reddit'"
194
+ :fill="colored ? '#FF4500' : 'currentColor'"
195
+ d="M12 0C5.373 0 0 5.373 0 12c0 3.314 1.343 6.314 3.515 8.485l-2.286 2.286C.775 23.225 1.097 24 1.738 24H12c6.627 0 12-5.373 12-12S18.627 0 12 0Zm4.388 3.199c1.104 0 1.999.895 1.999 1.999 0 1.105-.895 2-1.999 2-.946 0-1.739-.657-1.947-1.539v.002c-1.147.162-2.032 1.15-2.032 2.341v.007c1.776.067 3.4.567 4.686 1.363.473-.363 1.064-.58 1.707-.58 1.547 0 2.802 1.254 2.802 2.802 0 1.117-.655 2.081-1.601 2.531-.088 3.256-3.637 5.876-7.997 5.876-4.361 0-7.905-2.617-7.998-5.87-.954-.447-1.614-1.415-1.614-2.538 0-1.548 1.255-2.802 2.803-2.802.645 0 1.239.218 1.712.585 1.275-.79 2.881-1.291 4.64-1.365v-.01c0-1.663 1.263-3.034 2.88-3.207.188-.911.993-1.595 1.959-1.595Zm-8.085 8.376c-.784 0-1.459.78-1.506 1.797-.047 1.016.64 1.429 1.426 1.429.786 0 1.371-.369 1.418-1.385.047-1.017-.553-1.841-1.338-1.841Zm7.406 0c-.786 0-1.385.824-1.338 1.841.047 1.017.634 1.385 1.418 1.385.785 0 1.473-.413 1.426-1.429-.046-1.017-.721-1.797-1.506-1.797Zm-3.703 4.013c-.974 0-1.907.048-2.77.135-.147.015-.241.168-.183.305.483 1.154 1.622 1.964 2.953 1.964 1.33 0 2.47-.81 2.953-1.964.057-.137-.037-.29-.184-.305-.863-.087-1.795-.135-2.769-.135Z"
196
+ />
197
+
198
+ <!-- Twitch -->
199
+ <path
200
+ v-else-if="normalizedName === 'twitch'"
201
+ :fill="colored ? '#9146FF' : 'currentColor'"
202
+ d="M11.571 4.714h1.715v5.143H11.57zm4.715 0H18v5.143h-1.714zM6 0L1.714 4.286v15.428h5.143V24l4.286-4.286h3.428L22.286 12V0zm14.571 11.143l-3.428 3.428h-3.429l-3 3v-3H6.857V1.714h13.714Z"
203
+ />
204
+
205
+ <!-- Figma -->
206
+ <template v-else-if="normalizedName === 'figma'">
207
+ <template v-if="colored">
208
+ <path fill="#F24E1E" d="M12.735 0H8.148C5.672 0 3.658 2.014 3.658 4.49s2.014 4.49 4.49 4.49h4.587V0z" />
209
+ <path fill="#FF7262" d="M15.852 0h-3.117v8.981h3.117c2.476 0 4.49-2.014 4.49-4.49S18.328 0 15.852 0z" />
210
+ <path fill="#A259FF" d="M12.735 7.51H8.148C5.672 7.51 3.658 9.524 3.658 12s2.014 4.49 4.49 4.49h4.587V7.51z" />
211
+ <path fill="#1ABCFE" d="M15.852 7.51h-.098c-2.476 0-4.49 2.014-4.49 4.49s2.014 4.49 4.49 4.49h.098c2.476 0 4.49-2.014 4.49-4.49s-2.014-4.49-4.49-4.49z" />
212
+ <path fill="#0ACF83" d="M8.172 24c-2.489 0-4.515-2.014-4.515-4.49s2.014-4.49 4.49-4.49h4.588v4.441c0 2.503-2.047 4.539-4.563 4.539z" />
213
+ </template>
214
+ <path
215
+ v-else
216
+ fill="currentColor"
217
+ d="M15.852 8.981h-4.588V0h4.588c2.476 0 4.49 2.014 4.49 4.49s-2.014 4.491-4.49 4.491zM12.735 7.51h3.117c1.665 0 3.019-1.355 3.019-3.019s-1.355-3.019-3.019-3.019h-3.117V7.51zm0 1.471H8.148c-2.476 0-4.49-2.014-4.49-4.49S5.672 0 8.148 0h4.588v8.981zm-4.587-7.51c-1.665 0-3.019 1.355-3.019 3.019s1.354 3.02 3.019 3.02h3.117V1.471H8.148zm4.587 15.019H8.148c-2.476 0-4.49-2.014-4.49-4.49s2.014-4.49 4.49-4.49h4.588v8.98zM8.148 8.981c-1.665 0-3.019 1.355-3.019 3.019s1.355 3.019 3.019 3.019h3.117V8.981H8.148zM8.172 24c-2.489 0-4.515-2.014-4.515-4.49s2.014-4.49 4.49-4.49h4.588v4.441c0 2.503-2.047 4.539-4.563 4.539zm-.024-7.51a3.023 3.023 0 0 0-3.019 3.019c0 1.665 1.365 3.019 3.044 3.019 1.705 0 3.093-1.376 3.093-3.068v-2.97H8.148zm7.704 0h-.098c-2.476 0-4.49-2.014-4.49-4.49s2.014-4.49 4.49-4.49h.098c2.476 0 4.49 2.014 4.49 4.49s-2.014 4.49-4.49 4.49zm-.097-7.509c-1.665 0-3.019 1.355-3.019 3.019s1.355 3.019 3.019 3.019h.098c1.665 0 3.019-1.355 3.019-3.019s-1.355-3.019-3.019-3.019h-.098z"
218
+ />
219
+ </template>
220
+
221
+ <!-- GitLab -->
222
+ <template v-else-if="normalizedName === 'gitlab'">
223
+ <template v-if="colored">
224
+ <path fill="#E24329" d="m12 20.72-4.57-14.07h9.14L12 20.72z" />
225
+ <path fill="#FC6D26" d="M12 20.72 7.43 6.65H1.47l10.53 14.07z" />
226
+ <path fill="#FCA326" d="M1.47 6.65 0 11.18a.9.9 0 0 0 .32 1.01L12 20.72 1.47 6.65z" />
227
+ <path fill="#FC6D26" d="m12 20.72 4.57-14.07h5.96L12 20.72z" />
228
+ <path fill="#FCA326" d="M22.53 6.65 24 11.18a.9.9 0 0 1-.32 1.01L12 20.72l10.53-14.07z" />
229
+ </template>
230
+ <path
231
+ v-else
232
+ fill="currentColor"
233
+ d="m23.6004 9.5927-.0337-.0862L20.3.9814a.851.851 0 0 0-.3362-.405.8748.8748 0 0 0-.9997.0539.8748.8748 0 0 0-.29.4399l-2.2055 6.748H7.5375l-2.2057-6.748a.8573.8573 0 0 0-.29-.4412.8748.8748 0 0 0-.9997-.0537.8585.8585 0 0 0-.3362.4049L.4332 9.5015l-.0325.0862a6.0657 6.0657 0 0 0 2.0119 7.0105l.0113.0087.03.0213 4.976 3.7264 2.462 1.8633 1.4995 1.1321a1.0085 1.0085 0 0 0 1.2197 0l1.4995-1.1321 2.4619-1.8633 5.006-3.7489.0125-.01a6.0682 6.0682 0 0 0 2.0094-7.003z"
234
+ />
235
+ </template>
236
+
237
+ <!-- Spotify -->
238
+ <path
239
+ v-else-if="normalizedName === 'spotify'"
240
+ :fill="colored ? '#1DB954' : 'currentColor'"
241
+ d="M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.66 0 12 0zm5.521 17.34c-.24.359-.66.48-1.021.24-2.82-1.74-6.36-2.101-10.561-1.141-.418.122-.779-.179-.899-.539-.12-.421.18-.78.54-.9 4.56-1.021 8.52-.6 11.64 1.32.42.18.479.659.301 1.02zm1.44-3.3c-.301.42-.841.6-1.262.3-3.239-1.98-8.159-2.58-11.939-1.38-.479.12-1.02-.12-1.14-.6-.12-.48.12-1.021.6-1.141C9.6 9.9 15 10.561 18.72 12.84c.361.181.54.78.241 1.2zm.12-3.36C15.24 8.4 8.82 8.16 5.16 9.301c-.6.179-1.2-.181-1.38-.721-.18-.601.18-1.2.72-1.381 4.26-1.26 11.28-1.02 15.721 1.621.539.3.719 1.02.419 1.56-.299.421-1.02.599-1.559.3z"
242
+ />
243
+
244
+ <!-- Notion -->
245
+ <path
246
+ v-else-if="normalizedName === 'notion'"
247
+ fill="currentColor"
248
+ d="M4.459 4.208c.746.606 1.026.56 2.428.466l13.215-.793c.28 0 .047-.28-.046-.326L17.86 1.968c-.42-.326-.981-.7-2.055-.607L3.01 2.295c-.466.046-.56.28-.374.466zm.793 3.08v13.904c0 .747.373 1.027 1.214.98l14.523-.84c.841-.046.935-.56.935-1.167V6.354c0-.606-.233-.933-.748-.887l-15.177.887c-.56.047-.747.327-.747.933zm14.337.745c.093.42 0 .84-.42.888l-.7.14v10.264c-.608.327-1.168.514-1.635.514-.748 0-.935-.234-1.495-.933l-4.577-7.186v6.952L12.21 19s0 .84-1.168.84l-3.222.186c-.093-.186 0-.653.327-.746l.84-.233V9.854L7.822 9.76c-.094-.42.14-1.026.793-1.073l3.456-.233 4.764 7.279v-6.44l-1.215-.139c-.093-.514.28-.887.747-.933zM1.936 1.035l13.31-.98c1.634-.14 2.055-.047 3.082.7l4.249 2.986c.7.513.934.653.934 1.213v16.378c0 1.026-.373 1.634-1.68 1.726l-15.458.934c-.98.047-1.448-.093-1.962-.747l-3.129-4.06c-.56-.747-.793-1.306-.793-1.96V2.667c0-.839.374-1.54 1.447-1.632z"
249
+ />
250
+
251
+ <!-- Dribbble -->
252
+ <path
253
+ v-else-if="normalizedName === 'dribbble'"
254
+ :fill="colored ? '#EA4C89' : 'currentColor'"
255
+ d="M12 24C5.385 24 0 18.615 0 12S5.385 0 12 0s12 5.385 12 12-5.385 12-12 12zm10.12-10.358c-.35-.11-3.17-.953-6.384-.438 1.34 3.684 1.887 6.684 1.992 7.308 2.3-1.555 3.936-4.02 4.395-6.87zm-6.115 7.808c-.153-.9-.75-4.032-2.19-7.77l-.066.02c-5.79 2.015-7.86 6.025-8.04 6.4 1.73 1.358 3.92 2.166 6.29 2.166 1.42 0 2.77-.29 4-.814zm-11.62-2.58c.232-.4 3.045-5.055 8.332-6.765.135-.045.27-.084.405-.12-.26-.585-.54-1.167-.832-1.74C7.17 11.775 2.206 11.71 1.756 11.7l-.004.312c0 2.633.998 5.037 2.634 6.855zm-2.42-8.955c.46.008 4.683.026 9.477-1.248-1.698-3.018-3.53-5.558-3.8-5.928-2.868 1.35-5.01 3.99-5.676 7.17zM9.6 2.052c.282.38 2.145 2.914 3.822 6 3.645-1.365 5.19-3.44 5.373-3.702-1.81-1.61-4.19-2.586-6.795-2.586-.825 0-1.63.1-2.4.285zm10.335 3.483c-.218.29-1.935 2.493-5.724 4.04.24.49.47.985.68 1.486.08.18.15.36.22.53 3.41-.43 6.8.26 7.14.33-.02-2.42-.88-4.64-2.31-6.38z"
256
+ />
257
+ </svg>
258
+ </template>
@@ -37,6 +37,7 @@ declare module 'vue' {
37
37
  AvatarImage: typeof import('./components/ui/avatar/AvatarImage.vue')['default']
38
38
  Badge: typeof import('./components/ui/badge/Badge.vue')['default']
39
39
  BarChart: typeof import('./components/ui/chart/BarChart.vue')['default']
40
+ BrandIcon: typeof import('./components/BrandIcon.vue')['default']
40
41
  Breadcrumb: typeof import('./components/ui/breadcrumb/Breadcrumb.vue')['default']
41
42
  BreadcrumbEllipsis: typeof import('./components/ui/breadcrumb/BreadcrumbEllipsis.vue')['default']
42
43
  BreadcrumbItem: typeof import('./components/ui/breadcrumb/BreadcrumbItem.vue')['default']
@@ -0,0 +1,216 @@
1
+ <script setup lang="ts">
2
+ import { ref, onMounted, onUnmounted } from 'vue'
3
+ import { RouterView } from 'vue-router'
4
+ import { useColorMode } from '@vueuse/core'
5
+ import {
6
+ Sun,
7
+ Moon,
8
+ Sparkles,
9
+ ShieldCheck,
10
+ Zap,
11
+ } from '@lucide/vue'
12
+ import AppLogo from '@/components/AppLogo.vue'
13
+
14
+ const colorMode = useColorMode()
15
+
16
+ const toggleColorMode = () => {
17
+ colorMode.value = colorMode.value === 'dark' ? 'light' : 'dark'
18
+ }
19
+
20
+ // Testimonial Carousel
21
+ interface Testimonial {
22
+ quote: string
23
+ author: string
24
+ role: string
25
+ company: string
26
+ avatar: string
27
+ }
28
+
29
+ const testimonials: Testimonial[] = [
30
+ {
31
+ quote: 'Nala reduced our frontend delivery cycles by over 70%. The architecture, real API adapters, and UI primitives are exceptionally well-crafted.',
32
+ author: 'Sarah Jenkins',
33
+ role: 'VP of Product',
34
+ company: 'Horizon SaaS',
35
+ avatar: 'SJ',
36
+ },
37
+ {
38
+ quote: 'The strict TypeScript hygiene, Tailwind v4 design tokens, and zero-boilerplate auto-imports make pairing with AI agents effortless.',
39
+ author: 'David Chen',
40
+ role: 'Lead Architect',
41
+ company: 'CloudScale Technologies',
42
+ avatar: 'DC',
43
+ },
44
+ {
45
+ quote: 'By far the cleanest, fastest, and most comprehensive Vue 3 enterprise admin dashboard available. Exceptional attention to detail.',
46
+ author: 'Elena Rostova',
47
+ role: 'Chief Technology Officer',
48
+ company: 'Synapse AI',
49
+ avatar: 'ER',
50
+ },
51
+ ]
52
+
53
+ const activeIndex = ref(0)
54
+ let carouselTimer: ReturnType<typeof setInterval> | null = null
55
+
56
+ onMounted(() => {
57
+ carouselTimer = setInterval(() => {
58
+ activeIndex.value = (activeIndex.value + 1) % testimonials.length
59
+ }, 6000)
60
+ })
61
+
62
+ onUnmounted(() => {
63
+ if (carouselTimer) clearInterval(carouselTimer)
64
+ })
65
+ </script>
66
+
67
+ <template>
68
+ <div class="min-h-dvh lg:h-screen w-full flex flex-col lg:grid lg:grid-cols-12 bg-background text-foreground transition-colors duration-200 lg:overflow-hidden">
69
+ <!-- Left Column: Authentication Form Container (5 Cols / 7 Cols responsive) -->
70
+ <div class="flex-1 flex flex-col justify-between p-6 sm:p-8 lg:p-8 xl:p-10 lg:col-span-6 xl:col-span-5 relative overflow-y-auto lg:h-full">
71
+ <!-- Top Brand Navigation Header -->
72
+ <header class="flex items-center justify-between w-full shrink-0">
73
+ <router-link to="/" class="inline-flex items-center gap-2.5 group focus:outline-none">
74
+ <AppLogo size="md" :withText="true" />
75
+ </router-link>
76
+
77
+ <div class="flex items-center gap-2">
78
+ <!-- Theme Toggle -->
79
+ <button
80
+ type="button"
81
+ class="h-8 w-8 rounded-lg border border-border/80 flex items-center justify-center text-muted-foreground hover:text-foreground hover:bg-muted/60 transition-colors cursor-pointer"
82
+ title="Toggle theme"
83
+ @click="toggleColorMode"
84
+ >
85
+ <Sun v-if="colorMode === 'dark'" class="h-4 w-4" />
86
+ <Moon v-else class="h-4 w-4" />
87
+ </button>
88
+ </div>
89
+ </header>
90
+
91
+ <!-- Center Auth Content Area -->
92
+ <main class="my-auto py-6 w-full max-w-md mx-auto flex flex-col justify-center">
93
+ <RouterView v-slot="{ Component }">
94
+ <Transition name="page" mode="out-in">
95
+ <component :is="Component" />
96
+ </Transition>
97
+ </RouterView>
98
+ </main>
99
+
100
+ <!-- Bottom Footer -->
101
+ <footer class="pt-4 flex flex-col sm:flex-row items-center justify-between text-xs text-muted-foreground gap-2 border-t border-border/40 shrink-0">
102
+ <p>&copy; {{ new Date().getFullYear() }} Nala Dashboard. All rights reserved.</p>
103
+ <div class="flex items-center gap-4">
104
+ <a href="#" class="hover:text-foreground transition-colors">Privacy Policy</a>
105
+ <a href="#" class="hover:text-foreground transition-colors">Terms of Service</a>
106
+ <a href="#" class="hover:text-foreground transition-colors">Security</a>
107
+ </div>
108
+ </footer>
109
+ </div>
110
+
111
+ <!-- Right Column: Hero Side-Banner Panel (7 Cols / 8 Cols on desktop) -->
112
+ <aside class="hidden lg:flex lg:col-span-6 xl:col-span-7 relative flex-col justify-between p-8 xl:p-10 overflow-hidden bg-muted/30 border-l border-border/60 lg:h-full">
113
+ <!-- Ambient Gradient Backdrops -->
114
+ <div class="absolute inset-0 bg-linear-to-br from-primary/10 via-primary/5 to-transparent pointer-events-none" />
115
+ <div class="absolute -top-24 -right-24 h-96 w-96 rounded-full bg-primary/15 blur-3xl pointer-events-none" />
116
+ <div class="absolute -bottom-24 -left-24 h-96 w-96 rounded-full bg-primary/10 blur-3xl pointer-events-none" />
117
+
118
+ <!-- Top Badge / Header info -->
119
+ <div class="relative z-10 flex items-center justify-between shrink-0">
120
+ <div class="inline-flex items-center gap-2 rounded-full border border-primary/20 bg-primary/10 px-3 py-1 text-xs font-medium text-primary backdrop-blur-xs">
121
+ <Sparkles class="h-3.5 w-3.5" />
122
+ Enterprise Admin Platform
123
+ </div>
124
+
125
+ <div class="flex items-center gap-4 text-xs text-muted-foreground">
126
+ <span class="inline-flex items-center gap-1.5">
127
+ <span class="h-2 w-2 rounded-full bg-emerald-500 animate-pulse" />
128
+ v3.1.1 Production Ready
129
+ </span>
130
+ </div>
131
+ </div>
132
+
133
+ <!-- Center Hero Graphic & Value Proposition -->
134
+ <div class="relative z-10 my-auto py-4 xl:py-6 space-y-5 xl:space-y-6 max-w-xl">
135
+ <div class="space-y-2">
136
+ <h2 class="text-2xl xl:text-3xl font-bold tracking-tight text-foreground">
137
+ The Enterprise Architecture for High-Velocity Teams.
138
+ </h2>
139
+ <p class="text-xs xl:text-sm text-muted-foreground leading-relaxed">
140
+ Built with Vue 3 Composition API, Tailwind CSS v4 OKLCH tokens, Reka UI primitives, and real API adapters with safe offline fallbacks.
141
+ </p>
142
+ </div>
143
+
144
+ <!-- Key Capability Badges -->
145
+ <div class="grid grid-cols-2 gap-3 pt-1">
146
+ <div class="flex items-start gap-2.5 rounded-xl border border-border/70 bg-card/60 p-3 backdrop-blur-xs shadow-2xs">
147
+ <ShieldCheck class="h-4 w-4 text-primary mt-0.5 shrink-0" />
148
+ <div>
149
+ <h4 class="text-xs font-semibold text-foreground">Enterprise Security</h4>
150
+ <p class="text-[11px] text-muted-foreground mt-0.5">2FA TOTP & SAML Single Sign-On</p>
151
+ </div>
152
+ </div>
153
+
154
+ <div class="flex items-start gap-2.5 rounded-xl border border-border/70 bg-card/60 p-3 backdrop-blur-xs shadow-2xs">
155
+ <Zap class="h-4 w-4 text-amber-500 mt-0.5 shrink-0" />
156
+ <div>
157
+ <h4 class="text-xs font-semibold text-foreground">Sub-Second HMR</h4>
158
+ <p class="text-[11px] text-muted-foreground mt-0.5">Vite 8 bundler with zero-import</p>
159
+ </div>
160
+ </div>
161
+ </div>
162
+
163
+ <!-- Dynamic Testimonial Card with Transition -->
164
+ <div class="rounded-2xl border border-border/80 bg-card/80 p-5 backdrop-blur-md shadow-xs relative overflow-hidden transition-all duration-300">
165
+ <div class="space-y-3">
166
+ <p class="text-xs xl:text-sm text-foreground/90 italic leading-relaxed min-h-12 xl:min-h-14">
167
+ "{{ testimonials[activeIndex].quote }}"
168
+ </p>
169
+
170
+ <div class="flex items-center justify-between pt-2 border-t border-border/50">
171
+ <div class="flex items-center gap-3">
172
+ <div class="h-8 w-8 rounded-full bg-primary/15 text-primary font-semibold text-xs flex items-center justify-center border border-primary/20 shrink-0">
173
+ {{ testimonials[activeIndex].avatar }}
174
+ </div>
175
+ <div>
176
+ <div class="text-xs font-semibold text-foreground">{{ testimonials[activeIndex].author }}</div>
177
+ <div class="text-[11px] text-muted-foreground">{{ testimonials[activeIndex].role }} &middot; {{ testimonials[activeIndex].company }}</div>
178
+ </div>
179
+ </div>
180
+
181
+ <!-- Carousel Dots -->
182
+ <div class="flex items-center gap-1.5">
183
+ <button
184
+ v-for="(_, index) in testimonials"
185
+ :key="index"
186
+ type="button"
187
+ :class="[
188
+ 'h-1.5 rounded-full transition-all cursor-pointer',
189
+ activeIndex === index ? 'w-5 bg-primary' : 'w-1.5 bg-muted-foreground/30 hover:bg-muted-foreground/50'
190
+ ]"
191
+ @click="activeIndex = index"
192
+ />
193
+ </div>
194
+ </div>
195
+ </div>
196
+ </div>
197
+ </div>
198
+
199
+ <!-- Bottom Platform Metrics Strip -->
200
+ <div class="relative z-10 grid grid-cols-3 gap-4 pt-4 border-t border-border/50 shrink-0">
201
+ <div>
202
+ <div class="text-xl xl:text-2xl font-bold tracking-tight text-foreground">46+</div>
203
+ <div class="text-xs text-muted-foreground mt-0.5">UI Primitives</div>
204
+ </div>
205
+ <div>
206
+ <div class="text-xl xl:text-2xl font-bold tracking-tight text-foreground">99.9%</div>
207
+ <div class="text-xs text-muted-foreground mt-0.5">SLA Availability</div>
208
+ </div>
209
+ <div>
210
+ <div class="text-xl xl:text-2xl font-bold tracking-tight text-foreground">&lt;100ms</div>
211
+ <div class="text-xs text-muted-foreground mt-0.5">API Latency</div>
212
+ </div>
213
+ </div>
214
+ </aside>
215
+ </div>
216
+ </template>
@@ -115,6 +115,106 @@ const router = createRouter({
115
115
  name: 'lock-screen',
116
116
  component: () => import('@/views/auth/LockScreenView.vue'),
117
117
  },
118
+ {
119
+ path: '2fa',
120
+ name: 'two-factor',
121
+ component: () => import('@/views/auth/TwoFactorChallengeView.vue'),
122
+ },
123
+ {
124
+ path: 'two-factor',
125
+ redirect: '/auth/2fa',
126
+ },
127
+ {
128
+ path: 'sso',
129
+ name: 'sso-login',
130
+ component: () => import('@/views/auth/SsoLoginView.vue'),
131
+ },
132
+ {
133
+ path: 'magic-link',
134
+ name: 'magic-link',
135
+ component: () => import('@/views/auth/MagicLinkView.vue'),
136
+ },
137
+ {
138
+ path: 'select-tenant',
139
+ name: 'select-tenant',
140
+ component: () => import('@/views/auth/SelectTenantView.vue'),
141
+ },
142
+ {
143
+ path: 'select-workspace',
144
+ redirect: '/auth/select-tenant',
145
+ },
146
+ {
147
+ path: 'suspended',
148
+ name: 'suspended',
149
+ component: () => import('@/views/auth/SuspendedView.vue'),
150
+ },
151
+ {
152
+ path: 'deactivated',
153
+ redirect: '/auth/suspended',
154
+ },
155
+ {
156
+ path: 'frozen',
157
+ redirect: '/auth/suspended',
158
+ },
159
+ ],
160
+ },
161
+ {
162
+ path: '/auth-split',
163
+ component: () => import('@/layouts/AuthSplitLayout.vue'),
164
+ children: [
165
+ {
166
+ path: '',
167
+ redirect: '/auth-split/login',
168
+ },
169
+ {
170
+ path: 'login',
171
+ name: 'split-login',
172
+ component: () => import('@/views/auth/LoginView.vue'),
173
+ },
174
+ {
175
+ path: 'register',
176
+ name: 'split-register',
177
+ component: () => import('@/views/auth/RegisterView.vue'),
178
+ },
179
+ {
180
+ path: '2fa',
181
+ name: 'split-2fa',
182
+ component: () => import('@/views/auth/TwoFactorChallengeView.vue'),
183
+ },
184
+ {
185
+ path: 'sso',
186
+ name: 'split-sso',
187
+ component: () => import('@/views/auth/SsoLoginView.vue'),
188
+ },
189
+ {
190
+ path: 'magic-link',
191
+ name: 'split-magic-link',
192
+ component: () => import('@/views/auth/MagicLinkView.vue'),
193
+ },
194
+ {
195
+ path: 'select-tenant',
196
+ name: 'split-select-tenant',
197
+ component: () => import('@/views/auth/SelectTenantView.vue'),
198
+ },
199
+ {
200
+ path: 'select-workspace',
201
+ redirect: '/auth-split/select-tenant',
202
+ },
203
+ {
204
+ path: 'forgot-password',
205
+ name: 'split-forgot-password',
206
+ component: () => import('@/views/auth/ForgotPasswordView.vue'),
207
+ },
208
+ {
209
+ path: 'reset-password',
210
+ name: 'split-reset-password',
211
+ component: () => import('@/views/auth/ResetPasswordView.vue'),
212
+ },
213
+ {
214
+ path: 'suspended',
215
+ name: 'split-suspended',
216
+ component: () => import('@/views/auth/SuspendedView.vue'),
217
+ },
118
218
  ],
119
219
  },
120
220
  {
@@ -1,6 +1,4 @@
1
1
 
2
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
3
-
4
2
  @font-face {
5
3
  font-family: 'Inter';
6
4
  src: url('./assets/fonts/InterVariable.woff2') format('woff2-variations');
@@ -109,7 +109,7 @@ function fillDemoPassword() {
109
109
  </CardDescription>
110
110
  </CardHeader>
111
111
 
112
- <CardContent class="space-y-4">
112
+ <CardContent class="px-6 sm:px-8 pb-6 space-y-4">
113
113
  <form @submit.prevent="handleUnlock" class="space-y-4">
114
114
  <div class="space-y-2">
115
115
  <div class="flex items-center justify-between">