@cogito.ai/cli 0.3.1 → 0.3.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.
Files changed (41) hide show
  1. package/README.md +181 -0
  2. package/dist/templates/web-nextjs/.env.example +4 -0
  3. package/dist/templates/web-nextjs/.vscode/settings.json +3 -0
  4. package/dist/templates/web-nextjs/README.md +25 -1
  5. package/dist/templates/web-nextjs/apps/docs/.source/browser.ts +1 -1
  6. package/dist/templates/web-nextjs/apps/docs/.source/server.ts +4 -3
  7. package/dist/templates/web-nextjs/apps/docs/content/docs/features/auth.mdx +139 -0
  8. package/dist/templates/web-nextjs/apps/web/components.json +25 -0
  9. package/dist/templates/web-nextjs/apps/web/messages/en.json +28 -0
  10. package/dist/templates/web-nextjs/apps/web/messages/zh.json +28 -0
  11. package/dist/templates/web-nextjs/apps/web/middleware.ts +53 -9
  12. package/dist/templates/web-nextjs/apps/web/package.json +13 -1
  13. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(auth)/login/page.tsx +142 -0
  14. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(auth)/signup/page.tsx +151 -0
  15. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(protected)/dashboard/page.tsx +42 -0
  16. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(protected)/layout.tsx +22 -0
  17. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/globals.css +129 -3
  18. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/layout.tsx +2 -4
  19. package/dist/templates/web-nextjs/apps/web/src/app/auth/callback/route.ts +21 -0
  20. package/dist/templates/web-nextjs/apps/web/src/components/ui/alert.tsx +76 -0
  21. package/dist/templates/web-nextjs/apps/web/src/components/ui/button.tsx +58 -0
  22. package/dist/templates/web-nextjs/apps/web/src/components/ui/form.tsx +154 -0
  23. package/dist/templates/web-nextjs/apps/web/src/components/ui/input.tsx +20 -0
  24. package/dist/templates/web-nextjs/apps/web/src/components/ui/label.tsx +20 -0
  25. package/dist/templates/web-nextjs/apps/web/src/components/ui/sonner.tsx +50 -0
  26. package/dist/templates/web-nextjs/apps/web/src/core/repositories/IAuthRepository.ts +9 -0
  27. package/dist/templates/web-nextjs/apps/web/src/core/types/auth.ts +14 -0
  28. package/dist/templates/web-nextjs/apps/web/src/features/auth/__contract__.ts +14 -0
  29. package/dist/templates/web-nextjs/apps/web/src/features/auth/actions.ts +86 -0
  30. package/dist/templates/web-nextjs/apps/web/src/features/auth/index.ts +1 -0
  31. package/dist/templates/web-nextjs/apps/web/src/i18n/config.ts +12 -0
  32. package/dist/templates/web-nextjs/apps/web/src/i18n/request.ts +3 -1
  33. package/dist/templates/web-nextjs/apps/web/src/infra/db/SupabaseAuthRepository.ts +63 -0
  34. package/dist/templates/web-nextjs/apps/web/src/infra/db/client.ts +38 -0
  35. package/dist/templates/web-nextjs/apps/web/src/infra/providers.ts +6 -0
  36. package/dist/templates/web-nextjs/apps/web/src/lib/utils.ts +6 -0
  37. package/dist/templates/web-nextjs/apps/web/src/lib/validations/auth.ts +20 -0
  38. package/dist/templates/web-nextjs/apps/web/src/styles/shadcn-tailwind.css +95 -0
  39. package/dist/templates/web-nextjs/apps/web/src/styles/tw-animate.css +1 -0
  40. package/dist/templates/web-nextjs/pnpm-lock.yaml +2327 -17
  41. package/package.json +1 -1
@@ -0,0 +1,154 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import {
5
+ Controller,
6
+ type ControllerProps,
7
+ type FieldPath,
8
+ type FieldValues,
9
+ FormProvider,
10
+ useFormContext,
11
+ type UseFormReturn,
12
+ } from "react-hook-form"
13
+
14
+ import { cn } from "@/lib/utils"
15
+ import { Label } from "@/components/ui/label"
16
+
17
+ const Form = FormProvider
18
+
19
+ type FormFieldContextValue<
20
+ TFieldValues extends FieldValues = FieldValues,
21
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
22
+ > = {
23
+ name: TName
24
+ }
25
+
26
+ const FormFieldContext = React.createContext<FormFieldContextValue>(
27
+ {} as FormFieldContextValue,
28
+ )
29
+
30
+ function FormField<
31
+ TFieldValues extends FieldValues = FieldValues,
32
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
33
+ >({ ...props }: ControllerProps<TFieldValues, TName>) {
34
+ return (
35
+ <FormFieldContext.Provider value={{ name: props.name }}>
36
+ <Controller {...props} />
37
+ </FormFieldContext.Provider>
38
+ )
39
+ }
40
+
41
+ function useFormField() {
42
+ const fieldContext = React.useContext(FormFieldContext)
43
+ const itemContext = React.useContext(FormItemContext)
44
+ const { getFieldState, formState } = useFormContext()
45
+
46
+ const fieldState = getFieldState(fieldContext.name, formState)
47
+
48
+ if (!fieldContext) {
49
+ throw new Error("useFormField should be used within <FormField>")
50
+ }
51
+
52
+ const { id } = itemContext
53
+
54
+ return {
55
+ id,
56
+ name: fieldContext.name,
57
+ formItemId: `${id}-form-item`,
58
+ formDescriptionId: `${id}-form-item-description`,
59
+ formMessageId: `${id}-form-item-message`,
60
+ ...fieldState,
61
+ }
62
+ }
63
+
64
+ type FormItemContextValue = {
65
+ id: string
66
+ }
67
+
68
+ const FormItemContext = React.createContext<FormItemContextValue>(
69
+ {} as FormItemContextValue,
70
+ )
71
+
72
+ function FormItem({ className, ...props }: React.ComponentProps<"div">) {
73
+ const id = React.useId()
74
+
75
+ return (
76
+ <FormItemContext.Provider value={{ id }}>
77
+ <div className={cn("grid gap-2", className)} {...props} />
78
+ </FormItemContext.Provider>
79
+ )
80
+ }
81
+
82
+ function FormLabel({
83
+ className,
84
+ ...props
85
+ }: React.ComponentProps<typeof Label>) {
86
+ const { error, formItemId } = useFormField()
87
+
88
+ return (
89
+ <Label
90
+ className={cn(error && "text-destructive", className)}
91
+ htmlFor={formItemId}
92
+ {...props}
93
+ />
94
+ )
95
+ }
96
+
97
+ function FormControl({ ...props }: React.ComponentProps<"div">) {
98
+ const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
99
+
100
+ return (
101
+ <div
102
+ id={formItemId}
103
+ aria-describedby={
104
+ !error
105
+ ? `${formDescriptionId}`
106
+ : `${formDescriptionId} ${formMessageId}`
107
+ }
108
+ aria-invalid={!!error}
109
+ {...props}
110
+ />
111
+ )
112
+ }
113
+
114
+ function FormDescription({ className, ...props }: React.ComponentProps<"p">) {
115
+ const { formDescriptionId } = useFormField()
116
+
117
+ return (
118
+ <p
119
+ id={formDescriptionId}
120
+ className={cn("text-sm text-muted-foreground", className)}
121
+ {...props}
122
+ />
123
+ )
124
+ }
125
+
126
+ function FormMessage({ className, children, ...props }: React.ComponentProps<"p">) {
127
+ const { error, formMessageId } = useFormField()
128
+ const body = error ? String(error?.message ?? "") : children
129
+
130
+ if (!body) {
131
+ return null
132
+ }
133
+
134
+ return (
135
+ <p
136
+ id={formMessageId}
137
+ className={cn("text-sm font-medium text-destructive", className)}
138
+ {...props}
139
+ >
140
+ {body}
141
+ </p>
142
+ )
143
+ }
144
+
145
+ export {
146
+ useFormField,
147
+ Form,
148
+ FormItem,
149
+ FormLabel,
150
+ FormControl,
151
+ FormDescription,
152
+ FormMessage,
153
+ FormField,
154
+ }
@@ -0,0 +1,20 @@
1
+ import * as React from "react"
2
+ import { Input as InputPrimitive } from "@base-ui/react/input"
3
+
4
+ import { cn } from "@/lib/utils"
5
+
6
+ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
7
+ return (
8
+ <InputPrimitive
9
+ type={type}
10
+ data-slot="input"
11
+ className={cn(
12
+ "h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
13
+ className
14
+ )}
15
+ {...props}
16
+ />
17
+ )
18
+ }
19
+
20
+ export { Input }
@@ -0,0 +1,20 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ function Label({ className, ...props }: React.ComponentProps<"label">) {
8
+ return (
9
+ <label
10
+ data-slot="label"
11
+ className={cn(
12
+ "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
13
+ className
14
+ )}
15
+ {...props}
16
+ />
17
+ )
18
+ }
19
+
20
+ export { Label }
@@ -0,0 +1,50 @@
1
+ "use client"
2
+
3
+ import { useTheme } from "next-themes"
4
+ import { Toaster as Sonner, type ToasterProps } from "sonner"
5
+ import { CircleCheckIcon, InfoIcon, TriangleAlertIcon, OctagonXIcon, Loader2Icon } from "lucide-react"
6
+
7
+ const Toaster = ({ ...props }: ToasterProps) => {
8
+ const { resolvedTheme } = useTheme()
9
+ const theme: ToasterProps['theme'] = resolvedTheme === 'dark' ? 'dark' : resolvedTheme === 'light' ? 'light' : 'system'
10
+
11
+ return (
12
+ <Sonner
13
+ theme={theme}
14
+ className="toaster group"
15
+ icons={{
16
+ success: (
17
+ <CircleCheckIcon className="size-4" />
18
+ ),
19
+ info: (
20
+ <InfoIcon className="size-4" />
21
+ ),
22
+ warning: (
23
+ <TriangleAlertIcon className="size-4" />
24
+ ),
25
+ error: (
26
+ <OctagonXIcon className="size-4" />
27
+ ),
28
+ loading: (
29
+ <Loader2Icon className="size-4 animate-spin" />
30
+ ),
31
+ }}
32
+ style={
33
+ {
34
+ "--normal-bg": "var(--popover)",
35
+ "--normal-text": "var(--popover-foreground)",
36
+ "--normal-border": "var(--border)",
37
+ "--border-radius": "var(--radius)",
38
+ } as React.CSSProperties
39
+ }
40
+ toastOptions={{
41
+ classNames: {
42
+ toast: "cn-toast",
43
+ },
44
+ }}
45
+ {...props}
46
+ />
47
+ )
48
+ }
49
+
50
+ export { Toaster }
@@ -0,0 +1,9 @@
1
+ import type { AuthResult, AuthUser } from '@/core/types/auth'
2
+
3
+ export interface IAuthRepository {
4
+ signInWithPassword(email: string, password: string): Promise<AuthResult>
5
+ signUp(email: string, password: string): Promise<AuthResult>
6
+ signOut(): Promise<void>
7
+ getSession(): Promise<AuthUser | null>
8
+ signInWithOAuth(provider: 'github', nextPath?: string): Promise<{ url: string }>
9
+ }
@@ -0,0 +1,14 @@
1
+ export type AuthUser = {
2
+ id: string
3
+ email: string
4
+ createdAt: string
5
+ }
6
+
7
+ export type AuthResult = {
8
+ user: AuthUser | null
9
+ error: string | null
10
+ }
11
+
12
+ export type ActionResult<T = void> =
13
+ | { data: T; error: null }
14
+ | { data: null; error: string }
@@ -0,0 +1,14 @@
1
+ import type { ActionResult } from '@/core/types/auth'
2
+
3
+ export type SignInArgs = { email: string; password: string }
4
+ export type SignUpArgs = { email: string; password: string; confirmPassword: string }
5
+ export type SignUpSuccessData = { success: true; email: string }
6
+ export type OAuthData = { url: string }
7
+
8
+ export interface AuthFeatureContract {
9
+ signIn(args: SignInArgs): Promise<ActionResult>
10
+ signUp(args: SignUpArgs): Promise<ActionResult<SignUpSuccessData>>
11
+ signOut(): Promise<void>
12
+ signInWithGithub(): Promise<ActionResult<OAuthData>>
13
+ signInWithGithubForLocale(locale: string): Promise<ActionResult<OAuthData>>
14
+ }
@@ -0,0 +1,86 @@
1
+ 'use server'
2
+
3
+ import { redirect } from 'next/navigation'
4
+ import { getAuthRepository } from '@/infra/providers'
5
+ import { signInSchema, signUpSchema } from '@/lib/validations/auth'
6
+ import type { ActionResult } from '@/core/types/auth'
7
+ import { defaultLocale, isLocale } from '@/i18n/config'
8
+ import type { SignUpSuccessData, OAuthData } from './__contract__'
9
+
10
+ function normalizeLocale(input: FormDataEntryValue | null): string {
11
+ const locale = typeof input === 'string' ? input : defaultLocale
12
+ return isLocale(locale) ? locale : defaultLocale
13
+ }
14
+
15
+ export async function signIn(
16
+ _prevState: ActionResult | null,
17
+ formData: FormData,
18
+ ): Promise<ActionResult> {
19
+ const parsed = signInSchema.safeParse({
20
+ email: formData.get('email'),
21
+ password: formData.get('password'),
22
+ })
23
+
24
+ if (!parsed.success) {
25
+ return { data: null, error: parsed.error.issues[0]?.message ?? '输入无效' }
26
+ }
27
+
28
+ const repo = getAuthRepository()
29
+ const result = await repo.signInWithPassword(parsed.data.email, parsed.data.password)
30
+
31
+ if (result.error) {
32
+ return { data: null, error: result.error }
33
+ }
34
+
35
+ const locale = normalizeLocale(formData.get('locale'))
36
+ redirect(`/${locale}/dashboard`)
37
+ }
38
+
39
+ export async function signUp(
40
+ _prevState: ActionResult<SignUpSuccessData> | null,
41
+ formData: FormData,
42
+ ): Promise<ActionResult<SignUpSuccessData>> {
43
+ const parsed = signUpSchema.safeParse({
44
+ email: formData.get('email'),
45
+ password: formData.get('password'),
46
+ confirmPassword: formData.get('confirmPassword'),
47
+ })
48
+
49
+ if (!parsed.success) {
50
+ return { data: null, error: parsed.error.issues[0]?.message ?? '输入无效' }
51
+ }
52
+
53
+ const repo = getAuthRepository()
54
+ const result = await repo.signUp(parsed.data.email, parsed.data.password)
55
+
56
+ if (result.error) {
57
+ return { data: null, error: result.error }
58
+ }
59
+
60
+ return { data: { success: true, email: parsed.data.email }, error: null }
61
+ }
62
+
63
+ export async function signOut(formData: FormData): Promise<void> {
64
+ const repo = getAuthRepository()
65
+ await repo.signOut()
66
+ const locale = normalizeLocale(formData.get('locale'))
67
+ redirect(`/${locale}/login`)
68
+ }
69
+
70
+ export async function signInWithGithub(): Promise<ActionResult<OAuthData>> {
71
+ return signInWithGithubForLocale(defaultLocale)
72
+ }
73
+
74
+ export async function signInWithGithubForLocale(
75
+ localeInput: string,
76
+ ): Promise<ActionResult<OAuthData>> {
77
+ const repo = getAuthRepository()
78
+ const locale = isLocale(localeInput) ? localeInput : defaultLocale
79
+ try {
80
+ const { url } = await repo.signInWithOAuth('github', `/${locale}/dashboard`)
81
+ return { data: { url }, error: null }
82
+ } catch (err) {
83
+ const msg = err instanceof Error ? err.message : 'OAuth 初始化失败'
84
+ return { data: null, error: msg }
85
+ }
86
+ }
@@ -0,0 +1 @@
1
+ export { signIn, signUp, signOut, signInWithGithub, signInWithGithubForLocale } from './actions'
@@ -0,0 +1,12 @@
1
+ export const locales = ['en', 'zh'] as const
2
+
3
+ export type AppLocale = (typeof locales)[number]
4
+
5
+ const envDefaultLocale = process.env.APP_DEFAULT_LOCALE
6
+
7
+ export const defaultLocale: AppLocale =
8
+ envDefaultLocale === 'en' || envDefaultLocale === 'zh' ? envDefaultLocale : 'zh'
9
+
10
+ export function isLocale(value: string): value is AppLocale {
11
+ return locales.includes(value as AppLocale)
12
+ }
@@ -1,7 +1,9 @@
1
1
  import { getRequestConfig } from 'next-intl/server'
2
+ import { defaultLocale, isLocale } from './config'
2
3
 
3
4
  export default getRequestConfig(async ({ requestLocale }) => {
4
- const locale = (await requestLocale) ?? 'en'
5
+ const candidateLocale = await requestLocale
6
+ const locale = candidateLocale && isLocale(candidateLocale) ? candidateLocale : defaultLocale
5
7
 
6
8
  return {
7
9
  locale,
@@ -0,0 +1,63 @@
1
+ import type { IAuthRepository } from '@/core/repositories/IAuthRepository'
2
+ import type { AuthResult, AuthUser } from '@/core/types/auth'
3
+ import { getServerClient } from '@/infra/db/client'
4
+
5
+ export class SupabaseAuthRepository implements IAuthRepository {
6
+ async signInWithPassword(email: string, password: string): Promise<AuthResult> {
7
+ const supabase = await getServerClient()
8
+ const { data, error } = await supabase.auth.signInWithPassword({ email, password })
9
+ if (error) {
10
+ return { user: null, error: error.message }
11
+ }
12
+ const u = data.user
13
+ return {
14
+ user: u ? { id: u.id, email: u.email ?? '', createdAt: u.created_at } : null,
15
+ error: null,
16
+ }
17
+ }
18
+
19
+ async signUp(email: string, password: string): Promise<AuthResult> {
20
+ const supabase = await getServerClient()
21
+ const { data, error } = await supabase.auth.signUp({ email, password })
22
+ if (error) {
23
+ const msg = error.message.toLowerCase().includes('already')
24
+ ? '该邮箱已被注册'
25
+ : error.message
26
+ return { user: null, error: msg }
27
+ }
28
+ const u = data.user
29
+ return {
30
+ user: u ? { id: u.id, email: u.email ?? '', createdAt: u.created_at } : null,
31
+ error: null,
32
+ }
33
+ }
34
+
35
+ async signOut(): Promise<void> {
36
+ const supabase = await getServerClient()
37
+ await supabase.auth.signOut()
38
+ }
39
+
40
+ async getSession(): Promise<AuthUser | null> {
41
+ const supabase = await getServerClient()
42
+ const { data: { user } } = await supabase.auth.getUser()
43
+ if (!user) return null
44
+ return { id: user.id, email: user.email ?? '', createdAt: user.created_at }
45
+ }
46
+
47
+ async signInWithOAuth(provider: 'github', nextPath = '/zh/dashboard'): Promise<{ url: string }> {
48
+ const supabase = await getServerClient()
49
+ const appUrl = process.env.NEXT_PUBLIC_APP_URL ?? 'http://localhost:3000'
50
+ const safeNextPath = nextPath.startsWith('/') ? nextPath : '/zh/dashboard'
51
+ const redirectTo = `${appUrl}/auth/callback?next=${encodeURIComponent(safeNextPath)}`
52
+ const { data, error } = await supabase.auth.signInWithOAuth({
53
+ provider,
54
+ options: {
55
+ redirectTo,
56
+ },
57
+ })
58
+ if (error || !data.url) {
59
+ throw new Error(error?.message ?? 'OAuth redirect URL unavailable')
60
+ }
61
+ return { url: data.url }
62
+ }
63
+ }
@@ -1,6 +1,7 @@
1
1
  import { createServerClient } from '@supabase/ssr'
2
2
  import { createBrowserClient } from '@supabase/ssr'
3
3
  import { cookies } from 'next/headers'
4
+ import type { NextRequest, NextResponse } from 'next/server'
4
5
 
5
6
  /**
6
7
  * Returns a Supabase client safe for use in Server Components and Server Actions.
@@ -53,3 +54,40 @@ export function getBrowserClient() {
53
54
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
54
55
  )
55
56
  }
57
+
58
+ /**
59
+ * Returns a Supabase client for use in middleware.
60
+ * Reads and writes cookies via the provided request/response objects.
61
+ *
62
+ * Usage:
63
+ * ```ts
64
+ * // In middleware.ts:
65
+ * const { supabase, response } = createMiddlewareClient(request, response)
66
+ * await supabase.auth.getUser() // refreshes session token
67
+ * ```
68
+ */
69
+ export function createMiddlewareClient(
70
+ request: NextRequest,
71
+ response: NextResponse,
72
+ ) {
73
+ const supabase = createServerClient(
74
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
75
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
76
+ {
77
+ cookies: {
78
+ getAll() {
79
+ return request.cookies.getAll()
80
+ },
81
+ setAll(cookiesToSet) {
82
+ for (const { name, value } of cookiesToSet) {
83
+ request.cookies.set(name, value)
84
+ }
85
+ for (const { name, value, options } of cookiesToSet) {
86
+ response.cookies.set(name, value, options)
87
+ }
88
+ },
89
+ },
90
+ },
91
+ )
92
+ return { supabase, response }
93
+ }
@@ -0,0 +1,6 @@
1
+ import { SupabaseAuthRepository } from './db/SupabaseAuthRepository'
2
+ import type { IAuthRepository } from '@/core/repositories/IAuthRepository'
3
+
4
+ export function getAuthRepository(): IAuthRepository {
5
+ return new SupabaseAuthRepository()
6
+ }
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
@@ -0,0 +1,20 @@
1
+ import { z } from 'zod'
2
+
3
+ export const signInSchema = z.object({
4
+ email: z.string().email('请输入有效的邮箱地址'),
5
+ password: z.string().min(8, '密码至少 8 位'),
6
+ })
7
+
8
+ export const signUpSchema = z
9
+ .object({
10
+ email: z.string().email('请输入有效的邮箱地址'),
11
+ password: z.string().min(8, '密码至少 8 位'),
12
+ confirmPassword: z.string(),
13
+ })
14
+ .refine((data) => data.password === data.confirmPassword, {
15
+ message: '两次密码不一致',
16
+ path: ['confirmPassword'],
17
+ })
18
+
19
+ export type SignInInput = z.infer<typeof signInSchema>
20
+ export type SignUpInput = z.infer<typeof signUpSchema>
@@ -0,0 +1,95 @@
1
+ @theme inline {
2
+ @keyframes accordion-down {
3
+ from {
4
+ height: 0;
5
+ }
6
+ to {
7
+ height: var(
8
+ --radix-accordion-content-height,
9
+ var(--accordion-panel-height, auto)
10
+ );
11
+ }
12
+ }
13
+
14
+ @keyframes accordion-up {
15
+ from {
16
+ height: var(
17
+ --radix-accordion-content-height,
18
+ var(--accordion-panel-height, auto)
19
+ );
20
+ }
21
+ to {
22
+ height: 0;
23
+ }
24
+ }
25
+ }
26
+
27
+ /* Custom variants */
28
+ @custom-variant data-open {
29
+ &:where([data-state="open"]),
30
+ &:where([data-open]:not([data-open="false"])) {
31
+ @slot;
32
+ }
33
+ }
34
+
35
+ @custom-variant data-closed {
36
+ &:where([data-state="closed"]),
37
+ &:where([data-closed]:not([data-closed="false"])) {
38
+ @slot;
39
+ }
40
+ }
41
+
42
+ @custom-variant data-checked {
43
+ &:where([data-state="checked"]),
44
+ &:where([data-checked]:not([data-checked="false"])) {
45
+ @slot;
46
+ }
47
+ }
48
+
49
+ @custom-variant data-unchecked {
50
+ &:where([data-state="unchecked"]),
51
+ &:where([data-unchecked]:not([data-unchecked="false"])) {
52
+ @slot;
53
+ }
54
+ }
55
+
56
+ @custom-variant data-selected {
57
+ &:where([data-selected="true"]) {
58
+ @slot;
59
+ }
60
+ }
61
+
62
+ @custom-variant data-disabled {
63
+ &:where([data-disabled="true"]),
64
+ &:where([data-disabled]:not([data-disabled="false"])) {
65
+ @slot;
66
+ }
67
+ }
68
+
69
+ @custom-variant data-active {
70
+ &:where([data-state="active"]),
71
+ &:where([data-active]:not([data-active="false"])) {
72
+ @slot;
73
+ }
74
+ }
75
+
76
+ @custom-variant data-horizontal {
77
+ &:where([data-orientation="horizontal"]) {
78
+ @slot;
79
+ }
80
+ }
81
+
82
+ @custom-variant data-vertical {
83
+ &:where([data-orientation="vertical"]) {
84
+ @slot;
85
+ }
86
+ }
87
+
88
+ @utility no-scrollbar {
89
+ -ms-overflow-style: none;
90
+ scrollbar-width: none;
91
+
92
+ &::-webkit-scrollbar {
93
+ display: none;
94
+ }
95
+ }
@@ -0,0 +1 @@
1
+ @property --tw-animation-delay{syntax:"*";inherits:false;initial-value:0s}@property --tw-animation-direction{syntax:"*";inherits:false;initial-value:normal}@property --tw-animation-duration{syntax:"*";inherits:false}@property --tw-animation-fill-mode{syntax:"*";inherits:false;initial-value:none}@property --tw-animation-iteration-count{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-translate-y{syntax:"*";inherits:false;initial-value:0}@theme inline{--animation-delay-0: 0s; --animation-delay-75: 75ms; --animation-delay-100: .1s; --animation-delay-150: .15s; --animation-delay-200: .2s; --animation-delay-300: .3s; --animation-delay-500: .5s; --animation-delay-700: .7s; --animation-delay-1000: 1s; --animation-repeat-0: 0; --animation-repeat-1: 1; --animation-repeat-infinite: infinite; --animation-direction-normal: normal; --animation-direction-reverse: reverse; --animation-direction-alternate: alternate; --animation-direction-alternate-reverse: alternate-reverse; --animation-fill-mode-none: none; --animation-fill-mode-forwards: forwards; --animation-fill-mode-backwards: backwards; --animation-fill-mode-both: both; --percentage-0: 0; --percentage-5: .05; --percentage-10: .1; --percentage-15: .15; --percentage-20: .2; --percentage-25: .25; --percentage-30: .3; --percentage-35: .35; --percentage-40: .4; --percentage-45: .45; --percentage-50: .5; --percentage-55: .55; --percentage-60: .6; --percentage-65: .65; --percentage-70: .7; --percentage-75: .75; --percentage-80: .8; --percentage-85: .85; --percentage-90: .9; --percentage-95: .95; --percentage-100: 1; --percentage-translate-full: 1; --animate-in: enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none); --animate-out: exit var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none); @keyframes enter { from { opacity: var(--tw-enter-opacity,1); transform: translate3d(var(--tw-enter-translate-x,0),var(--tw-enter-translate-y,0),0)scale3d(var(--tw-enter-scale,1),var(--tw-enter-scale,1),var(--tw-enter-scale,1))rotate(var(--tw-enter-rotate,0)); filter: blur(var(--tw-enter-blur,0)); }}@keyframes exit { to { opacity: var(--tw-exit-opacity,1); transform: translate3d(var(--tw-exit-translate-x,0),var(--tw-exit-translate-y,0),0)scale3d(var(--tw-exit-scale,1),var(--tw-exit-scale,1),var(--tw-exit-scale,1))rotate(var(--tw-exit-rotate,0)); filter: blur(var(--tw-exit-blur,0)); }}--animate-accordion-down: accordion-down var(--tw-animation-duration,var(--tw-duration,.2s))var(--tw-ease,ease-out)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none); --animate-accordion-up: accordion-up var(--tw-animation-duration,var(--tw-duration,.2s))var(--tw-ease,ease-out)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none); --animate-collapsible-down: collapsible-down var(--tw-animation-duration,var(--tw-duration,.2s))var(--tw-ease,ease-out)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none); --animate-collapsible-up: collapsible-up var(--tw-animation-duration,var(--tw-duration,.2s))var(--tw-ease,ease-out)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none); @keyframes accordion-down { from { height: 0; }to { height: var(--radix-accordion-content-height,var(--bits-accordion-content-height,var(--reka-accordion-content-height,var(--kb-accordion-content-height,var(--ngp-accordion-content-height,auto))))); }}@keyframes accordion-up { from { height: var(--radix-accordion-content-height,var(--bits-accordion-content-height,var(--reka-accordion-content-height,var(--kb-accordion-content-height,var(--ngp-accordion-content-height,auto))))); }to { height: 0; }}@keyframes collapsible-down { from { height: 0; }to { height: var(--radix-collapsible-content-height,var(--bits-collapsible-content-height,var(--reka-collapsible-content-height,var(--kb-collapsible-content-height,auto)))); }}@keyframes collapsible-up { from { height: var(--radix-collapsible-content-height,var(--bits-collapsible-content-height,var(--reka-collapsible-content-height,var(--kb-collapsible-content-height,auto)))); }to { height: 0; }}--animate-caret-blink: caret-blink 1.25s ease-out infinite; @keyframes caret-blink { 0%,70%,100% { opacity: 1; }20%,50% { opacity: 0; }}}@utility animation-duration-*{--tw-animation-duration: calc(--value(number)*1ms); --tw-animation-duration: --value(--animation-duration-*,[duration],"initial",[*]); animation-duration: calc(--value(number)*1ms); animation-duration: --value(--animation-duration-*,[duration],"initial",[*]);}@utility delay-*{animation-delay: calc(--value(number)*1ms); animation-delay: --value(--animation-delay-*,[duration],"initial",[*]); --tw-animation-delay: calc(--value(number)*1ms); --tw-animation-delay: --value(--animation-delay-*,[duration],"initial",[*]);}@utility repeat-*{animation-iteration-count: --value(--animation-repeat-*,number,"initial",[*]); --tw-animation-iteration-count: --value(--animation-repeat-*,number,"initial",[*]);}@utility direction-*{animation-direction: --value(--animation-direction-*,"initial",[*]); --tw-animation-direction: --value(--animation-direction-*,"initial",[*]);}@utility fill-mode-*{animation-fill-mode: --value(--animation-fill-mode-*,"initial",[*]); --tw-animation-fill-mode: --value(--animation-fill-mode-*,"initial",[*]);}@utility running{animation-play-state: running;}@utility paused{animation-play-state: paused;}@utility play-state-*{animation-play-state: --value("initial",[*]);}@utility blur-in{--tw-enter-blur: 20px;}@utility blur-in-*{--tw-enter-blur: calc(--value(number)*1px); --tw-enter-blur: --value(--blur-*,[*]);}@utility blur-out{--tw-exit-blur: 20px;}@utility blur-out-*{--tw-exit-blur: calc(--value(number)*1px); --tw-exit-blur: --value(--blur-*,[*]);}@utility fade-in{--tw-enter-opacity: 0;}@utility fade-in-*{--tw-enter-opacity: calc(--value(number)/100); --tw-enter-opacity: --value(--percentage-*,[*]);}@utility fade-out{--tw-exit-opacity: 0;}@utility fade-out-*{--tw-exit-opacity: calc(--value(number)/100); --tw-exit-opacity: --value(--percentage-*,[*]);}@utility zoom-in{--tw-enter-scale: 0;}@utility zoom-in-*{--tw-enter-scale: calc(--value(number)*1%); --tw-enter-scale: calc(--value(ratio)); --tw-enter-scale: --value(--percentage-*,[*]);}@utility -zoom-in-*{--tw-enter-scale: calc(--value(number)*-1%); --tw-enter-scale: calc(--value(ratio)*-1); --tw-enter-scale: --value(--percentage-*,[*]);}@utility zoom-out{--tw-exit-scale: 0;}@utility zoom-out-*{--tw-exit-scale: calc(--value(number)*1%); --tw-exit-scale: calc(--value(ratio)); --tw-exit-scale: --value(--percentage-*,[*]);}@utility -zoom-out-*{--tw-exit-scale: calc(--value(number)*-1%); --tw-exit-scale: calc(--value(ratio)*-1); --tw-exit-scale: --value(--percentage-*,[*]);}@utility spin-in{--tw-enter-rotate: 30deg;}@utility spin-in-*{--tw-enter-rotate: calc(--value(number)*1deg); --tw-enter-rotate: calc(--value(ratio)*360deg); --tw-enter-rotate: --value(--rotate-*,[*]);}@utility -spin-in{--tw-enter-rotate: -30deg;}@utility -spin-in-*{--tw-enter-rotate: calc(--value(number)*-1deg); --tw-enter-rotate: calc(--value(ratio)*-360deg); --tw-enter-rotate: --value(--rotate-*,[*]);}@utility spin-out{--tw-exit-rotate: 30deg;}@utility spin-out-*{--tw-exit-rotate: calc(--value(number)*1deg); --tw-exit-rotate: calc(--value(ratio)*360deg); --tw-exit-rotate: --value(--rotate-*,[*]);}@utility -spin-out{--tw-exit-rotate: -30deg;}@utility -spin-out-*{--tw-exit-rotate: calc(--value(number)*-1deg); --tw-exit-rotate: calc(--value(ratio)*-360deg); --tw-exit-rotate: --value(--rotate-*,[*]);}@utility slide-in-from-top{--tw-enter-translate-y: -100%;}@utility slide-in-from-top-*{--tw-enter-translate-y: calc(--value(integer)*var(--spacing)*-1); --tw-enter-translate-y: calc(--value(--percentage-*,--percentage-translate-*)*-100%); --tw-enter-translate-y: calc(--value(ratio)*-100%); --tw-enter-translate-y: calc(--value(--translate-*,[percentage],[length])*-1);}@utility slide-in-from-bottom{--tw-enter-translate-y: 100%;}@utility slide-in-from-bottom-*{--tw-enter-translate-y: calc(--value(integer)*var(--spacing)); --tw-enter-translate-y: calc(--value(--percentage-*,--percentage-translate-*)*100%); --tw-enter-translate-y: calc(--value(ratio)*100%); --tw-enter-translate-y: --value(--translate-*,[percentage],[length]);}@utility slide-in-from-left{--tw-enter-translate-x: -100%;}@utility slide-in-from-left-*{--tw-enter-translate-x: calc(--value(integer)*var(--spacing)*-1); --tw-enter-translate-x: calc(--value(--percentage-*,--percentage-translate-*)*-100%); --tw-enter-translate-x: calc(--value(ratio)*-100%); --tw-enter-translate-x: calc(--value(--translate-*,[percentage],[length])*-1);}@utility slide-in-from-right{--tw-enter-translate-x: 100%;}@utility slide-in-from-right-*{--tw-enter-translate-x: calc(--value(integer)*var(--spacing)); --tw-enter-translate-x: calc(--value(--percentage-*,--percentage-translate-*)*100%); --tw-enter-translate-x: calc(--value(ratio)*100%); --tw-enter-translate-x: --value(--translate-*,[percentage],[length]);}@utility slide-in-from-start{&:dir(ltr){ --tw-enter-translate-x: -100%; }&:dir(rtl){ --tw-enter-translate-x: 100%; }}@utility slide-in-from-start-*{&:where(:dir(ltr),[dir="ltr"],[dir="ltr"]*){ --tw-enter-translate-x: calc(--value(integer)*var(--spacing)*-1); --tw-enter-translate-x: calc(--value(--percentage-*,--percentage-translate-*)*-100%); --tw-enter-translate-x: calc(--value(ratio)*-100%); --tw-enter-translate-x: calc(--value(--translate-*,[percentage],[length])*-1); }&:where(:dir(rtl),[dir="rtl"],[dir="rtl"]*){ --tw-enter-translate-x: calc(--value(integer)*var(--spacing)); --tw-enter-translate-x: calc(--value(--percentage-*,--percentage-translate-*)*100%); --tw-enter-translate-x: calc(--value(ratio)*100%); --tw-enter-translate-x: --value(--translate-*,[percentage],[length]); }}@utility slide-in-from-end{&:dir(ltr){ --tw-enter-translate-x: 100%; }&:dir(rtl){ --tw-enter-translate-x: -100%; }}@utility slide-in-from-end-*{&:where(:dir(ltr),[dir="ltr"],[dir="ltr"]*){ --tw-enter-translate-x: calc(--value(integer)*var(--spacing)); --tw-enter-translate-x: calc(--value(--percentage-*,--percentage-translate-*)*100%); --tw-enter-translate-x: calc(--value(ratio)*100%); --tw-enter-translate-x: --value(--translate-*,[percentage],[length]); }&:where(:dir(rtl),[dir="rtl"],[dir="rtl"]*){ --tw-enter-translate-x: calc(--value(integer)*var(--spacing)*-1); --tw-enter-translate-x: calc(--value(--percentage-*,--percentage-translate-*)*-100%); --tw-enter-translate-x: calc(--value(ratio)*-100%); --tw-enter-translate-x: calc(--value(--translate-*,[percentage],[length])*-1); }}@utility slide-out-to-top{--tw-exit-translate-y: -100%;}@utility slide-out-to-top-*{--tw-exit-translate-y: calc(--value(integer)*var(--spacing)*-1); --tw-exit-translate-y: calc(--value(--percentage-*,--percentage-translate-*)*-100%); --tw-exit-translate-y: calc(--value(ratio)*-100%); --tw-exit-translate-y: calc(--value(--translate-*,[percentage],[length])*-1);}@utility slide-out-to-bottom{--tw-exit-translate-y: 100%;}@utility slide-out-to-bottom-*{--tw-exit-translate-y: calc(--value(integer)*var(--spacing)); --tw-exit-translate-y: calc(--value(--percentage-*,--percentage-translate-*)*100%); --tw-exit-translate-y: calc(--value(ratio)*100%); --tw-exit-translate-y: --value(--translate-*,[percentage],[length]);}@utility slide-out-to-left{--tw-exit-translate-x: -100%;}@utility slide-out-to-left-*{--tw-exit-translate-x: calc(--value(integer)*var(--spacing)*-1); --tw-exit-translate-x: calc(--value(--percentage-*,--percentage-translate-*)*-100%); --tw-exit-translate-x: calc(--value(ratio)*-100%); --tw-exit-translate-x: calc(--value(--translate-*,[percentage],[length])*-1);}@utility slide-out-to-right{--tw-exit-translate-x: 100%;}@utility slide-out-to-right-*{--tw-exit-translate-x: calc(--value(integer)*var(--spacing)); --tw-exit-translate-x: calc(--value(--percentage-*,--percentage-translate-*)*100%); --tw-exit-translate-x: calc(--value(ratio)*100%); --tw-exit-translate-x: --value(--translate-*,[percentage],[length]);}@utility slide-out-to-start{&:dir(ltr){ --tw-exit-translate-x: -100%; }&:dir(rtl){ --tw-exit-translate-x: 100%; }}@utility slide-out-to-start-*{&:where(:dir(ltr),[dir="ltr"],[dir="ltr"]*){ --tw-exit-translate-x: calc(--value(integer)*var(--spacing)*-1); --tw-exit-translate-x: calc(--value(--percentage-*,--percentage-translate-*)*-100%); --tw-exit-translate-x: calc(--value(ratio)*-100%); --tw-exit-translate-x: calc(--value(--translate-*,[percentage],[length])*-1); }&:where(:dir(rtl),[dir="rtl"],[dir="rtl"]*){ --tw-exit-translate-x: calc(--value(integer)*var(--spacing)); --tw-exit-translate-x: calc(--value(--percentage-*,--percentage-translate-*)*100%); --tw-exit-translate-x: calc(--value(ratio)*100%); --tw-exit-translate-x: --value(--translate-*,[percentage],[length]); }}@utility slide-out-to-end{&:dir(ltr){ --tw-exit-translate-x: 100%; }&:dir(rtl){ --tw-exit-translate-x: -100%; }}@utility slide-out-to-end-*{&:where(:dir(ltr),[dir="ltr"],[dir="ltr"]*){ --tw-exit-translate-x: calc(--value(integer)*var(--spacing)); --tw-exit-translate-x: calc(--value(--percentage-*,--percentage-translate-*)*100%); --tw-exit-translate-x: calc(--value(ratio)*100%); --tw-exit-translate-x: --value(--translate-*,[percentage],[length]); }&:where(:dir(rtl),[dir="rtl"],[dir="rtl"]*){ --tw-exit-translate-x: calc(--value(integer)*var(--spacing)*-1); --tw-exit-translate-x: calc(--value(--percentage-*,--percentage-translate-*)*-100%); --tw-exit-translate-x: calc(--value(ratio)*-100%); --tw-exit-translate-x: calc(--value(--translate-*,[percentage],[length])*-1); }}