refactor: refactor webui

This commit is contained in:
master 2025-04-26 01:43:23 +08:00
parent b20f7cd1ad
commit ee1b1ae5e6
104 changed files with 934 additions and 827 deletions

View File

@ -10,11 +10,11 @@
"cssVariables": true "cssVariables": true
}, },
"aliases": { "aliases": {
"components": "@/components", "components": "@/views/components",
"utils": "@/infra/styles/utils", "utils": "@/views/utils",
"ui": "@/components/ui", "ui": "@/views/components/ui",
"lib": "@/lib", "lib": "@/views/lib",
"hooks": "@/infra/hooks" "hooks": "@/views/hooks"
}, },
"iconLibrary": "lucide" "iconLibrary": "lucide"
} }

View File

@ -18,32 +18,32 @@
"@graphiql/toolkit": "^0.11.1", "@graphiql/toolkit": "^0.11.1",
"@hookform/resolvers": "^5.0.1", "@hookform/resolvers": "^5.0.1",
"@outposts/injection-js": "^2.5.1", "@outposts/injection-js": "^2.5.1",
"@radix-ui/react-accordion": "^1.2.7", "@radix-ui/react-accordion": "^1.2.10",
"@radix-ui/react-alert-dialog": "^1.1.10", "@radix-ui/react-alert-dialog": "^1.1.13",
"@radix-ui/react-aspect-ratio": "^1.1.4", "@radix-ui/react-aspect-ratio": "^1.1.6",
"@radix-ui/react-avatar": "^1.1.6", "@radix-ui/react-avatar": "^1.1.9",
"@radix-ui/react-checkbox": "^1.2.2", "@radix-ui/react-checkbox": "^1.3.1",
"@radix-ui/react-collapsible": "^1.1.7", "@radix-ui/react-collapsible": "^1.1.10",
"@radix-ui/react-context-menu": "^2.2.11", "@radix-ui/react-context-menu": "^2.2.14",
"@radix-ui/react-dialog": "^1.1.10", "@radix-ui/react-dialog": "^1.1.13",
"@radix-ui/react-dropdown-menu": "^2.1.11", "@radix-ui/react-dropdown-menu": "^2.1.14",
"@radix-ui/react-hover-card": "^1.1.10", "@radix-ui/react-hover-card": "^1.1.13",
"@radix-ui/react-label": "^2.1.4", "@radix-ui/react-label": "^2.1.6",
"@radix-ui/react-menubar": "^1.1.11", "@radix-ui/react-menubar": "^1.1.14",
"@radix-ui/react-navigation-menu": "^1.2.9", "@radix-ui/react-navigation-menu": "^1.2.12",
"@radix-ui/react-popover": "^1.1.10", "@radix-ui/react-popover": "^1.1.13",
"@radix-ui/react-progress": "^1.1.4", "@radix-ui/react-progress": "^1.1.6",
"@radix-ui/react-radio-group": "^1.3.3", "@radix-ui/react-radio-group": "^1.3.6",
"@radix-ui/react-scroll-area": "^1.2.5", "@radix-ui/react-scroll-area": "^1.2.8",
"@radix-ui/react-select": "^2.2.2", "@radix-ui/react-select": "^2.2.4",
"@radix-ui/react-separator": "^1.1.4", "@radix-ui/react-separator": "^1.1.6",
"@radix-ui/react-slider": "^1.3.2", "@radix-ui/react-slider": "^1.3.4",
"@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-slot": "^1.2.2",
"@radix-ui/react-switch": "^1.2.2", "@radix-ui/react-switch": "^1.2.4",
"@radix-ui/react-tabs": "^1.1.8", "@radix-ui/react-tabs": "^1.1.11",
"@radix-ui/react-toggle": "^1.1.6", "@radix-ui/react-toggle": "^1.1.8",
"@radix-ui/react-toggle-group": "^1.1.7", "@radix-ui/react-toggle-group": "^1.1.9",
"@radix-ui/react-tooltip": "^1.2.3", "@radix-ui/react-tooltip": "^1.2.6",
"@rsbuild/plugin-react": "^1.2.0", "@rsbuild/plugin-react": "^1.2.0",
"@tanstack/react-router": "^1.112.13", "@tanstack/react-router": "^1.112.13",
"@tanstack/router-devtools": "^1.112.13", "@tanstack/router-devtools": "^1.112.13",
@ -63,10 +63,10 @@
"next-themes": "^0.4.6", "next-themes": "^0.4.6",
"oidc-client-rx": "0.1.0-alpha.9", "oidc-client-rx": "0.1.0-alpha.9",
"react": "^19.1.0", "react": "^19.1.0",
"react-day-picker": "9.6.7", "react-day-picker": "8.10.1",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-hook-form": "^7.56.0", "react-hook-form": "^7.56.3",
"react-resizable-panels": "^3.0.0", "react-resizable-panels": "^3.0.1",
"recharts": "^2.15.3", "recharts": "^2.15.3",
"rxjs": "^7.8.2", "rxjs": "^7.8.2",
"sonner": "^2.0.3", "sonner": "^2.0.3",
@ -74,7 +74,8 @@
"tailwindcss": "^4.0.6", "tailwindcss": "^4.0.6",
"tw-animate-css": "^1.2.7", "tw-animate-css": "^1.2.7",
"type-fest": "^4.40.0", "type-fest": "^4.40.0",
"vaul": "^1.1.2" "vaul": "^1.1.2",
"zod": "^3.24.4"
}, },
"devDependencies": { "devDependencies": {
"@rsbuild/core": "^1.2.15", "@rsbuild/core": "^1.2.15",

View File

@ -1,4 +1,13 @@
import { AuthService } from '@/domains/auth/auth.service'; import { AuthService } from '@/domains/auth/auth.service';
import { AUTH_PROVIDER, type AuthProvider } from '@/infra/auth/auth.provider';
import { BasicAuthProvider } from '@/infra/auth/basic';
import {
AUTH_METHOD,
type AuthMethodType,
getAppAuthMethod,
} from '@/infra/auth/defs';
import { OidcAuthProvider, buildOidcConfig } from '@/infra/auth/oidc';
import { UnreachableError } from '@/infra/errors/common';
import type { Injector, Provider } from '@outposts/injection-js'; import type { Injector, Provider } from '@outposts/injection-js';
import type { AnyRouter } from '@tanstack/react-router'; import type { AnyRouter } from '@tanstack/react-router';
import { import {
@ -9,16 +18,11 @@ import {
} from 'oidc-client-rx'; } from 'oidc-client-rx';
import { withTanstackRouter } from 'oidc-client-rx/adapters/@tanstack/react-router'; import { withTanstackRouter } from 'oidc-client-rx/adapters/@tanstack/react-router';
import type { Observable } from 'rxjs'; import type { Observable } from 'rxjs';
import {
AppAuthMethod,
AuthMethodEnum,
type AuthMethodType,
buildOidcConfig,
} from './config';
export function provideAuth(router: AnyRouter): Provider[] { export function provideAuth(router: AnyRouter): Provider[] {
const providers: Provider[] = [AuthService]; const providers: Provider[] = [AuthService];
if (AppAuthMethod === AuthMethodEnum.OIDC) { const appAuthMethod = getAppAuthMethod();
if (appAuthMethod === AUTH_METHOD.OIDC) {
providers.push( providers.push(
...provideOidcAuth( ...provideOidcAuth(
{ {
@ -32,18 +36,25 @@ export function provideAuth(router: AnyRouter): Provider[] {
withCheckAuthResultEvent() withCheckAuthResultEvent()
) )
); );
providers.push({
provide: AUTH_PROVIDER,
useClass: OidcAuthProvider,
});
} else if (appAuthMethod === AUTH_METHOD.BASIC) {
providers.push({
provide: AUTH_PROVIDER,
useClass: BasicAuthProvider,
});
} else {
throw new UnreachableError(`Unsupported auth method: ${appAuthMethod}`);
} }
return providers; return providers;
} }
export function setupAuthContext(injector: Injector) {
const { authService } = authContextFromInjector(injector);
authService.setup();
}
export interface AuthContext { export interface AuthContext {
type: AuthMethodType; type: AuthMethodType;
authService: AuthService; authService: AuthService;
authProvider: AuthProvider;
isAuthenticated$: Observable<boolean>; isAuthenticated$: Observable<boolean>;
userData$: Observable<{}>; userData$: Observable<{}>;
checkAuthResultEvent$: Observable<CheckAuthResultEventType>; checkAuthResultEvent$: Observable<CheckAuthResultEventType>;
@ -51,11 +62,18 @@ export interface AuthContext {
export function authContextFromInjector(injector: Injector): AuthContext { export function authContextFromInjector(injector: Injector): AuthContext {
const authService = injector.get(AuthService); const authService = injector.get(AuthService);
const authProvider = injector.get(AUTH_PROVIDER);
return { return {
type: AppAuthMethod, type: authProvider.authMethod,
authService,
isAuthenticated$: authService.isAuthenticated$, isAuthenticated$: authService.isAuthenticated$,
userData$: authService.userData$, userData$: authService.userData$,
checkAuthResultEvent$: authService.checkAuthResultEvent$, checkAuthResultEvent$: authService.checkAuthResultEvent$,
authService,
authProvider,
}; };
} }
export function setupAuthContext(injector: Injector) {
const { authService } = authContextFromInjector(injector);
authService.setup();
}

View File

@ -1,19 +1,17 @@
import type { RouterContext } from '@/infra/routes/traits'; import type { RouterContext } from '@/infra/routes/traits';
import { runInInjectionContext } from '@outposts/injection-js';
import { autoLoginPartialRoutesGuard } from 'oidc-client-rx';
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { authContextFromInjector } from './context'; import { authContextFromInjector } from './context';
export const beforeLoadGuard = async ({ export const beforeLoadGuard = async ({
context, context,
}: { context: RouterContext }) => { }: { context: RouterContext }) => {
const { isAuthenticated$ } = authContextFromInjector(context.injector); const { isAuthenticated$, authProvider } = authContextFromInjector(
context.injector
);
if (!(await firstValueFrom(isAuthenticated$))) { if (!(await firstValueFrom(isAuthenticated$))) {
const guard$ = runInInjectionContext(context.injector, () => const isAuthenticated = await firstValueFrom(
autoLoginPartialRoutesGuard() authProvider.autoLoginPartialRoutesGuard()
); );
const isAuthenticated = await firstValueFrom(guard$);
if (!isAuthenticated) { if (!isAuthenticated) {
throw !isAuthenticated; throw !isAuthenticated;
} }

View File

@ -26,9 +26,9 @@ export function useAuth() {
); );
return { return {
...authContext,
userData, userData,
injector, injector,
isAuthenticated, isAuthenticated,
authContext,
}; };
} }

View File

@ -1,53 +1,15 @@
import { AppAuthMethod, AuthMethodEnum } from '@/app/auth/config'; import { AUTH_PROVIDER } from '@/infra/auth/auth.provider';
import { injectInjector } from '@/infra/di/inject'; import { Injectable, inject } from '@outposts/injection-js';
import { Injectable, type Injector } from '@outposts/injection-js';
import {
CHECK_AUTH_RESULT_EVENT,
type CheckAuthResultEventType,
OidcSecurityService,
} from 'oidc-client-rx';
import { NEVER, type Observable, map, of } from 'rxjs';
const BASIC_AUTH_IS_AUTHENTICATED$ = of(true) as Observable<true>;
const BASIC_AUTH_USER_DATA$ = of({});
@Injectable() @Injectable()
export class AuthService { export class AuthService {
private injector: Injector = injectInjector(); private authProvider = inject(AUTH_PROVIDER);
oidcSecurityService: OidcSecurityService | undefined;
checkAuthResultEvent$: Observable<CheckAuthResultEventType>; isAuthenticated$ = this.authProvider.isAuthenticated$;
constructor() { userData$ = this.authProvider.userData$;
if (AppAuthMethod === 'oidc') { checkAuthResultEvent$ = this.authProvider.checkAuthResultEvent$;
this.oidcSecurityService = this.injector.get(OidcSecurityService);
this.checkAuthResultEvent$ = this.injector.get(CHECK_AUTH_RESULT_EVENT);
} else {
this.checkAuthResultEvent$ = NEVER;
}
}
setup() { setup() {
if (AppAuthMethod === AuthMethodEnum.OIDC) { this.authProvider.setup();
this.oidcSecurityService!.checkAuth().subscribe();
}
}
get isAuthenticated$() {
return (
this.oidcSecurityService?.isAuthenticated$.pipe(
map((s) => s.isAuthenticated)
) ?? BASIC_AUTH_IS_AUTHENTICATED$
);
}
get userData$() {
return (
this.oidcSecurityService?.userData$?.pipe(map((s) => s.userData)) ??
BASIC_AUTH_USER_DATA$
);
}
getAccessToken(): Observable<string | undefined> {
return this.oidcSecurityService?.getAccessToken() ?? of(undefined);
} }
} }

View File

@ -0,0 +1,27 @@
import { InjectionToken } from '@outposts/injection-js';
import type { CheckAuthResultEventType } from 'oidc-client-rx';
import { type Observable, map } from 'rxjs';
import type { AuthMethodType } from './defs';
export abstract class AuthProvider {
abstract authMethod: AuthMethodType;
abstract checkAuthResultEvent$: Observable<CheckAuthResultEventType>;
abstract isAuthenticated$: Observable<boolean>;
abstract userData$: Observable<any>;
abstract getAccessToken(): Observable<string | undefined>;
abstract setup(): void;
abstract autoLoginPartialRoutesGuard(): Observable<boolean>;
getAuthHeaders(): Observable<Record<string, string>> {
return this.getAccessToken().pipe(
map((accessToken) =>
accessToken
? {
Authorization: `Bearer ${accessToken}`,
}
: ({} as Record<string, string>)
)
);
}
}
export const AUTH_PROVIDER = new InjectionToken<AuthProvider>('AUTH_PROVIDER');

View File

@ -0,0 +1,22 @@
import { UnreachableError } from '@/infra/errors/common';
import type { CheckAuthResultEventType } from 'oidc-client-rx';
import { NEVER, type Observable, of } from 'rxjs';
import { AuthProvider } from '../auth.provider';
import { AUTH_METHOD } from '../defs';
export class BasicAuthProvider extends AuthProvider {
authMethod = AUTH_METHOD.BASIC;
isAuthenticated$ = of(true);
userData$ = of({});
checkAuthResultEvent$: Observable<CheckAuthResultEventType> = NEVER;
getAccessToken(): Observable<string | undefined> {
return of(undefined);
}
setup(): void {}
autoLoginPartialRoutesGuard(): Observable<boolean> {
throw new UnreachableError('Basic auth should always be authenticated');
}
}

View File

@ -0,0 +1 @@
export { BasicAuthProvider } from './basic-auth.provider';

View File

@ -0,0 +1,12 @@
import type { ValueOf } from 'type-fest';
export const AUTH_METHOD = {
BASIC: 'basic',
OIDC: 'oidc',
} as const;
export type AuthMethodType = ValueOf<typeof AUTH_METHOD>;
export function getAppAuthMethod(): AuthMethodType {
return process.env.AUTH_TYPE as AuthMethodType;
}

View File

@ -1,14 +1,4 @@
import { LogLevel, type OpenIdConfiguration } from 'oidc-client-rx'; import { LogLevel, type OpenIdConfiguration } from 'oidc-client-rx';
import type { ValueOf } from 'type-fest';
export const AuthMethodEnum = {
BASIC: 'basic',
OIDC: 'oidc',
} as const;
export type AuthMethodType = ValueOf<typeof AuthMethodEnum>;
export const AppAuthMethod = process.env.AUTH_TYPE as AuthMethodType;
export function buildOidcConfig(): OpenIdConfiguration { export function buildOidcConfig(): OpenIdConfiguration {
const origin = window.location.origin; const origin = window.location.origin;

View File

@ -0,0 +1,2 @@
export { buildOidcConfig } from './config';
export { OidcAuthProvider } from './oidc-auth.provider';

View File

@ -0,0 +1,41 @@
import { injectInjector } from '@/infra/di/inject';
import { inject, runInInjectionContext } from '@outposts/injection-js';
import {
CHECK_AUTH_RESULT_EVENT,
OidcSecurityService,
autoLoginPartialRoutesGuard,
} from 'oidc-client-rx';
import { type Observable, map } from 'rxjs';
import { AuthProvider } from '../auth.provider';
import { AUTH_METHOD } from '../defs';
export class OidcAuthProvider extends AuthProvider {
authMethod = AUTH_METHOD.OIDC;
oidcSecurityService = inject(OidcSecurityService);
checkAuthResultEvent$ = inject(CHECK_AUTH_RESULT_EVENT);
injector = injectInjector();
setup() {
this.oidcSecurityService.checkAuth().subscribe();
}
get isAuthenticated$() {
return this.oidcSecurityService.isAuthenticated$.pipe(
map((s) => s.isAuthenticated)
);
}
get userData$() {
return this.oidcSecurityService.userData$.pipe(map((s) => s.userData));
}
getAccessToken(): Observable<string | undefined> {
return this.oidcSecurityService.getAccessToken();
}
autoLoginPartialRoutesGuard() {
return runInInjectionContext(this.injector, () =>
autoLoginPartialRoutesGuard()
);
}
}

View File

@ -0,0 +1,16 @@
import type { Injector, Provider } from '@outposts/injection-js';
import { GraphQLService } from './graphql.service';
export function provideGraphql(): Provider[] {
return [GraphQLService];
}
export interface GraphQLContext {
graphqlService: GraphQLService;
}
export function graphqlContextFromInjector(injector: Injector): GraphQLContext {
return {
graphqlService: injector.get(GraphQLService),
};
}

View File

@ -0,0 +1,30 @@
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import { Injectable, inject } from '@outposts/injection-js';
import { firstValueFrom } from 'rxjs';
import { AUTH_PROVIDER } from '../auth/auth.provider.ts';
@Injectable()
export class GraphQLService {
private authProvider = inject(AUTH_PROVIDER);
private apiLink = createHttpLink({
uri: '/api/graphql',
});
private authLink = setContext(async (_, { headers }) => {
const authHeaders = await firstValueFrom(
this.authProvider.getAuthHeaders()
);
return { headers: { ...headers, ...authHeaders } };
});
_apollo = new ApolloClient({
link: this.authLink.concat(this.apiLink),
cache: new InMemoryCache(),
});
query = this._apollo.query;
mutate = this._apollo.mutate;
watchQuery = this._apollo.watchQuery;
}

View File

@ -0,0 +1,2 @@
export { GraphQLService } from './graphql.service';
export { provideGraphql } from './context';

View File

@ -1,21 +0,0 @@
import React from 'react';
const MOBILE_BREAKPOINT = 768;
export function useIsMobile() {
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(
undefined
);
React.useEffect(() => {
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
const onChange = () => {
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
};
mql.addEventListener('change', onChange);
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
return () => mql.removeEventListener('change', onChange);
}, []);
return !!isMobile;
}

View File

@ -1,7 +0,0 @@
import { Injectable, inject } from '@outposts/injection-js';
import { OidcSecurityService } from 'oidc-client-rx';
@Injectable()
export class HttpService {
authService = inject(OidcSecurityService);
}

View File

@ -1,4 +1,4 @@
import type { ProLinkProps } from '@/components/ui/pro-link'; import type { ProLinkProps } from '@/views/components/ui/pro-link';
import type { Injector } from '@outposts/injection-js'; import type { Injector } from '@outposts/injection-js';
import type { LucideIcon } from 'lucide-react'; import type { LucideIcon } from 'lucide-react';

View File

@ -1,5 +1,5 @@
import { guardRouteIndexAsNotFound } from '@/components/layout/app-not-found';
import type { RouteStateDataOption } from '@/infra/routes/traits'; import type { RouteStateDataOption } from '@/infra/routes/traits';
import { guardRouteIndexAsNotFound } from '@/views/components/layout/app-not-found';
import { Outlet } from '@tanstack/react-router'; import { Outlet } from '@tanstack/react-router';
export interface BuildVirtualBranchRouteOptions { export interface BuildVirtualBranchRouteOptions {

View File

@ -3,6 +3,8 @@ import { provideAuth, setupAuthContext } from '@/app/auth/context';
import { providePlatform } from '@/infra/platform/context'; import { providePlatform } from '@/infra/platform/context';
import { provideStorages } from '@/infra/storage/context'; import { provideStorages } from '@/infra/storage/context';
import { provideStyles } from '@/infra/styles/context'; import { provideStyles } from '@/infra/styles/context';
import { AppNotFoundComponent } from '@/views/components/layout/app-not-found';
import { routeTree } from '@/views/routeTree.gen';
import { type Injector, ReflectiveInjector } from '@outposts/injection-js'; import { type Injector, ReflectiveInjector } from '@outposts/injection-js';
import { RouterProvider, createRouter } from '@tanstack/react-router'; import { RouterProvider, createRouter } from '@tanstack/react-router';
import { import {
@ -11,9 +13,10 @@ import {
} from 'oidc-client-rx/adapters/react'; } from 'oidc-client-rx/adapters/react';
import { Suspense } from 'react'; import { Suspense } from 'react';
import { createRoot } from 'react-dom/client'; import { createRoot } from 'react-dom/client';
import { AppNotFoundComponent } from './components/layout/app-not-found';
import { routeTree } from './routeTree.gen';
import './app.css'; import './app.css';
import { ApolloProvider } from '@apollo/client';
import { provideGraphql } from './infra/graphql';
import { graphqlContextFromInjector } from './infra/graphql/context';
// Create a new router instance // Create a new router instance
const router = createRouter({ const router = createRouter({
@ -40,22 +43,27 @@ const injector: Injector = ReflectiveInjector.resolveAndCreate([
...provideStorages(), ...provideStorages(),
...provideAuth(router), ...provideAuth(router),
...provideStyles(), ...provideStyles(),
...provideGraphql(),
]); ]);
setupAuthContext(injector); setupAuthContext(injector);
const rootElement = document.getElementById('root'); const rootElement = document.getElementById('root');
const { graphqlService } = graphqlContextFromInjector(injector);
const App = () => { const App = () => {
return ( return (
<InjectorProvider injector={injector}> <InjectorProvider injector={injector}>
<Suspense> <Suspense>
<RouterProvider <ApolloProvider client={graphqlService._apollo}>
router={router} <RouterProvider
context={{ router={router}
injector, context={{
}} injector,
/> }}
/>
</ApolloProvider>
</Suspense> </Suspense>
</InjectorProvider> </InjectorProvider>
); );

View File

@ -2,9 +2,9 @@ import {
SidebarMenu, SidebarMenu,
SidebarMenuButton, SidebarMenuButton,
SidebarMenuItem, SidebarMenuItem,
} from '@/components/ui/sidebar'; } from '@/views/components/ui/sidebar';
import { Image } from '@/components/ui/image'; import { Image } from '@/views/components/ui/image';
export function AppIcon() { export function AppIcon() {
return ( return (

View File

@ -1,4 +1,6 @@
import { AppSidebar } from '@/components/layout/app-sidebar'; import type { RouteStateDataOption } from '@/infra/routes/traits';
import type { RouteBreadcrumbItem } from '@/infra/routes/traits';
import { AppSidebar } from '@/views/components/layout/app-sidebar';
import { import {
Breadcrumb, Breadcrumb,
BreadcrumbItem, BreadcrumbItem,
@ -6,16 +8,14 @@ import {
BreadcrumbList, BreadcrumbList,
BreadcrumbPage, BreadcrumbPage,
BreadcrumbSeparator, BreadcrumbSeparator,
} from '@/components/ui/breadcrumb'; } from '@/views/components/ui/breadcrumb';
import { Separator } from '@/components/ui/separator'; import { Separator } from '@/views/components/ui/separator';
import { import {
SidebarInset, SidebarInset,
SidebarProvider, SidebarProvider,
SidebarTrigger, SidebarTrigger,
} from '@/components/ui/sidebar'; } from '@/views/components/ui/sidebar';
import type { RouteStateDataOption } from '@/infra/routes/traits'; import { cn } from '@/views/utils';
import type { RouteBreadcrumbItem } from '@/infra/routes/traits';
import { cn } from '@/infra/styles/utils';
import { useMatches } from '@tanstack/react-router'; import { useMatches } from '@tanstack/react-router';
import { import {
type DetailedHTMLProps, type DetailedHTMLProps,

View File

@ -1,11 +1,11 @@
import { AppNavMainData } from '@/infra/routes/nav';
import { import {
Sidebar, Sidebar,
SidebarContent, SidebarContent,
SidebarFooter, SidebarFooter,
SidebarHeader, SidebarHeader,
SidebarRail, SidebarRail,
} from '@/components/ui/sidebar'; } from '@/views/components/ui/sidebar';
import { AppNavMainData } from '@/infra/routes/nav';
import type { ComponentPropsWithoutRef } from 'react'; import type { ComponentPropsWithoutRef } from 'react';
import { AppIcon } from './app-icon'; import { AppIcon } from './app-icon';
import { NavMain } from './nav-main'; import { NavMain } from './nav-main';

View File

@ -6,7 +6,7 @@ import {
Collapsible, Collapsible,
CollapsibleContent, CollapsibleContent,
CollapsibleTrigger, CollapsibleTrigger,
} from '@/components/ui/collapsible'; } from '@/views/components/ui/collapsible';
import { import {
SidebarGroup, SidebarGroup,
SidebarGroupLabel, SidebarGroupLabel,
@ -16,7 +16,7 @@ import {
SidebarMenuSub, SidebarMenuSub,
SidebarMenuSubButton, SidebarMenuSubButton,
SidebarMenuSubItem, SidebarMenuSubItem,
} from '@/components/ui/sidebar'; } from '@/views/components/ui/sidebar';
import { useMatches } from '@tanstack/react-router'; import { useMatches } from '@tanstack/react-router';
import { ProLink, type ProLinkProps } from '../ui/pro-link'; import { ProLink, type ProLinkProps } from '../ui/pro-link';

View File

@ -16,7 +16,7 @@ import {
DropdownMenuItem, DropdownMenuItem,
DropdownMenuSeparator, DropdownMenuSeparator,
DropdownMenuTrigger, DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'; } from '@/views/components/ui/dropdown-menu';
import { import {
SidebarGroup, SidebarGroup,
SidebarGroupLabel, SidebarGroupLabel,
@ -25,7 +25,7 @@ import {
SidebarMenuButton, SidebarMenuButton,
SidebarMenuItem, SidebarMenuItem,
useSidebar, useSidebar,
} from '@/components/ui/sidebar'; } from '@/views/components/ui/sidebar';
import type { ComponentProps } from 'react'; import type { ComponentProps } from 'react';
export function NavProjects({ export function NavProjects({

View File

@ -9,7 +9,11 @@ import {
Sparkles, Sparkles,
} from 'lucide-react'; } from 'lucide-react';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import {
Avatar,
AvatarFallback,
AvatarImage,
} from '@/views/components/ui/avatar';
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
@ -18,13 +22,13 @@ import {
DropdownMenuLabel, DropdownMenuLabel,
DropdownMenuSeparator, DropdownMenuSeparator,
DropdownMenuTrigger, DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'; } from '@/views/components/ui/dropdown-menu';
import { import {
SidebarMenu, SidebarMenu,
SidebarMenuButton, SidebarMenuButton,
SidebarMenuItem, SidebarMenuItem,
useSidebar, useSidebar,
} from '@/components/ui/sidebar'; } from '@/views/components/ui/sidebar';
export function NavUser({ export function NavUser({
user, user,

View File

@ -1,13 +1,13 @@
import * as React from "react" import * as AccordionPrimitive from "@radix-ui/react-accordion";
import * as AccordionPrimitive from "@radix-ui/react-accordion" import { ChevronDownIcon } from "lucide-react";
import { ChevronDownIcon } from "lucide-react" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Accordion({ function Accordion({
...props ...props
}: React.ComponentProps<typeof AccordionPrimitive.Root>) { }: React.ComponentProps<typeof AccordionPrimitive.Root>) {
return <AccordionPrimitive.Root data-slot="accordion" {...props} /> return <AccordionPrimitive.Root data-slot="accordion" {...props} />;
} }
function AccordionItem({ function AccordionItem({
@ -20,7 +20,7 @@ function AccordionItem({
className={cn("border-b last:border-b-0", className)} className={cn("border-b last:border-b-0", className)}
{...props} {...props}
/> />
) );
} }
function AccordionTrigger({ function AccordionTrigger({
@ -42,7 +42,7 @@ function AccordionTrigger({
<ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" /> <ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
</AccordionPrimitive.Trigger> </AccordionPrimitive.Trigger>
</AccordionPrimitive.Header> </AccordionPrimitive.Header>
) );
} }
function AccordionContent({ function AccordionContent({
@ -58,7 +58,7 @@ function AccordionContent({
> >
<div className={cn("pt-0 pb-4", className)}>{children}</div> <div className={cn("pt-0 pb-4", className)}>{children}</div>
</AccordionPrimitive.Content> </AccordionPrimitive.Content>
) );
} }
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };

View File

@ -1,15 +1,15 @@
"use client" "use client";
import * as React from "react" import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { buttonVariants } from "@/views/components/ui/button";
import { buttonVariants } from "@/components/ui/button" import { cn } from "@/views/utils";
function AlertDialog({ function AlertDialog({
...props ...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) { }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} /> return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
} }
function AlertDialogTrigger({ function AlertDialogTrigger({
@ -17,7 +17,7 @@ function AlertDialogTrigger({
}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) { }: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
return ( return (
<AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} /> <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
) );
} }
function AlertDialogPortal({ function AlertDialogPortal({
@ -25,7 +25,7 @@ function AlertDialogPortal({
}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) { }: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
return ( return (
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} /> <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
) );
} }
function AlertDialogOverlay({ function AlertDialogOverlay({
@ -41,7 +41,7 @@ function AlertDialogOverlay({
)} )}
{...props} {...props}
/> />
) );
} }
function AlertDialogContent({ function AlertDialogContent({
@ -60,7 +60,7 @@ function AlertDialogContent({
{...props} {...props}
/> />
</AlertDialogPortal> </AlertDialogPortal>
) );
} }
function AlertDialogHeader({ function AlertDialogHeader({
@ -73,7 +73,7 @@ function AlertDialogHeader({
className={cn("flex flex-col gap-2 text-center sm:text-left", className)} className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
{...props} {...props}
/> />
) );
} }
function AlertDialogFooter({ function AlertDialogFooter({
@ -89,7 +89,7 @@ function AlertDialogFooter({
)} )}
{...props} {...props}
/> />
) );
} }
function AlertDialogTitle({ function AlertDialogTitle({
@ -102,7 +102,7 @@ function AlertDialogTitle({
className={cn("text-lg font-semibold", className)} className={cn("text-lg font-semibold", className)}
{...props} {...props}
/> />
) );
} }
function AlertDialogDescription({ function AlertDialogDescription({
@ -115,7 +115,7 @@ function AlertDialogDescription({
className={cn("text-muted-foreground text-sm", className)} className={cn("text-muted-foreground text-sm", className)}
{...props} {...props}
/> />
) );
} }
function AlertDialogAction({ function AlertDialogAction({
@ -127,7 +127,7 @@ function AlertDialogAction({
className={cn(buttonVariants(), className)} className={cn(buttonVariants(), className)}
{...props} {...props}
/> />
) );
} }
function AlertDialogCancel({ function AlertDialogCancel({
@ -139,7 +139,7 @@ function AlertDialogCancel({
className={cn(buttonVariants({ variant: "outline" }), className)} className={cn(buttonVariants({ variant: "outline" }), className)}
{...props} {...props}
/> />
) );
} }
export { export {
@ -154,4 +154,4 @@ export {
AlertDialogDescription, AlertDialogDescription,
AlertDialogAction, AlertDialogAction,
AlertDialogCancel, AlertDialogCancel,
} };

View File

@ -1,7 +1,7 @@
import * as React from "react" import { type VariantProps, cva } from "class-variance-authority";
import { cva, type VariantProps } from "class-variance-authority" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
const alertVariants = cva( const alertVariants = cva(
"relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", "relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
@ -17,7 +17,7 @@ const alertVariants = cva(
variant: "default", variant: "default",
}, },
} }
) );
function Alert({ function Alert({
className, className,
@ -31,7 +31,7 @@ function Alert({
className={cn(alertVariants({ variant }), className)} className={cn(alertVariants({ variant }), className)}
{...props} {...props}
/> />
) );
} }
function AlertTitle({ className, ...props }: React.ComponentProps<"div">) { function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
@ -44,7 +44,7 @@ function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
)} )}
{...props} {...props}
/> />
) );
} }
function AlertDescription({ function AlertDescription({
@ -60,7 +60,7 @@ function AlertDescription({
)} )}
{...props} {...props}
/> />
) );
} }
export { Alert, AlertTitle, AlertDescription } export { Alert, AlertTitle, AlertDescription };

View File

@ -1,9 +1,9 @@
"use client" "use client";
import * as React from "react" import * as AvatarPrimitive from "@radix-ui/react-avatar";
import * as AvatarPrimitive from "@radix-ui/react-avatar" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Avatar({ function Avatar({
className, className,
@ -18,7 +18,7 @@ function Avatar({
)} )}
{...props} {...props}
/> />
) );
} }
function AvatarImage({ function AvatarImage({
@ -31,7 +31,7 @@ function AvatarImage({
className={cn("aspect-square size-full", className)} className={cn("aspect-square size-full", className)}
{...props} {...props}
/> />
) );
} }
function AvatarFallback({ function AvatarFallback({
@ -47,7 +47,7 @@ function AvatarFallback({
)} )}
{...props} {...props}
/> />
) );
} }
export { Avatar, AvatarImage, AvatarFallback } export { Avatar, AvatarImage, AvatarFallback };

View File

@ -1,8 +1,8 @@
import * as React from "react" import { Slot } from "@radix-ui/react-slot";
import { Slot } from "@radix-ui/react-slot" import { type VariantProps, cva } from "class-variance-authority";
import { cva, type VariantProps } from "class-variance-authority" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
const badgeVariants = cva( const badgeVariants = cva(
"inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
@ -23,7 +23,7 @@ const badgeVariants = cva(
variant: "default", variant: "default",
}, },
} }
) );
function Badge({ function Badge({
className, className,
@ -32,7 +32,7 @@ function Badge({
...props ...props
}: React.ComponentProps<"span"> & }: React.ComponentProps<"span"> &
VariantProps<typeof badgeVariants> & { asChild?: boolean }) { VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
const Comp = asChild ? Slot : "span" const Comp = asChild ? Slot : "span";
return ( return (
<Comp <Comp
@ -40,7 +40,7 @@ function Badge({
className={cn(badgeVariants({ variant }), className)} className={cn(badgeVariants({ variant }), className)}
{...props} {...props}
/> />
) );
} }
export { Badge, badgeVariants } export { Badge, badgeVariants };

View File

@ -1,11 +1,11 @@
import * as React from "react" import { Slot } from "@radix-ui/react-slot";
import { Slot } from "@radix-ui/react-slot" import { ChevronRight, MoreHorizontal } from "lucide-react";
import { ChevronRight, MoreHorizontal } from "lucide-react" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} /> return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />;
} }
function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) { function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
@ -18,7 +18,7 @@ function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
)} )}
{...props} {...props}
/> />
) );
} }
function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) { function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
@ -28,7 +28,7 @@ function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
className={cn("inline-flex items-center gap-1.5", className)} className={cn("inline-flex items-center gap-1.5", className)}
{...props} {...props}
/> />
) );
} }
function BreadcrumbLink({ function BreadcrumbLink({
@ -36,9 +36,9 @@ function BreadcrumbLink({
className, className,
...props ...props
}: React.ComponentProps<"a"> & { }: React.ComponentProps<"a"> & {
asChild?: boolean asChild?: boolean;
}) { }) {
const Comp = asChild ? Slot : "a" const Comp = asChild ? Slot : "a";
return ( return (
<Comp <Comp
@ -46,7 +46,7 @@ function BreadcrumbLink({
className={cn("hover:text-foreground transition-colors", className)} className={cn("hover:text-foreground transition-colors", className)}
{...props} {...props}
/> />
) );
} }
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) { function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
@ -59,7 +59,7 @@ function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
className={cn("text-foreground font-normal", className)} className={cn("text-foreground font-normal", className)}
{...props} {...props}
/> />
) );
} }
function BreadcrumbSeparator({ function BreadcrumbSeparator({
@ -77,7 +77,7 @@ function BreadcrumbSeparator({
> >
{children ?? <ChevronRight />} {children ?? <ChevronRight />}
</li> </li>
) );
} }
function BreadcrumbEllipsis({ function BreadcrumbEllipsis({
@ -95,7 +95,7 @@ function BreadcrumbEllipsis({
<MoreHorizontal className="size-4" /> <MoreHorizontal className="size-4" />
<span className="sr-only">More</span> <span className="sr-only">More</span>
</span> </span>
) );
} }
export { export {
@ -106,4 +106,4 @@ export {
BreadcrumbPage, BreadcrumbPage,
BreadcrumbSeparator, BreadcrumbSeparator,
BreadcrumbEllipsis, BreadcrumbEllipsis,
} };

View File

@ -1,8 +1,8 @@
import * as React from "react" import { Slot } from "@radix-ui/react-slot";
import { Slot } from "@radix-ui/react-slot" import { type VariantProps, cva } from "class-variance-authority";
import { cva, type VariantProps } from "class-variance-authority" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
const buttonVariants = cva( const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
@ -33,7 +33,7 @@ const buttonVariants = cva(
size: "default", size: "default",
}, },
} }
) );
function Button({ function Button({
className, className,
@ -43,9 +43,9 @@ function Button({
...props ...props
}: React.ComponentProps<"button"> & }: React.ComponentProps<"button"> &
VariantProps<typeof buttonVariants> & { VariantProps<typeof buttonVariants> & {
asChild?: boolean asChild?: boolean;
}) { }) {
const Comp = asChild ? Slot : "button" const Comp = asChild ? Slot : "button";
return ( return (
<Comp <Comp
@ -53,7 +53,7 @@ function Button({
className={cn(buttonVariants({ variant, size, className }))} className={cn(buttonVariants({ variant, size, className }))}
{...props} {...props}
/> />
) );
} }
export { Button, buttonVariants } export { Button, buttonVariants };

View File

@ -1,9 +1,9 @@
import * as React from "react" import { ChevronLeft, ChevronRight } from "lucide-react";
import { ChevronLeft, ChevronRight } from "lucide-react" import * as React from "react";
import { DayPicker } from "react-day-picker" import { DayPicker } from "react-day-picker";
import { cn } from "@/infra/styles/utils" import { buttonVariants } from "@/views/components/ui/button";
import { buttonVariants } from "@/components/ui/button" import { cn } from "@/views/utils";
function Calendar({ function Calendar({
className, className,
@ -67,7 +67,7 @@ function Calendar({
}} }}
{...props} {...props}
/> />
) );
} }
export { Calendar } export { Calendar };

View File

@ -1,6 +1,6 @@
import * as React from "react" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Card({ className, ...props }: React.ComponentProps<"div">) { function Card({ className, ...props }: React.ComponentProps<"div">) {
return ( return (
@ -12,7 +12,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
)} )}
{...props} {...props}
/> />
) );
} }
function CardHeader({ className, ...props }: React.ComponentProps<"div">) { function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
@ -25,7 +25,7 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
)} )}
{...props} {...props}
/> />
) );
} }
function CardTitle({ className, ...props }: React.ComponentProps<"div">) { function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
@ -35,7 +35,7 @@ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
className={cn("leading-none font-semibold", className)} className={cn("leading-none font-semibold", className)}
{...props} {...props}
/> />
) );
} }
function CardDescription({ className, ...props }: React.ComponentProps<"div">) { function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
@ -45,7 +45,7 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
className={cn("text-muted-foreground text-sm", className)} className={cn("text-muted-foreground text-sm", className)}
{...props} {...props}
/> />
) );
} }
function CardAction({ className, ...props }: React.ComponentProps<"div">) { function CardAction({ className, ...props }: React.ComponentProps<"div">) {
@ -58,7 +58,7 @@ function CardAction({ className, ...props }: React.ComponentProps<"div">) {
)} )}
{...props} {...props}
/> />
) );
} }
function CardContent({ className, ...props }: React.ComponentProps<"div">) { function CardContent({ className, ...props }: React.ComponentProps<"div">) {
@ -68,7 +68,7 @@ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
className={cn("px-6", className)} className={cn("px-6", className)}
{...props} {...props}
/> />
) );
} }
function CardFooter({ className, ...props }: React.ComponentProps<"div">) { function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
@ -78,7 +78,7 @@ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
className={cn("flex items-center px-6 [.border-t]:pt-6", className)} className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
{...props} {...props}
/> />
) );
} }
export { export {
@ -89,4 +89,4 @@ export {
CardAction, CardAction,
CardDescription, CardDescription,
CardContent, CardContent,
} };

View File

@ -1,45 +1,45 @@
"use client" "use client";
import * as React from "react"
import useEmblaCarousel, { import useEmblaCarousel, {
type UseEmblaCarouselType, type UseEmblaCarouselType,
} from "embla-carousel-react" } from "embla-carousel-react";
import { ArrowLeft, ArrowRight } from "lucide-react" import { ArrowLeft, ArrowRight } from "lucide-react";
import * as React from "react";
import { cn } from "@/infra/styles/utils" import { Button } from "@/views/components/ui/button";
import { Button } from "@/components/ui/button" import { cn } from "@/views/utils";
type CarouselApi = UseEmblaCarouselType[1] type CarouselApi = UseEmblaCarouselType[1];
type UseCarouselParameters = Parameters<typeof useEmblaCarousel> type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
type CarouselOptions = UseCarouselParameters[0] type CarouselOptions = UseCarouselParameters[0];
type CarouselPlugin = UseCarouselParameters[1] type CarouselPlugin = UseCarouselParameters[1];
type CarouselProps = { type CarouselProps = {
opts?: CarouselOptions opts?: CarouselOptions;
plugins?: CarouselPlugin plugins?: CarouselPlugin;
orientation?: "horizontal" | "vertical" orientation?: "horizontal" | "vertical";
setApi?: (api: CarouselApi) => void setApi?: (api: CarouselApi) => void;
} };
type CarouselContextProps = { type CarouselContextProps = {
carouselRef: ReturnType<typeof useEmblaCarousel>[0] carouselRef: ReturnType<typeof useEmblaCarousel>[0];
api: ReturnType<typeof useEmblaCarousel>[1] api: ReturnType<typeof useEmblaCarousel>[1];
scrollPrev: () => void scrollPrev: () => void;
scrollNext: () => void scrollNext: () => void;
canScrollPrev: boolean canScrollPrev: boolean;
canScrollNext: boolean canScrollNext: boolean;
} & CarouselProps } & CarouselProps;
const CarouselContext = React.createContext<CarouselContextProps | null>(null) const CarouselContext = React.createContext<CarouselContextProps | null>(null);
function useCarousel() { function useCarousel() {
const context = React.useContext(CarouselContext) const context = React.useContext(CarouselContext);
if (!context) { if (!context) {
throw new Error("useCarousel must be used within a <Carousel />") throw new Error("useCarousel must be used within a <Carousel />");
} }
return context return context;
} }
function Carousel({ function Carousel({
@ -57,52 +57,52 @@ function Carousel({
axis: orientation === "horizontal" ? "x" : "y", axis: orientation === "horizontal" ? "x" : "y",
}, },
plugins plugins
) );
const [canScrollPrev, setCanScrollPrev] = React.useState(false) const [canScrollPrev, setCanScrollPrev] = React.useState(false);
const [canScrollNext, setCanScrollNext] = React.useState(false) const [canScrollNext, setCanScrollNext] = React.useState(false);
const onSelect = React.useCallback((api: CarouselApi) => { const onSelect = React.useCallback((api: CarouselApi) => {
if (!api) return if (!api) return;
setCanScrollPrev(api.canScrollPrev()) setCanScrollPrev(api.canScrollPrev());
setCanScrollNext(api.canScrollNext()) setCanScrollNext(api.canScrollNext());
}, []) }, []);
const scrollPrev = React.useCallback(() => { const scrollPrev = React.useCallback(() => {
api?.scrollPrev() api?.scrollPrev();
}, [api]) }, [api]);
const scrollNext = React.useCallback(() => { const scrollNext = React.useCallback(() => {
api?.scrollNext() api?.scrollNext();
}, [api]) }, [api]);
const handleKeyDown = React.useCallback( const handleKeyDown = React.useCallback(
(event: React.KeyboardEvent<HTMLDivElement>) => { (event: React.KeyboardEvent<HTMLDivElement>) => {
if (event.key === "ArrowLeft") { if (event.key === "ArrowLeft") {
event.preventDefault() event.preventDefault();
scrollPrev() scrollPrev();
} else if (event.key === "ArrowRight") { } else if (event.key === "ArrowRight") {
event.preventDefault() event.preventDefault();
scrollNext() scrollNext();
} }
}, },
[scrollPrev, scrollNext] [scrollPrev, scrollNext]
) );
React.useEffect(() => { React.useEffect(() => {
if (!api || !setApi) return if (!api || !setApi) return;
setApi(api) setApi(api);
}, [api, setApi]) }, [api, setApi]);
React.useEffect(() => { React.useEffect(() => {
if (!api) return if (!api) return;
onSelect(api) onSelect(api);
api.on("reInit", onSelect) api.on("reInit", onSelect);
api.on("select", onSelect) api.on("select", onSelect);
return () => { return () => {
api?.off("select", onSelect) api?.off("select", onSelect);
} };
}, [api, onSelect]) }, [api, onSelect]);
return ( return (
<CarouselContext.Provider <CarouselContext.Provider
@ -129,11 +129,11 @@ function Carousel({
{children} {children}
</div> </div>
</CarouselContext.Provider> </CarouselContext.Provider>
) );
} }
function CarouselContent({ className, ...props }: React.ComponentProps<"div">) { function CarouselContent({ className, ...props }: React.ComponentProps<"div">) {
const { carouselRef, orientation } = useCarousel() const { carouselRef, orientation } = useCarousel();
return ( return (
<div <div
@ -150,11 +150,11 @@ function CarouselContent({ className, ...props }: React.ComponentProps<"div">) {
{...props} {...props}
/> />
</div> </div>
) );
} }
function CarouselItem({ className, ...props }: React.ComponentProps<"div">) { function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
const { orientation } = useCarousel() const { orientation } = useCarousel();
return ( return (
<div <div
@ -168,7 +168,7 @@ function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
)} )}
{...props} {...props}
/> />
) );
} }
function CarouselPrevious({ function CarouselPrevious({
@ -177,7 +177,7 @@ function CarouselPrevious({
size = "icon", size = "icon",
...props ...props
}: React.ComponentProps<typeof Button>) { }: React.ComponentProps<typeof Button>) {
const { orientation, scrollPrev, canScrollPrev } = useCarousel() const { orientation, scrollPrev, canScrollPrev } = useCarousel();
return ( return (
<Button <Button
@ -198,7 +198,7 @@ function CarouselPrevious({
<ArrowLeft /> <ArrowLeft />
<span className="sr-only">Previous slide</span> <span className="sr-only">Previous slide</span>
</Button> </Button>
) );
} }
function CarouselNext({ function CarouselNext({
@ -207,7 +207,7 @@ function CarouselNext({
size = "icon", size = "icon",
...props ...props
}: React.ComponentProps<typeof Button>) { }: React.ComponentProps<typeof Button>) {
const { orientation, scrollNext, canScrollNext } = useCarousel() const { orientation, scrollNext, canScrollNext } = useCarousel();
return ( return (
<Button <Button
@ -228,7 +228,7 @@ function CarouselNext({
<ArrowRight /> <ArrowRight />
<span className="sr-only">Next slide</span> <span className="sr-only">Next slide</span>
</Button> </Button>
) );
} }
export { export {
@ -238,4 +238,4 @@ export {
CarouselItem, CarouselItem,
CarouselPrevious, CarouselPrevious,
CarouselNext, CarouselNext,
} };

View File

@ -1,7 +1,7 @@
import * as React from "react"; import * as React from "react";
import * as RechartsPrimitive from "recharts"; import * as RechartsPrimitive from "recharts";
import { cn } from "@/infra/styles/utils"; import { cn } from "@/views/utils";
// Format: { THEME_NAME: CSS_SELECTOR } // Format: { THEME_NAME: CSS_SELECTOR }
const THEMES = { light: "", dark: ".dark" } as const; const THEMES = { light: "", dark: ".dark" } as const;

View File

@ -1,10 +1,10 @@
"use client" "use client";
import * as React from "react" import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import * as CheckboxPrimitive from "@radix-ui/react-checkbox" import { CheckIcon } from "lucide-react";
import { CheckIcon } from "lucide-react" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Checkbox({ function Checkbox({
className, className,
@ -26,7 +26,7 @@ function Checkbox({
<CheckIcon className="size-3.5" /> <CheckIcon className="size-3.5" />
</CheckboxPrimitive.Indicator> </CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root> </CheckboxPrimitive.Root>
) );
} }
export { Checkbox } export { Checkbox };

View File

@ -1,17 +1,17 @@
"use client" "use client";
import * as React from "react" import { Command as CommandPrimitive } from "cmdk";
import { Command as CommandPrimitive } from "cmdk" import { SearchIcon } from "lucide-react";
import { SearchIcon } from "lucide-react" import * as React from "react";
import { cn } from "@/infra/styles/utils"
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
DialogDescription, DialogDescription,
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from "@/components/ui/dialog" } from "@/views/components/ui/dialog";
import { cn } from "@/views/utils";
function Command({ function Command({
className, className,
@ -26,7 +26,7 @@ function Command({
)} )}
{...props} {...props}
/> />
) );
} }
function CommandDialog({ function CommandDialog({
@ -35,8 +35,8 @@ function CommandDialog({
children, children,
...props ...props
}: React.ComponentProps<typeof Dialog> & { }: React.ComponentProps<typeof Dialog> & {
title?: string title?: string;
description?: string description?: string;
}) { }) {
return ( return (
<Dialog {...props}> <Dialog {...props}>
@ -50,7 +50,7 @@ function CommandDialog({
</Command> </Command>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
) );
} }
function CommandInput({ function CommandInput({
@ -72,7 +72,7 @@ function CommandInput({
{...props} {...props}
/> />
</div> </div>
) );
} }
function CommandList({ function CommandList({
@ -88,7 +88,7 @@ function CommandList({
)} )}
{...props} {...props}
/> />
) );
} }
function CommandEmpty({ function CommandEmpty({
@ -100,7 +100,7 @@ function CommandEmpty({
className="py-6 text-center text-sm" className="py-6 text-center text-sm"
{...props} {...props}
/> />
) );
} }
function CommandGroup({ function CommandGroup({
@ -116,7 +116,7 @@ function CommandGroup({
)} )}
{...props} {...props}
/> />
) );
} }
function CommandSeparator({ function CommandSeparator({
@ -129,7 +129,7 @@ function CommandSeparator({
className={cn("bg-border -mx-1 h-px", className)} className={cn("bg-border -mx-1 h-px", className)}
{...props} {...props}
/> />
) );
} }
function CommandItem({ function CommandItem({
@ -145,7 +145,7 @@ function CommandItem({
)} )}
{...props} {...props}
/> />
) );
} }
function CommandShortcut({ function CommandShortcut({
@ -161,7 +161,7 @@ function CommandShortcut({
)} )}
{...props} {...props}
/> />
) );
} }
export { export {
@ -174,4 +174,4 @@ export {
CommandItem, CommandItem,
CommandShortcut, CommandShortcut,
CommandSeparator, CommandSeparator,
} };

View File

@ -1,15 +1,15 @@
"use client" "use client";
import * as React from "react" import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu" import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function ContextMenu({ function ContextMenu({
...props ...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Root>) { }: React.ComponentProps<typeof ContextMenuPrimitive.Root>) {
return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} /> return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />;
} }
function ContextMenuTrigger({ function ContextMenuTrigger({
@ -17,7 +17,7 @@ function ContextMenuTrigger({
}: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) { }: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) {
return ( return (
<ContextMenuPrimitive.Trigger data-slot="context-menu-trigger" {...props} /> <ContextMenuPrimitive.Trigger data-slot="context-menu-trigger" {...props} />
) );
} }
function ContextMenuGroup({ function ContextMenuGroup({
@ -25,7 +25,7 @@ function ContextMenuGroup({
}: React.ComponentProps<typeof ContextMenuPrimitive.Group>) { }: React.ComponentProps<typeof ContextMenuPrimitive.Group>) {
return ( return (
<ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} /> <ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} />
) );
} }
function ContextMenuPortal({ function ContextMenuPortal({
@ -33,13 +33,13 @@ function ContextMenuPortal({
}: React.ComponentProps<typeof ContextMenuPrimitive.Portal>) { }: React.ComponentProps<typeof ContextMenuPrimitive.Portal>) {
return ( return (
<ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} /> <ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} />
) );
} }
function ContextMenuSub({ function ContextMenuSub({
...props ...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Sub>) { }: React.ComponentProps<typeof ContextMenuPrimitive.Sub>) {
return <ContextMenuPrimitive.Sub data-slot="context-menu-sub" {...props} /> return <ContextMenuPrimitive.Sub data-slot="context-menu-sub" {...props} />;
} }
function ContextMenuRadioGroup({ function ContextMenuRadioGroup({
@ -50,7 +50,7 @@ function ContextMenuRadioGroup({
data-slot="context-menu-radio-group" data-slot="context-menu-radio-group"
{...props} {...props}
/> />
) );
} }
function ContextMenuSubTrigger({ function ContextMenuSubTrigger({
@ -59,7 +59,7 @@ function ContextMenuSubTrigger({
children, children,
...props ...props
}: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & { }: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {
inset?: boolean inset?: boolean;
}) { }) {
return ( return (
<ContextMenuPrimitive.SubTrigger <ContextMenuPrimitive.SubTrigger
@ -74,7 +74,7 @@ function ContextMenuSubTrigger({
{children} {children}
<ChevronRightIcon className="ml-auto" /> <ChevronRightIcon className="ml-auto" />
</ContextMenuPrimitive.SubTrigger> </ContextMenuPrimitive.SubTrigger>
) );
} }
function ContextMenuSubContent({ function ContextMenuSubContent({
@ -90,7 +90,7 @@ function ContextMenuSubContent({
)} )}
{...props} {...props}
/> />
) );
} }
function ContextMenuContent({ function ContextMenuContent({
@ -108,7 +108,7 @@ function ContextMenuContent({
{...props} {...props}
/> />
</ContextMenuPrimitive.Portal> </ContextMenuPrimitive.Portal>
) );
} }
function ContextMenuItem({ function ContextMenuItem({
@ -117,8 +117,8 @@ function ContextMenuItem({
variant = "default", variant = "default",
...props ...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Item> & { }: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {
inset?: boolean inset?: boolean;
variant?: "default" | "destructive" variant?: "default" | "destructive";
}) { }) {
return ( return (
<ContextMenuPrimitive.Item <ContextMenuPrimitive.Item
@ -131,7 +131,7 @@ function ContextMenuItem({
)} )}
{...props} {...props}
/> />
) );
} }
function ContextMenuCheckboxItem({ function ContextMenuCheckboxItem({
@ -157,7 +157,7 @@ function ContextMenuCheckboxItem({
</span> </span>
{children} {children}
</ContextMenuPrimitive.CheckboxItem> </ContextMenuPrimitive.CheckboxItem>
) );
} }
function ContextMenuRadioItem({ function ContextMenuRadioItem({
@ -181,7 +181,7 @@ function ContextMenuRadioItem({
</span> </span>
{children} {children}
</ContextMenuPrimitive.RadioItem> </ContextMenuPrimitive.RadioItem>
) );
} }
function ContextMenuLabel({ function ContextMenuLabel({
@ -189,7 +189,7 @@ function ContextMenuLabel({
inset, inset,
...props ...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Label> & { }: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {
inset?: boolean inset?: boolean;
}) { }) {
return ( return (
<ContextMenuPrimitive.Label <ContextMenuPrimitive.Label
@ -201,7 +201,7 @@ function ContextMenuLabel({
)} )}
{...props} {...props}
/> />
) );
} }
function ContextMenuSeparator({ function ContextMenuSeparator({
@ -214,7 +214,7 @@ function ContextMenuSeparator({
className={cn("bg-border -mx-1 my-1 h-px", className)} className={cn("bg-border -mx-1 my-1 h-px", className)}
{...props} {...props}
/> />
) );
} }
function ContextMenuShortcut({ function ContextMenuShortcut({
@ -230,7 +230,7 @@ function ContextMenuShortcut({
)} )}
{...props} {...props}
/> />
) );
} }
export { export {
@ -249,4 +249,4 @@ export {
ContextMenuSubContent, ContextMenuSubContent,
ContextMenuSubTrigger, ContextMenuSubTrigger,
ContextMenuRadioGroup, ContextMenuRadioGroup,
} };

View File

@ -1,31 +1,31 @@
import * as React from "react" import * as DialogPrimitive from "@radix-ui/react-dialog";
import * as DialogPrimitive from "@radix-ui/react-dialog" import { XIcon } from "lucide-react";
import { XIcon } from "lucide-react" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Dialog({ function Dialog({
...props ...props
}: React.ComponentProps<typeof DialogPrimitive.Root>) { }: React.ComponentProps<typeof DialogPrimitive.Root>) {
return <DialogPrimitive.Root data-slot="dialog" {...props} /> return <DialogPrimitive.Root data-slot="dialog" {...props} />;
} }
function DialogTrigger({ function DialogTrigger({
...props ...props
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) { }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} /> return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
} }
function DialogPortal({ function DialogPortal({
...props ...props
}: React.ComponentProps<typeof DialogPrimitive.Portal>) { }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} /> return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
} }
function DialogClose({ function DialogClose({
...props ...props
}: React.ComponentProps<typeof DialogPrimitive.Close>) { }: React.ComponentProps<typeof DialogPrimitive.Close>) {
return <DialogPrimitive.Close data-slot="dialog-close" {...props} /> return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
} }
function DialogOverlay({ function DialogOverlay({
@ -41,7 +41,7 @@ function DialogOverlay({
)} )}
{...props} {...props}
/> />
) );
} }
function DialogContent({ function DialogContent({
@ -67,7 +67,7 @@ function DialogContent({
</DialogPrimitive.Close> </DialogPrimitive.Close>
</DialogPrimitive.Content> </DialogPrimitive.Content>
</DialogPortal> </DialogPortal>
) );
} }
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
@ -77,7 +77,7 @@ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
className={cn("flex flex-col gap-2 text-center sm:text-left", className)} className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
{...props} {...props}
/> />
) );
} }
function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
@ -90,7 +90,7 @@ function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
)} )}
{...props} {...props}
/> />
) );
} }
function DialogTitle({ function DialogTitle({
@ -103,7 +103,7 @@ function DialogTitle({
className={cn("text-lg leading-none font-semibold", className)} className={cn("text-lg leading-none font-semibold", className)}
{...props} {...props}
/> />
) );
} }
function DialogDescription({ function DialogDescription({
@ -116,7 +116,7 @@ function DialogDescription({
className={cn("text-muted-foreground text-sm", className)} className={cn("text-muted-foreground text-sm", className)}
{...props} {...props}
/> />
) );
} }
export { export {
@ -130,4 +130,4 @@ export {
DialogPortal, DialogPortal,
DialogTitle, DialogTitle,
DialogTrigger, DialogTrigger,
} };

View File

@ -1,30 +1,30 @@
import * as React from "react" import * as React from "react";
import { Drawer as DrawerPrimitive } from "vaul" import { Drawer as DrawerPrimitive } from "vaul";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Drawer({ function Drawer({
...props ...props
}: React.ComponentProps<typeof DrawerPrimitive.Root>) { }: React.ComponentProps<typeof DrawerPrimitive.Root>) {
return <DrawerPrimitive.Root data-slot="drawer" {...props} /> return <DrawerPrimitive.Root data-slot="drawer" {...props} />;
} }
function DrawerTrigger({ function DrawerTrigger({
...props ...props
}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) { }: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {
return <DrawerPrimitive.Trigger data-slot="drawer-trigger" {...props} /> return <DrawerPrimitive.Trigger data-slot="drawer-trigger" {...props} />;
} }
function DrawerPortal({ function DrawerPortal({
...props ...props
}: React.ComponentProps<typeof DrawerPrimitive.Portal>) { }: React.ComponentProps<typeof DrawerPrimitive.Portal>) {
return <DrawerPrimitive.Portal data-slot="drawer-portal" {...props} /> return <DrawerPrimitive.Portal data-slot="drawer-portal" {...props} />;
} }
function DrawerClose({ function DrawerClose({
...props ...props
}: React.ComponentProps<typeof DrawerPrimitive.Close>) { }: React.ComponentProps<typeof DrawerPrimitive.Close>) {
return <DrawerPrimitive.Close data-slot="drawer-close" {...props} /> return <DrawerPrimitive.Close data-slot="drawer-close" {...props} />;
} }
function DrawerOverlay({ function DrawerOverlay({
@ -40,7 +40,7 @@ function DrawerOverlay({
)} )}
{...props} {...props}
/> />
) );
} }
function DrawerContent({ function DrawerContent({
@ -67,7 +67,7 @@ function DrawerContent({
{children} {children}
</DrawerPrimitive.Content> </DrawerPrimitive.Content>
</DrawerPortal> </DrawerPortal>
) );
} }
function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) { function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) {
@ -77,7 +77,7 @@ function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) {
className={cn("flex flex-col gap-1.5 p-4", className)} className={cn("flex flex-col gap-1.5 p-4", className)}
{...props} {...props}
/> />
) );
} }
function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) { function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) {
@ -87,7 +87,7 @@ function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) {
className={cn("mt-auto flex flex-col gap-2 p-4", className)} className={cn("mt-auto flex flex-col gap-2 p-4", className)}
{...props} {...props}
/> />
) );
} }
function DrawerTitle({ function DrawerTitle({
@ -100,7 +100,7 @@ function DrawerTitle({
className={cn("text-foreground font-semibold", className)} className={cn("text-foreground font-semibold", className)}
{...props} {...props}
/> />
) );
} }
function DrawerDescription({ function DrawerDescription({
@ -113,7 +113,7 @@ function DrawerDescription({
className={cn("text-muted-foreground text-sm", className)} className={cn("text-muted-foreground text-sm", className)}
{...props} {...props}
/> />
) );
} }
export { export {
@ -127,4 +127,4 @@ export {
DrawerFooter, DrawerFooter,
DrawerTitle, DrawerTitle,
DrawerDescription, DrawerDescription,
} };

View File

@ -1,15 +1,15 @@
"use client" "use client";
import * as React from "react" import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function DropdownMenu({ function DropdownMenu({
...props ...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) { }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} /> return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
} }
function DropdownMenuPortal({ function DropdownMenuPortal({
@ -17,7 +17,7 @@ function DropdownMenuPortal({
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) { }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
return ( return (
<DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} /> <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
) );
} }
function DropdownMenuTrigger({ function DropdownMenuTrigger({
@ -28,7 +28,7 @@ function DropdownMenuTrigger({
data-slot="dropdown-menu-trigger" data-slot="dropdown-menu-trigger"
{...props} {...props}
/> />
) );
} }
function DropdownMenuContent({ function DropdownMenuContent({
@ -48,7 +48,7 @@ function DropdownMenuContent({
{...props} {...props}
/> />
</DropdownMenuPrimitive.Portal> </DropdownMenuPrimitive.Portal>
) );
} }
function DropdownMenuGroup({ function DropdownMenuGroup({
@ -56,7 +56,7 @@ function DropdownMenuGroup({
}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) { }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
return ( return (
<DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} /> <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
) );
} }
function DropdownMenuItem({ function DropdownMenuItem({
@ -65,8 +65,8 @@ function DropdownMenuItem({
variant = "default", variant = "default",
...props ...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & { }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean inset?: boolean;
variant?: "default" | "destructive" variant?: "default" | "destructive";
}) { }) {
return ( return (
<DropdownMenuPrimitive.Item <DropdownMenuPrimitive.Item
@ -79,7 +79,7 @@ function DropdownMenuItem({
)} )}
{...props} {...props}
/> />
) );
} }
function DropdownMenuCheckboxItem({ function DropdownMenuCheckboxItem({
@ -105,7 +105,7 @@ function DropdownMenuCheckboxItem({
</span> </span>
{children} {children}
</DropdownMenuPrimitive.CheckboxItem> </DropdownMenuPrimitive.CheckboxItem>
) );
} }
function DropdownMenuRadioGroup({ function DropdownMenuRadioGroup({
@ -116,7 +116,7 @@ function DropdownMenuRadioGroup({
data-slot="dropdown-menu-radio-group" data-slot="dropdown-menu-radio-group"
{...props} {...props}
/> />
) );
} }
function DropdownMenuRadioItem({ function DropdownMenuRadioItem({
@ -140,7 +140,7 @@ function DropdownMenuRadioItem({
</span> </span>
{children} {children}
</DropdownMenuPrimitive.RadioItem> </DropdownMenuPrimitive.RadioItem>
) );
} }
function DropdownMenuLabel({ function DropdownMenuLabel({
@ -148,7 +148,7 @@ function DropdownMenuLabel({
inset, inset,
...props ...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & { }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
inset?: boolean inset?: boolean;
}) { }) {
return ( return (
<DropdownMenuPrimitive.Label <DropdownMenuPrimitive.Label
@ -160,7 +160,7 @@ function DropdownMenuLabel({
)} )}
{...props} {...props}
/> />
) );
} }
function DropdownMenuSeparator({ function DropdownMenuSeparator({
@ -173,7 +173,7 @@ function DropdownMenuSeparator({
className={cn("bg-border -mx-1 my-1 h-px", className)} className={cn("bg-border -mx-1 my-1 h-px", className)}
{...props} {...props}
/> />
) );
} }
function DropdownMenuShortcut({ function DropdownMenuShortcut({
@ -189,13 +189,13 @@ function DropdownMenuShortcut({
)} )}
{...props} {...props}
/> />
) );
} }
function DropdownMenuSub({ function DropdownMenuSub({
...props ...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) { }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} /> return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
} }
function DropdownMenuSubTrigger({ function DropdownMenuSubTrigger({
@ -204,7 +204,7 @@ function DropdownMenuSubTrigger({
children, children,
...props ...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & { }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
inset?: boolean inset?: boolean;
}) { }) {
return ( return (
<DropdownMenuPrimitive.SubTrigger <DropdownMenuPrimitive.SubTrigger
@ -219,7 +219,7 @@ function DropdownMenuSubTrigger({
{children} {children}
<ChevronRightIcon className="ml-auto size-4" /> <ChevronRightIcon className="ml-auto size-4" />
</DropdownMenuPrimitive.SubTrigger> </DropdownMenuPrimitive.SubTrigger>
) );
} }
function DropdownMenuSubContent({ function DropdownMenuSubContent({
@ -235,7 +235,7 @@ function DropdownMenuSubContent({
)} )}
{...props} {...props}
/> />
) );
} }
export { export {
@ -254,4 +254,4 @@ export {
DropdownMenuSub, DropdownMenuSub,
DropdownMenuSubTrigger, DropdownMenuSubTrigger,
DropdownMenuSubContent, DropdownMenuSubContent,
} };

View File

@ -11,8 +11,8 @@ import {
useFormState, useFormState,
} from "react-hook-form"; } from "react-hook-form";
import { Label } from "@/components/ui/label"; import { Label } from "@/views/components/ui/label";
import { cn } from "@/infra/styles/utils"; import { cn } from "@/views/utils";
const Form = FormProvider; const Form = FormProvider;

View File

@ -1,12 +1,12 @@
import * as React from "react" import * as HoverCardPrimitive from "@radix-ui/react-hover-card";
import * as HoverCardPrimitive from "@radix-ui/react-hover-card" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function HoverCard({ function HoverCard({
...props ...props
}: React.ComponentProps<typeof HoverCardPrimitive.Root>) { }: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
return <HoverCardPrimitive.Root data-slot="hover-card" {...props} /> return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />;
} }
function HoverCardTrigger({ function HoverCardTrigger({
@ -14,7 +14,7 @@ function HoverCardTrigger({
}: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) { }: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
return ( return (
<HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} /> <HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
) );
} }
function HoverCardContent({ function HoverCardContent({
@ -36,7 +36,7 @@ function HoverCardContent({
{...props} {...props}
/> />
</HoverCardPrimitive.Portal> </HoverCardPrimitive.Portal>
) );
} }
export { HoverCard, HoverCardTrigger, HoverCardContent } export { HoverCard, HoverCardTrigger, HoverCardContent };

View File

@ -1,17 +1,17 @@
"use client" "use client";
import * as React from "react" import { OTPInput, OTPInputContext } from "input-otp";
import { OTPInput, OTPInputContext } from "input-otp" import { MinusIcon } from "lucide-react";
import { MinusIcon } from "lucide-react" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function InputOTP({ function InputOTP({
className, className,
containerClassName, containerClassName,
...props ...props
}: React.ComponentProps<typeof OTPInput> & { }: React.ComponentProps<typeof OTPInput> & {
containerClassName?: string containerClassName?: string;
}) { }) {
return ( return (
<OTPInput <OTPInput
@ -23,7 +23,7 @@ function InputOTP({
className={cn("disabled:cursor-not-allowed", className)} className={cn("disabled:cursor-not-allowed", className)}
{...props} {...props}
/> />
) );
} }
function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) { function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) {
@ -33,7 +33,7 @@ function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) {
className={cn("flex items-center", className)} className={cn("flex items-center", className)}
{...props} {...props}
/> />
) );
} }
function InputOTPSlot({ function InputOTPSlot({
@ -41,10 +41,10 @@ function InputOTPSlot({
className, className,
...props ...props
}: React.ComponentProps<"div"> & { }: React.ComponentProps<"div"> & {
index: number index: number;
}) { }) {
const inputOTPContext = React.useContext(OTPInputContext) const inputOTPContext = React.useContext(OTPInputContext);
const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {} const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
return ( return (
<div <div
@ -63,7 +63,7 @@ function InputOTPSlot({
</div> </div>
)} )}
</div> </div>
) );
} }
function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) { function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) {
@ -71,7 +71,7 @@ function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) {
<div data-slot="input-otp-separator" role="separator" {...props}> <div data-slot="input-otp-separator" role="separator" {...props}>
<MinusIcon /> <MinusIcon />
</div> </div>
) );
} }
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };

View File

@ -1,6 +1,6 @@
import * as React from "react" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Input({ className, type, ...props }: React.ComponentProps<"input">) { function Input({ className, type, ...props }: React.ComponentProps<"input">) {
return ( return (
@ -15,7 +15,7 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
)} )}
{...props} {...props}
/> />
) );
} }
export { Input } export { Input };

View File

@ -1,9 +1,9 @@
"use client" "use client";
import * as React from "react" import * as LabelPrimitive from "@radix-ui/react-label";
import * as LabelPrimitive from "@radix-ui/react-label" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Label({ function Label({
className, className,
@ -18,7 +18,7 @@ function Label({
)} )}
{...props} {...props}
/> />
) );
} }
export { Label } export { Label };

View File

@ -1,8 +1,8 @@
import * as React from "react" import * as MenubarPrimitive from "@radix-ui/react-menubar";
import * as MenubarPrimitive from "@radix-ui/react-menubar" import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Menubar({ function Menubar({
className, className,
@ -17,25 +17,25 @@ function Menubar({
)} )}
{...props} {...props}
/> />
) );
} }
function MenubarMenu({ function MenubarMenu({
...props ...props
}: React.ComponentProps<typeof MenubarPrimitive.Menu>) { }: React.ComponentProps<typeof MenubarPrimitive.Menu>) {
return <MenubarPrimitive.Menu data-slot="menubar-menu" {...props} /> return <MenubarPrimitive.Menu data-slot="menubar-menu" {...props} />;
} }
function MenubarGroup({ function MenubarGroup({
...props ...props
}: React.ComponentProps<typeof MenubarPrimitive.Group>) { }: React.ComponentProps<typeof MenubarPrimitive.Group>) {
return <MenubarPrimitive.Group data-slot="menubar-group" {...props} /> return <MenubarPrimitive.Group data-slot="menubar-group" {...props} />;
} }
function MenubarPortal({ function MenubarPortal({
...props ...props
}: React.ComponentProps<typeof MenubarPrimitive.Portal>) { }: React.ComponentProps<typeof MenubarPrimitive.Portal>) {
return <MenubarPrimitive.Portal data-slot="menubar-portal" {...props} /> return <MenubarPrimitive.Portal data-slot="menubar-portal" {...props} />;
} }
function MenubarRadioGroup({ function MenubarRadioGroup({
@ -43,7 +43,7 @@ function MenubarRadioGroup({
}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) { }: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {
return ( return (
<MenubarPrimitive.RadioGroup data-slot="menubar-radio-group" {...props} /> <MenubarPrimitive.RadioGroup data-slot="menubar-radio-group" {...props} />
) );
} }
function MenubarTrigger({ function MenubarTrigger({
@ -59,7 +59,7 @@ function MenubarTrigger({
)} )}
{...props} {...props}
/> />
) );
} }
function MenubarContent({ function MenubarContent({
@ -83,7 +83,7 @@ function MenubarContent({
{...props} {...props}
/> />
</MenubarPortal> </MenubarPortal>
) );
} }
function MenubarItem({ function MenubarItem({
@ -92,8 +92,8 @@ function MenubarItem({
variant = "default", variant = "default",
...props ...props
}: React.ComponentProps<typeof MenubarPrimitive.Item> & { }: React.ComponentProps<typeof MenubarPrimitive.Item> & {
inset?: boolean inset?: boolean;
variant?: "default" | "destructive" variant?: "default" | "destructive";
}) { }) {
return ( return (
<MenubarPrimitive.Item <MenubarPrimitive.Item
@ -106,7 +106,7 @@ function MenubarItem({
)} )}
{...props} {...props}
/> />
) );
} }
function MenubarCheckboxItem({ function MenubarCheckboxItem({
@ -132,7 +132,7 @@ function MenubarCheckboxItem({
</span> </span>
{children} {children}
</MenubarPrimitive.CheckboxItem> </MenubarPrimitive.CheckboxItem>
) );
} }
function MenubarRadioItem({ function MenubarRadioItem({
@ -156,7 +156,7 @@ function MenubarRadioItem({
</span> </span>
{children} {children}
</MenubarPrimitive.RadioItem> </MenubarPrimitive.RadioItem>
) );
} }
function MenubarLabel({ function MenubarLabel({
@ -164,7 +164,7 @@ function MenubarLabel({
inset, inset,
...props ...props
}: React.ComponentProps<typeof MenubarPrimitive.Label> & { }: React.ComponentProps<typeof MenubarPrimitive.Label> & {
inset?: boolean inset?: boolean;
}) { }) {
return ( return (
<MenubarPrimitive.Label <MenubarPrimitive.Label
@ -176,7 +176,7 @@ function MenubarLabel({
)} )}
{...props} {...props}
/> />
) );
} }
function MenubarSeparator({ function MenubarSeparator({
@ -189,7 +189,7 @@ function MenubarSeparator({
className={cn("bg-border -mx-1 my-1 h-px", className)} className={cn("bg-border -mx-1 my-1 h-px", className)}
{...props} {...props}
/> />
) );
} }
function MenubarShortcut({ function MenubarShortcut({
@ -205,13 +205,13 @@ function MenubarShortcut({
)} )}
{...props} {...props}
/> />
) );
} }
function MenubarSub({ function MenubarSub({
...props ...props
}: React.ComponentProps<typeof MenubarPrimitive.Sub>) { }: React.ComponentProps<typeof MenubarPrimitive.Sub>) {
return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} /> return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} />;
} }
function MenubarSubTrigger({ function MenubarSubTrigger({
@ -220,7 +220,7 @@ function MenubarSubTrigger({
children, children,
...props ...props
}: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & { }: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & {
inset?: boolean inset?: boolean;
}) { }) {
return ( return (
<MenubarPrimitive.SubTrigger <MenubarPrimitive.SubTrigger
@ -235,7 +235,7 @@ function MenubarSubTrigger({
{children} {children}
<ChevronRightIcon className="ml-auto h-4 w-4" /> <ChevronRightIcon className="ml-auto h-4 w-4" />
</MenubarPrimitive.SubTrigger> </MenubarPrimitive.SubTrigger>
) );
} }
function MenubarSubContent({ function MenubarSubContent({
@ -251,7 +251,7 @@ function MenubarSubContent({
)} )}
{...props} {...props}
/> />
) );
} }
export { export {
@ -271,4 +271,4 @@ export {
MenubarSub, MenubarSub,
MenubarSubTrigger, MenubarSubTrigger,
MenubarSubContent, MenubarSubContent,
} };

View File

@ -1,9 +1,9 @@
import * as React from "react" import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu" import { cva } from "class-variance-authority";
import { cva } from "class-variance-authority" import { ChevronDownIcon } from "lucide-react";
import { ChevronDownIcon } from "lucide-react" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function NavigationMenu({ function NavigationMenu({
className, className,
@ -11,7 +11,7 @@ function NavigationMenu({
viewport = true, viewport = true,
...props ...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & { }: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {
viewport?: boolean viewport?: boolean;
}) { }) {
return ( return (
<NavigationMenuPrimitive.Root <NavigationMenuPrimitive.Root
@ -26,7 +26,7 @@ function NavigationMenu({
{children} {children}
{viewport && <NavigationMenuViewport />} {viewport && <NavigationMenuViewport />}
</NavigationMenuPrimitive.Root> </NavigationMenuPrimitive.Root>
) );
} }
function NavigationMenuList({ function NavigationMenuList({
@ -42,7 +42,7 @@ function NavigationMenuList({
)} )}
{...props} {...props}
/> />
) );
} }
function NavigationMenuItem({ function NavigationMenuItem({
@ -55,12 +55,12 @@ function NavigationMenuItem({
className={cn("relative", className)} className={cn("relative", className)}
{...props} {...props}
/> />
) );
} }
const navigationMenuTriggerStyle = cva( const navigationMenuTriggerStyle = cva(
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1" "group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1"
) );
function NavigationMenuTrigger({ function NavigationMenuTrigger({
className, className,
@ -79,7 +79,7 @@ function NavigationMenuTrigger({
aria-hidden="true" aria-hidden="true"
/> />
</NavigationMenuPrimitive.Trigger> </NavigationMenuPrimitive.Trigger>
) );
} }
function NavigationMenuContent({ function NavigationMenuContent({
@ -96,7 +96,7 @@ function NavigationMenuContent({
)} )}
{...props} {...props}
/> />
) );
} }
function NavigationMenuViewport({ function NavigationMenuViewport({
@ -118,7 +118,7 @@ function NavigationMenuViewport({
{...props} {...props}
/> />
</div> </div>
) );
} }
function NavigationMenuLink({ function NavigationMenuLink({
@ -134,7 +134,7 @@ function NavigationMenuLink({
)} )}
{...props} {...props}
/> />
) );
} }
function NavigationMenuIndicator({ function NavigationMenuIndicator({
@ -152,7 +152,7 @@ function NavigationMenuIndicator({
> >
<div className="bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md" /> <div className="bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md" />
</NavigationMenuPrimitive.Indicator> </NavigationMenuPrimitive.Indicator>
) );
} }
export { export {
@ -165,4 +165,4 @@ export {
NavigationMenuIndicator, NavigationMenuIndicator,
NavigationMenuViewport, NavigationMenuViewport,
navigationMenuTriggerStyle, navigationMenuTriggerStyle,
} };

View File

@ -1,12 +1,12 @@
import * as React from "react"
import { import {
ChevronLeftIcon, ChevronLeftIcon,
ChevronRightIcon, ChevronRightIcon,
MoreHorizontalIcon, MoreHorizontalIcon,
} from "lucide-react" } from "lucide-react";
import * as React from "react";
import { cn } from "@/infra/styles/utils" import { Button, buttonVariants } from "@/views/components/ui/button";
import { Button, buttonVariants } from "@/components/ui/button" import { cn } from "@/views/utils";
function Pagination({ className, ...props }: React.ComponentProps<"nav">) { function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
return ( return (
@ -17,7 +17,7 @@ function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
className={cn("mx-auto flex w-full justify-center", className)} className={cn("mx-auto flex w-full justify-center", className)}
{...props} {...props}
/> />
) );
} }
function PaginationContent({ function PaginationContent({
@ -30,17 +30,17 @@ function PaginationContent({
className={cn("flex flex-row items-center gap-1", className)} className={cn("flex flex-row items-center gap-1", className)}
{...props} {...props}
/> />
) );
} }
function PaginationItem({ ...props }: React.ComponentProps<"li">) { function PaginationItem({ ...props }: React.ComponentProps<"li">) {
return <li data-slot="pagination-item" {...props} /> return <li data-slot="pagination-item" {...props} />;
} }
type PaginationLinkProps = { type PaginationLinkProps = {
isActive?: boolean isActive?: boolean;
} & Pick<React.ComponentProps<typeof Button>, "size"> & } & Pick<React.ComponentProps<typeof Button>, "size"> &
React.ComponentProps<"a"> React.ComponentProps<"a">;
function PaginationLink({ function PaginationLink({
className, className,
@ -62,7 +62,7 @@ function PaginationLink({
)} )}
{...props} {...props}
/> />
) );
} }
function PaginationPrevious({ function PaginationPrevious({
@ -79,7 +79,7 @@ function PaginationPrevious({
<ChevronLeftIcon /> <ChevronLeftIcon />
<span className="hidden sm:block">Previous</span> <span className="hidden sm:block">Previous</span>
</PaginationLink> </PaginationLink>
) );
} }
function PaginationNext({ function PaginationNext({
@ -96,7 +96,7 @@ function PaginationNext({
<span className="hidden sm:block">Next</span> <span className="hidden sm:block">Next</span>
<ChevronRightIcon /> <ChevronRightIcon />
</PaginationLink> </PaginationLink>
) );
} }
function PaginationEllipsis({ function PaginationEllipsis({
@ -113,7 +113,7 @@ function PaginationEllipsis({
<MoreHorizontalIcon className="size-4" /> <MoreHorizontalIcon className="size-4" />
<span className="sr-only">More pages</span> <span className="sr-only">More pages</span>
</span> </span>
) );
} }
export { export {
@ -124,4 +124,4 @@ export {
PaginationPrevious, PaginationPrevious,
PaginationNext, PaginationNext,
PaginationEllipsis, PaginationEllipsis,
} };

View File

@ -1,20 +1,20 @@
"use client" "use client";
import * as React from "react" import * as PopoverPrimitive from "@radix-ui/react-popover";
import * as PopoverPrimitive from "@radix-ui/react-popover" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Popover({ function Popover({
...props ...props
}: React.ComponentProps<typeof PopoverPrimitive.Root>) { }: React.ComponentProps<typeof PopoverPrimitive.Root>) {
return <PopoverPrimitive.Root data-slot="popover" {...props} /> return <PopoverPrimitive.Root data-slot="popover" {...props} />;
} }
function PopoverTrigger({ function PopoverTrigger({
...props ...props
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) { }: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} /> return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
} }
function PopoverContent({ function PopoverContent({
@ -36,13 +36,13 @@ function PopoverContent({
{...props} {...props}
/> />
</PopoverPrimitive.Portal> </PopoverPrimitive.Portal>
) );
} }
function PopoverAnchor({ function PopoverAnchor({
...props ...props
}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) { }: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} /> return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />;
} }
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };

View File

@ -1,7 +1,7 @@
import { cn } from '@/infra/styles/utils'; import { cn } from "@/views/utils";
import type { FC, HTMLAttributes } from 'react'; import type { FC, HTMLAttributes } from "react";
type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl'; type Size = "xs" | "sm" | "md" | "lg" | "xl";
const sizes: Record<Size, { radius: number; strokeWidth: number }> = { const sizes: Record<Size, { radius: number; strokeWidth: number }> = {
xs: { radius: 15, strokeWidth: 3 }, xs: { radius: 15, strokeWidth: 3 },
@ -23,7 +23,7 @@ const ProgressCircle: FC<ProgressCircleProps> = ({
className, className,
children, children,
value = 0, value = 0,
size = 'md', size = "md",
radius, radius,
strokeWidth, strokeWidth,
showAnimation = true, showAnimation = true,
@ -39,7 +39,7 @@ const ProgressCircle: FC<ProgressCircleProps> = ({
return ( return (
<div <div
className={cn('flex flex-col items-center justify-center', className)} className={cn("flex flex-col items-center justify-center", className)}
{...props} {...props}
> >
<svg <svg
@ -56,7 +56,7 @@ const ProgressCircle: FC<ProgressCircleProps> = ({
fill="transparent" fill="transparent"
stroke="" stroke=""
strokeLinecap="round" strokeLinecap="round"
className={cn('stroke-secondary transition-colors ease-linear')} className={cn("stroke-secondary transition-colors ease-linear")}
/> />
{currentValue >= 0 && ( {currentValue >= 0 && (
<circle <circle
@ -70,13 +70,13 @@ const ProgressCircle: FC<ProgressCircleProps> = ({
stroke="" stroke=""
strokeLinecap="round" strokeLinecap="round"
className={cn( className={cn(
'stroke-primary transition-colors ease-linear', "stroke-primary transition-colors ease-linear",
showAnimation ? 'transition-all duration-300 ease-in-out' : '' showAnimation ? "transition-all duration-300 ease-in-out" : ""
)} )}
/> />
)} )}
</svg> </svg>
<div className={cn('absolute flex')}>{children}</div> <div className={cn("absolute flex")}>{children}</div>
</div> </div>
); );
}; };

View File

@ -1,7 +1,7 @@
import * as React from "react" import * as ProgressPrimitive from "@radix-ui/react-progress";
import * as ProgressPrimitive from "@radix-ui/react-progress" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Progress({ function Progress({
className, className,
@ -23,7 +23,7 @@ function Progress({
style={{ transform: `translateX(-${100 - (value || 0)}%)` }} style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
/> />
</ProgressPrimitive.Root> </ProgressPrimitive.Root>
) );
} }
export { Progress } export { Progress };

View File

@ -1,10 +1,10 @@
"use client" "use client";
import * as React from "react" import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group" import { CircleIcon } from "lucide-react";
import { CircleIcon } from "lucide-react" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function RadioGroup({ function RadioGroup({
className, className,
@ -16,7 +16,7 @@ function RadioGroup({
className={cn("grid gap-3", className)} className={cn("grid gap-3", className)}
{...props} {...props}
/> />
) );
} }
function RadioGroupItem({ function RadioGroupItem({
@ -39,7 +39,7 @@ function RadioGroupItem({
<CircleIcon className="fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" /> <CircleIcon className="fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" />
</RadioGroupPrimitive.Indicator> </RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item> </RadioGroupPrimitive.Item>
) );
} }
export { RadioGroup, RadioGroupItem } export { RadioGroup, RadioGroupItem };

View File

@ -1,8 +1,8 @@
import * as React from "react" import { GripVerticalIcon } from "lucide-react";
import { GripVerticalIcon } from "lucide-react" import * as React from "react";
import * as ResizablePrimitive from "react-resizable-panels" import * as ResizablePrimitive from "react-resizable-panels";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function ResizablePanelGroup({ function ResizablePanelGroup({
className, className,
@ -17,13 +17,13 @@ function ResizablePanelGroup({
)} )}
{...props} {...props}
/> />
) );
} }
function ResizablePanel({ function ResizablePanel({
...props ...props
}: React.ComponentProps<typeof ResizablePrimitive.Panel>) { }: React.ComponentProps<typeof ResizablePrimitive.Panel>) {
return <ResizablePrimitive.Panel data-slot="resizable-panel" {...props} /> return <ResizablePrimitive.Panel data-slot="resizable-panel" {...props} />;
} }
function ResizableHandle({ function ResizableHandle({
@ -31,7 +31,7 @@ function ResizableHandle({
className, className,
...props ...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & { }: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
withHandle?: boolean withHandle?: boolean;
}) { }) {
return ( return (
<ResizablePrimitive.PanelResizeHandle <ResizablePrimitive.PanelResizeHandle
@ -48,7 +48,7 @@ function ResizableHandle({
</div> </div>
)} )}
</ResizablePrimitive.PanelResizeHandle> </ResizablePrimitive.PanelResizeHandle>
) );
} }
export { ResizablePanelGroup, ResizablePanel, ResizableHandle } export { ResizablePanelGroup, ResizablePanel, ResizableHandle };

View File

@ -1,9 +1,9 @@
"use client" "use client";
import * as React from "react" import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function ScrollArea({ function ScrollArea({
className, className,
@ -25,7 +25,7 @@ function ScrollArea({
<ScrollBar /> <ScrollBar />
<ScrollAreaPrimitive.Corner /> <ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root> </ScrollAreaPrimitive.Root>
) );
} }
function ScrollBar({ function ScrollBar({
@ -52,7 +52,7 @@ function ScrollBar({
className="bg-border relative flex-1 rounded-full" className="bg-border relative flex-1 rounded-full"
/> />
</ScrollAreaPrimitive.ScrollAreaScrollbar> </ScrollAreaPrimitive.ScrollAreaScrollbar>
) );
} }
export { ScrollArea, ScrollBar } export { ScrollArea, ScrollBar };

View File

@ -1,25 +1,25 @@
import * as React from "react" import * as SelectPrimitive from "@radix-ui/react-select";
import * as SelectPrimitive from "@radix-ui/react-select" import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Select({ function Select({
...props ...props
}: React.ComponentProps<typeof SelectPrimitive.Root>) { }: React.ComponentProps<typeof SelectPrimitive.Root>) {
return <SelectPrimitive.Root data-slot="select" {...props} /> return <SelectPrimitive.Root data-slot="select" {...props} />;
} }
function SelectGroup({ function SelectGroup({
...props ...props
}: React.ComponentProps<typeof SelectPrimitive.Group>) { }: React.ComponentProps<typeof SelectPrimitive.Group>) {
return <SelectPrimitive.Group data-slot="select-group" {...props} /> return <SelectPrimitive.Group data-slot="select-group" {...props} />;
} }
function SelectValue({ function SelectValue({
...props ...props
}: React.ComponentProps<typeof SelectPrimitive.Value>) { }: React.ComponentProps<typeof SelectPrimitive.Value>) {
return <SelectPrimitive.Value data-slot="select-value" {...props} /> return <SelectPrimitive.Value data-slot="select-value" {...props} />;
} }
function SelectTrigger({ function SelectTrigger({
@ -28,7 +28,7 @@ function SelectTrigger({
children, children,
...props ...props
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & { }: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
size?: "sm" | "default" size?: "sm" | "default";
}) { }) {
return ( return (
<SelectPrimitive.Trigger <SelectPrimitive.Trigger
@ -45,7 +45,7 @@ function SelectTrigger({
<ChevronDownIcon className="size-4 opacity-50" /> <ChevronDownIcon className="size-4 opacity-50" />
</SelectPrimitive.Icon> </SelectPrimitive.Icon>
</SelectPrimitive.Trigger> </SelectPrimitive.Trigger>
) );
} }
function SelectContent({ function SelectContent({
@ -80,7 +80,7 @@ function SelectContent({
<SelectScrollDownButton /> <SelectScrollDownButton />
</SelectPrimitive.Content> </SelectPrimitive.Content>
</SelectPrimitive.Portal> </SelectPrimitive.Portal>
) );
} }
function SelectLabel({ function SelectLabel({
@ -93,7 +93,7 @@ function SelectLabel({
className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)} className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
{...props} {...props}
/> />
) );
} }
function SelectItem({ function SelectItem({
@ -117,7 +117,7 @@ function SelectItem({
</span> </span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText> <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item> </SelectPrimitive.Item>
) );
} }
function SelectSeparator({ function SelectSeparator({
@ -130,7 +130,7 @@ function SelectSeparator({
className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)} className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
{...props} {...props}
/> />
) );
} }
function SelectScrollUpButton({ function SelectScrollUpButton({
@ -148,7 +148,7 @@ function SelectScrollUpButton({
> >
<ChevronUpIcon className="size-4" /> <ChevronUpIcon className="size-4" />
</SelectPrimitive.ScrollUpButton> </SelectPrimitive.ScrollUpButton>
) );
} }
function SelectScrollDownButton({ function SelectScrollDownButton({
@ -166,7 +166,7 @@ function SelectScrollDownButton({
> >
<ChevronDownIcon className="size-4" /> <ChevronDownIcon className="size-4" />
</SelectPrimitive.ScrollDownButton> </SelectPrimitive.ScrollDownButton>
) );
} }
export { export {
@ -180,4 +180,4 @@ export {
SelectSeparator, SelectSeparator,
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} };

View File

@ -1,9 +1,9 @@
"use client" "use client";
import * as React from "react" import * as SeparatorPrimitive from "@radix-ui/react-separator";
import * as SeparatorPrimitive from "@radix-ui/react-separator" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Separator({ function Separator({
className, className,
@ -22,7 +22,7 @@ function Separator({
)} )}
{...props} {...props}
/> />
) );
} }
export { Separator } export { Separator };

View File

@ -1,29 +1,29 @@
import * as React from "react" import * as SheetPrimitive from "@radix-ui/react-dialog";
import * as SheetPrimitive from "@radix-ui/react-dialog" import { XIcon } from "lucide-react";
import { XIcon } from "lucide-react" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) { function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
return <SheetPrimitive.Root data-slot="sheet" {...props} /> return <SheetPrimitive.Root data-slot="sheet" {...props} />;
} }
function SheetTrigger({ function SheetTrigger({
...props ...props
}: React.ComponentProps<typeof SheetPrimitive.Trigger>) { }: React.ComponentProps<typeof SheetPrimitive.Trigger>) {
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} /> return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />;
} }
function SheetClose({ function SheetClose({
...props ...props
}: React.ComponentProps<typeof SheetPrimitive.Close>) { }: React.ComponentProps<typeof SheetPrimitive.Close>) {
return <SheetPrimitive.Close data-slot="sheet-close" {...props} /> return <SheetPrimitive.Close data-slot="sheet-close" {...props} />;
} }
function SheetPortal({ function SheetPortal({
...props ...props
}: React.ComponentProps<typeof SheetPrimitive.Portal>) { }: React.ComponentProps<typeof SheetPrimitive.Portal>) {
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} /> return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />;
} }
function SheetOverlay({ function SheetOverlay({
@ -39,7 +39,7 @@ function SheetOverlay({
)} )}
{...props} {...props}
/> />
) );
} }
function SheetContent({ function SheetContent({
@ -48,7 +48,7 @@ function SheetContent({
side = "right", side = "right",
...props ...props
}: React.ComponentProps<typeof SheetPrimitive.Content> & { }: React.ComponentProps<typeof SheetPrimitive.Content> & {
side?: "top" | "right" | "bottom" | "left" side?: "top" | "right" | "bottom" | "left";
}) { }) {
return ( return (
<SheetPortal> <SheetPortal>
@ -76,7 +76,7 @@ function SheetContent({
</SheetPrimitive.Close> </SheetPrimitive.Close>
</SheetPrimitive.Content> </SheetPrimitive.Content>
</SheetPortal> </SheetPortal>
) );
} }
function SheetHeader({ className, ...props }: React.ComponentProps<"div">) { function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
@ -86,7 +86,7 @@ function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
className={cn("flex flex-col gap-1.5 p-4", className)} className={cn("flex flex-col gap-1.5 p-4", className)}
{...props} {...props}
/> />
) );
} }
function SheetFooter({ className, ...props }: React.ComponentProps<"div">) { function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
@ -96,7 +96,7 @@ function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
className={cn("mt-auto flex flex-col gap-2 p-4", className)} className={cn("mt-auto flex flex-col gap-2 p-4", className)}
{...props} {...props}
/> />
) );
} }
function SheetTitle({ function SheetTitle({
@ -109,7 +109,7 @@ function SheetTitle({
className={cn("text-foreground font-semibold", className)} className={cn("text-foreground font-semibold", className)}
{...props} {...props}
/> />
) );
} }
function SheetDescription({ function SheetDescription({
@ -122,7 +122,7 @@ function SheetDescription({
className={cn("text-muted-foreground text-sm", className)} className={cn("text-muted-foreground text-sm", className)}
{...props} {...props}
/> />
) );
} }
export { export {
@ -134,4 +134,4 @@ export {
SheetFooter, SheetFooter,
SheetTitle, SheetTitle,
SheetDescription, SheetDescription,
} };

View File

@ -5,25 +5,25 @@ import { VariantProps, cva } from "class-variance-authority";
import { PanelLeftIcon } from "lucide-react"; import { PanelLeftIcon } from "lucide-react";
import * as React from "react"; import * as React from "react";
import { Button } from "@/components/ui/button"; import { Button } from "@/views/components/ui/button";
import { Input } from "@/components/ui/input"; import { Input } from "@/views/components/ui/input";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/views/components/ui/separator";
import { import {
Sheet, Sheet,
SheetContent, SheetContent,
SheetDescription, SheetDescription,
SheetHeader, SheetHeader,
SheetTitle, SheetTitle,
} from "@/components/ui/sheet"; } from "@/views/components/ui/sheet";
import { Skeleton } from "@/components/ui/skeleton"; import { Skeleton } from "@/views/components/ui/skeleton";
import { import {
Tooltip, Tooltip,
TooltipContent, TooltipContent,
TooltipProvider, TooltipProvider,
TooltipTrigger, TooltipTrigger,
} from "@/components/ui/tooltip"; } from "@/views/components/ui/tooltip";
import { useIsMobile } from "@/infra/hooks/use-mobile"; import { useIsMobile } from "@/views/hooks/use-mobile";
import { cn } from "@/infra/styles/utils"; import { cn } from "@/views/utils";
const SIDEBAR_COOKIE_NAME = "sidebar_state"; const SIDEBAR_COOKIE_NAME = "sidebar_state";
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
@ -83,7 +83,7 @@ function SidebarProvider({
} }
// This sets the cookie to keep the sidebar state. // This sets the cookie to keep the sidebar state.
// TODO: FIXME // TODO: FIX THIS
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`; document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
}, },
[setOpenProp, open] [setOpenProp, open]

View File

@ -1,7 +1,7 @@
import { cn } from "@/infra/styles/utils"; import { cn } from "@/views/utils";
import type React from "react"; import { ComponentProps } from "react";
function Skeleton({ className, ...props }: React.ComponentProps<"div">) { function Skeleton({ className, ...props }: ComponentProps<"div">) {
return ( return (
<div <div
data-slot="skeleton" data-slot="skeleton"

View File

@ -1,9 +1,9 @@
"use client" "use client";
import * as React from "react" import * as SliderPrimitive from "@radix-ui/react-slider";
import * as SliderPrimitive from "@radix-ui/react-slider" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Slider({ function Slider({
className, className,
@ -21,7 +21,7 @@ function Slider({
? defaultValue ? defaultValue
: [min, max], : [min, max],
[value, defaultValue, min, max] [value, defaultValue, min, max]
) );
return ( return (
<SliderPrimitive.Root <SliderPrimitive.Root
@ -57,7 +57,7 @@ function Slider({
/> />
))} ))}
</SliderPrimitive.Root> </SliderPrimitive.Root>
) );
} }
export { Slider } export { Slider };

View File

@ -1,24 +1,24 @@
import { cn } from '@/infra/styles/utils'; import { cn } from "@/views/utils";
import { import {
Loader, Loader,
LoaderCircle, LoaderCircle,
LoaderPinwheel, LoaderPinwheel,
type LucideProps, type LucideProps,
} from 'lucide-react'; } from "lucide-react";
export type SpinnerVariantProps = Omit<SpinnerProps, 'variant'>; export type SpinnerVariantProps = Omit<SpinnerProps, "variant">;
const Default = ({ className, ...props }: SpinnerVariantProps) => { const Default = ({ className, ...props }: SpinnerVariantProps) => {
return <Loader className={cn('animate-spin', className)} {...props} />; return <Loader className={cn("animate-spin", className)} {...props} />;
}; };
const Circle = ({ className, ...props }: SpinnerVariantProps) => { const Circle = ({ className, ...props }: SpinnerVariantProps) => {
return <LoaderCircle className={cn('animate-spin', className)} {...props} />; return <LoaderCircle className={cn("animate-spin", className)} {...props} />;
}; };
const Pinwheel = ({ className, ...props }: SpinnerVariantProps) => { const Pinwheel = ({ className, ...props }: SpinnerVariantProps) => {
return ( return (
<LoaderPinwheel className={cn('animate-spin', className)} {...props} /> <LoaderPinwheel className={cn("animate-spin", className)} {...props} />
); );
}; };
@ -32,16 +32,16 @@ const CircleFilled = ({
<div className="absolute inset-0 rotate-180"> <div className="absolute inset-0 rotate-180">
<LoaderCircle <LoaderCircle
className={cn( className={cn(
'animate-spin', "animate-spin",
className, className,
'text-foreground opacity-20' "text-foreground opacity-20"
)} )}
size={size} size={size}
{...props} {...props}
/> />
</div> </div>
<LoaderCircle <LoaderCircle
className={cn('relative animate-spin', className)} className={cn("relative animate-spin", className)}
size={size} size={size}
{...props} {...props}
/> />
@ -233,8 +233,8 @@ const Infinite = ({ size = 24, ...props }: SpinnerVariantProps) => (
d="M24.3 30C11.4 30 5 43.3 5 50s6.4 20 19.3 20c19.3 0 32.1-40 51.4-40 C88.6 30 95 43.3 95 50s-6.4 20-19.3 20C56.4 70 43.6 30 24.3 30z" d="M24.3 30C11.4 30 5 43.3 5 50s6.4 20 19.3 20c19.3 0 32.1-40 51.4-40 C88.6 30 95 43.3 95 50s-6.4 20-19.3 20C56.4 70 43.6 30 24.3 30z"
strokeLinecap="round" strokeLinecap="round"
style={{ style={{
transform: 'scale(0.8)', transform: "scale(0.8)",
transformOrigin: '50px 50px', transformOrigin: "50px 50px",
}} }}
> >
<animate <animate
@ -250,31 +250,31 @@ const Infinite = ({ size = 24, ...props }: SpinnerVariantProps) => (
export type SpinnerProps = LucideProps & { export type SpinnerProps = LucideProps & {
variant?: variant?:
| 'default' | "default"
| 'circle' | "circle"
| 'pinwheel' | "pinwheel"
| 'circle-filled' | "circle-filled"
| 'ellipsis' | "ellipsis"
| 'ring' | "ring"
| 'bars' | "bars"
| 'infinite'; | "infinite";
}; };
export const Spinner = ({ variant, ...props }: SpinnerProps) => { export const Spinner = ({ variant, ...props }: SpinnerProps) => {
switch (variant) { switch (variant) {
case 'circle': case "circle":
return <Circle {...props} />; return <Circle {...props} />;
case 'pinwheel': case "pinwheel":
return <Pinwheel {...props} />; return <Pinwheel {...props} />;
case 'circle-filled': case "circle-filled":
return <CircleFilled {...props} />; return <CircleFilled {...props} />;
case 'ellipsis': case "ellipsis":
return <Ellipsis {...props} />; return <Ellipsis {...props} />;
case 'ring': case "ring":
return <Ring {...props} />; return <Ring {...props} />;
case 'bars': case "bars":
return <Bars {...props} />; return <Bars {...props} />;
case 'infinite': case "infinite":
return <Infinite {...props} />; return <Infinite {...props} />;
default: default:
return <Default {...props} />; return <Default {...props} />;

View File

@ -1,9 +1,9 @@
"use client" "use client";
import * as React from "react" import * as SwitchPrimitive from "@radix-ui/react-switch";
import * as SwitchPrimitive from "@radix-ui/react-switch" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Switch({ function Switch({
className, className,
@ -25,7 +25,7 @@ function Switch({
)} )}
/> />
</SwitchPrimitive.Root> </SwitchPrimitive.Root>
) );
} }
export { Switch } export { Switch };

View File

@ -1,6 +1,6 @@
import * as React from "react" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Table({ className, ...props }: React.ComponentProps<"table">) { function Table({ className, ...props }: React.ComponentProps<"table">) {
return ( return (
@ -14,7 +14,7 @@ function Table({ className, ...props }: React.ComponentProps<"table">) {
{...props} {...props}
/> />
</div> </div>
) );
} }
function TableHeader({ className, ...props }: React.ComponentProps<"thead">) { function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
@ -24,7 +24,7 @@ function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
className={cn("[&_tr]:border-b", className)} className={cn("[&_tr]:border-b", className)}
{...props} {...props}
/> />
) );
} }
function TableBody({ className, ...props }: React.ComponentProps<"tbody">) { function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
@ -34,7 +34,7 @@ function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
className={cn("[&_tr:last-child]:border-0", className)} className={cn("[&_tr:last-child]:border-0", className)}
{...props} {...props}
/> />
) );
} }
function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) { function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
@ -47,7 +47,7 @@ function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
)} )}
{...props} {...props}
/> />
) );
} }
function TableRow({ className, ...props }: React.ComponentProps<"tr">) { function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
@ -60,7 +60,7 @@ function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
)} )}
{...props} {...props}
/> />
) );
} }
function TableHead({ className, ...props }: React.ComponentProps<"th">) { function TableHead({ className, ...props }: React.ComponentProps<"th">) {
@ -73,7 +73,7 @@ function TableHead({ className, ...props }: React.ComponentProps<"th">) {
)} )}
{...props} {...props}
/> />
) );
} }
function TableCell({ className, ...props }: React.ComponentProps<"td">) { function TableCell({ className, ...props }: React.ComponentProps<"td">) {
@ -86,7 +86,7 @@ function TableCell({ className, ...props }: React.ComponentProps<"td">) {
)} )}
{...props} {...props}
/> />
) );
} }
function TableCaption({ function TableCaption({
@ -99,7 +99,7 @@ function TableCaption({
className={cn("text-muted-foreground mt-4 text-sm", className)} className={cn("text-muted-foreground mt-4 text-sm", className)}
{...props} {...props}
/> />
) );
} }
export { export {
@ -111,4 +111,4 @@ export {
TableRow, TableRow,
TableCell, TableCell,
TableCaption, TableCaption,
} };

View File

@ -1,9 +1,9 @@
"use client" "use client";
import * as React from "react" import * as TabsPrimitive from "@radix-ui/react-tabs";
import * as TabsPrimitive from "@radix-ui/react-tabs" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Tabs({ function Tabs({
className, className,
@ -15,7 +15,7 @@ function Tabs({
className={cn("flex flex-col gap-2", className)} className={cn("flex flex-col gap-2", className)}
{...props} {...props}
/> />
) );
} }
function TabsList({ function TabsList({
@ -31,7 +31,7 @@ function TabsList({
)} )}
{...props} {...props}
/> />
) );
} }
function TabsTrigger({ function TabsTrigger({
@ -47,7 +47,7 @@ function TabsTrigger({
)} )}
{...props} {...props}
/> />
) );
} }
function TabsContent({ function TabsContent({
@ -60,7 +60,7 @@ function TabsContent({
className={cn("flex-1 outline-none", className)} className={cn("flex-1 outline-none", className)}
{...props} {...props}
/> />
) );
} }
export { Tabs, TabsList, TabsTrigger, TabsContent } export { Tabs, TabsList, TabsTrigger, TabsContent };

View File

@ -1,6 +1,6 @@
import * as React from "react" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
return ( return (
@ -12,7 +12,7 @@ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
)} )}
{...props} {...props}
/> />
) );
} }
export { Textarea } export { Textarea };

View File

@ -1,18 +1,18 @@
"use client" "use client";
import * as React from "react" import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group" import { type VariantProps } from "class-variance-authority";
import { type VariantProps } from "class-variance-authority" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { toggleVariants } from "@/views/components/ui/toggle";
import { toggleVariants } from "@/components/ui/toggle" import { cn } from "@/views/utils";
const ToggleGroupContext = React.createContext< const ToggleGroupContext = React.createContext<
VariantProps<typeof toggleVariants> VariantProps<typeof toggleVariants>
>({ >({
size: "default", size: "default",
variant: "default", variant: "default",
}) });
function ToggleGroup({ function ToggleGroup({
className, className,
@ -37,7 +37,7 @@ function ToggleGroup({
{children} {children}
</ToggleGroupContext.Provider> </ToggleGroupContext.Provider>
</ToggleGroupPrimitive.Root> </ToggleGroupPrimitive.Root>
) );
} }
function ToggleGroupItem({ function ToggleGroupItem({
@ -48,7 +48,7 @@ function ToggleGroupItem({
...props ...props
}: React.ComponentProps<typeof ToggleGroupPrimitive.Item> & }: React.ComponentProps<typeof ToggleGroupPrimitive.Item> &
VariantProps<typeof toggleVariants>) { VariantProps<typeof toggleVariants>) {
const context = React.useContext(ToggleGroupContext) const context = React.useContext(ToggleGroupContext);
return ( return (
<ToggleGroupPrimitive.Item <ToggleGroupPrimitive.Item
@ -67,7 +67,7 @@ function ToggleGroupItem({
> >
{children} {children}
</ToggleGroupPrimitive.Item> </ToggleGroupPrimitive.Item>
) );
} }
export { ToggleGroup, ToggleGroupItem } export { ToggleGroup, ToggleGroupItem };

View File

@ -1,8 +1,8 @@
import * as React from "react" import * as TogglePrimitive from "@radix-ui/react-toggle";
import * as TogglePrimitive from "@radix-ui/react-toggle" import { type VariantProps, cva } from "class-variance-authority";
import { cva, type VariantProps } from "class-variance-authority" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
const toggleVariants = cva( const toggleVariants = cva(
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap", "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap",
@ -24,7 +24,7 @@ const toggleVariants = cva(
size: "default", size: "default",
}, },
} }
) );
function Toggle({ function Toggle({
className, className,
@ -39,7 +39,7 @@ function Toggle({
className={cn(toggleVariants({ variant, size, className }))} className={cn(toggleVariants({ variant, size, className }))}
{...props} {...props}
/> />
) );
} }
export { Toggle, toggleVariants } export { Toggle, toggleVariants };

View File

@ -1,7 +1,7 @@
import * as React from "react" import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import * as TooltipPrimitive from "@radix-ui/react-tooltip" import * as React from "react";
import { cn } from "@/infra/styles/utils" import { cn } from "@/views/utils";
function TooltipProvider({ function TooltipProvider({
delayDuration = 0, delayDuration = 0,
@ -13,7 +13,7 @@ function TooltipProvider({
delayDuration={delayDuration} delayDuration={delayDuration}
{...props} {...props}
/> />
) );
} }
function Tooltip({ function Tooltip({
@ -23,13 +23,13 @@ function Tooltip({
<TooltipProvider> <TooltipProvider>
<TooltipPrimitive.Root data-slot="tooltip" {...props} /> <TooltipPrimitive.Root data-slot="tooltip" {...props} />
</TooltipProvider> </TooltipProvider>
) );
} }
function TooltipTrigger({ function TooltipTrigger({
...props ...props
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) { }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} /> return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
} }
function TooltipContent({ function TooltipContent({
@ -53,7 +53,7 @@ function TooltipContent({
<TooltipPrimitive.Arrow className="bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" /> <TooltipPrimitive.Arrow className="bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
</TooltipPrimitive.Content> </TooltipPrimitive.Content>
</TooltipPrimitive.Portal> </TooltipPrimitive.Portal>
) );
} }
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };

View File

@ -0,0 +1,19 @@
import * as React from "react"
const MOBILE_BREAKPOINT = 768
export function useIsMobile() {
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
React.useEffect(() => {
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
const onChange = () => {
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
}
mql.addEventListener("change", onChange)
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
return () => mql.removeEventListener("change", onChange)
}, [])
return !!isMobile
}

View File

@ -1,4 +1,4 @@
import { AppNotFoundComponent } from '@/components/layout/app-not-found'; import { AppNotFoundComponent } from '@/views/components/layout/app-not-found';
import { createFileRoute } from '@tanstack/react-router'; import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/404')({ export const Route = createFileRoute('/404')({

View File

@ -11,23 +11,17 @@ export const Route = createLazyFileRoute('/_app/playground/graphql-api')({
}); });
function PlaygroundGraphQLApiRouteComponent() { function PlaygroundGraphQLApiRouteComponent() {
const { authContext } = useAuth(); const { authProvider } = useAuth();
const fetcher: Fetcher = useCallback( const fetcher: Fetcher = useCallback(
async (props) => { async (props) => {
const accessToken = await firstValueFrom( const authHeaders = await firstValueFrom(authProvider.getAuthHeaders());
authContext.authService.getAccessToken()
);
return createGraphiQLFetcher({ return createGraphiQLFetcher({
url: '/api/graphql', url: '/api/graphql',
headers: accessToken headers: authHeaders,
? {
Authorization: `Bearer ${accessToken}`,
}
: undefined,
})(props); })(props);
}, },
[authContext.authService.getAccessToken] [authProvider]
); );
return ( return (

View File

@ -1,5 +1,5 @@
import { AppSkeleton } from '@/components/layout/app-skeleton';
import { buildLeafRouteStaticData } from '@/infra/routes/utils'; import { buildLeafRouteStaticData } from '@/infra/routes/utils';
import { AppSkeleton } from '@/views/components/layout/app-skeleton';
import { createFileRoute } from '@tanstack/react-router'; import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/_app/playground/graphql-api')({ export const Route = createFileRoute('/_app/playground/graphql-api')({

View File

@ -1,5 +1,5 @@
import { beforeLoadGuard } from '@/app/auth/guard'; import { beforeLoadGuard } from '@/app/auth/guard';
import { AppAside } from '@/components/layout/app-layout'; import { AppAside } from '@/views/components/layout/app-layout';
import { Outlet, createFileRoute } from '@tanstack/react-router'; import { Outlet, createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/_app')({ export const Route = createFileRoute('/_app')({

View File

@ -1,5 +1,6 @@
import { useAuth } from '@/app/auth/hooks'; import { useAuth } from '@/app/auth/hooks';
import { Button } from '@/components/ui/button'; import type { RouteStateDataOption } from '@/infra/routes/traits';
import { Button } from '@/views/components/ui/button';
import { import {
Card, Card,
CardContent, CardContent,
@ -7,7 +8,7 @@ import {
CardFooter, CardFooter,
CardHeader, CardHeader,
CardTitle, CardTitle,
} from '@/components/ui/card'; } from '@/views/components/ui/card';
import { import {
Form, Form,
FormControl, FormControl,
@ -16,17 +17,17 @@ import {
FormItem, FormItem,
FormLabel, FormLabel,
FormMessage, FormMessage,
} from '@/components/ui/form'; } from '@/views/components/ui/form';
import { Input } from '@/components/ui/input'; import { Input } from '@/views/components/ui/input';
import { import {
Select, Select,
SelectContent, SelectContent,
SelectItem, SelectItem,
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from '@/components/ui/select'; } from '@/views/components/ui/select';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/views/components/ui/switch';
import type { RouteStateDataOption } from '@/infra/routes/traits'; import { gql, useMutation } from '@apollo/client';
import { createFileRoute } from '@tanstack/react-router'; import { createFileRoute } from '@tanstack/react-router';
import { useNavigate } from '@tanstack/react-router'; import { useNavigate } from '@tanstack/react-router';
import { useState } from 'react'; import { useState } from 'react';
@ -47,6 +48,18 @@ type SubscriptionFormValues = {
enabled: boolean; enabled: boolean;
}; };
const CREATE_SUBSCRIPTION_MUTATION = gql`
mutation CreateSubscription($input: SubscriptionsInsertInput!) {
subscriptionsCreateOne(data: $input) {
id
displayName
sourceUrl
enabled
category
}
}
`;
function SubscriptionCreateRouteComponent() { function SubscriptionCreateRouteComponent() {
const { userData } = useAuth(); const { userData } = useAuth();
console.log(JSON.stringify(userData, null, 2)); console.log(JSON.stringify(userData, null, 2));
@ -61,21 +74,12 @@ function SubscriptionCreateRouteComponent() {
}, },
}); });
const [createSubscription] = useMutation(CREATE_SUBSCRIPTION_MUTATION);
const onSubmit = async (data: SubscriptionFormValues) => { const onSubmit = async (data: SubscriptionFormValues) => {
try { try {
setIsSubmitting(true); setIsSubmitting(true);
const requestData = { const response = await createSubscription({
query: `
mutation CreateSubscription($input: SubscriptionsInsertInput!) {
subscriptionsCreateOne(data: $input) {
id
displayName
sourceUrl
enabled
category
}
}
`,
variables: { variables: {
input: { input: {
category: data.category, category: data.category,
@ -84,18 +88,11 @@ function SubscriptionCreateRouteComponent() {
enabled: data.enabled, enabled: data.enabled,
}, },
}, },
};
const response = await fetch('/api/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestData),
}); });
const responseData = await response.json(); if (response.errors) {
if (responseData.errors) {
throw new Error( throw new Error(
responseData.errors[0]?.message || 'Failed to create subscription' response.errors[0]?.message || 'Failed to create subscription'
); );
} }

View File

@ -1,8 +1,9 @@
import { AppAuthMethod, AuthMethodEnum } from '@/app/auth/config'; import { authContextFromInjector } from '@/app/auth/context';
import { useAuth } from '@/app/auth/hooks'; import { useAuth } from '@/app/auth/hooks';
import { ProLink } from '@/components/ui/pro-link'; import { AUTH_METHOD } from '@/infra/auth/defs';
import { Spinner } from '@/components/ui/spinner'; import { ProLink } from '@/views/components/ui/pro-link';
import { createFileRoute } from '@tanstack/react-router'; import { Spinner } from '@/views/components/ui/spinner';
import { createFileRoute, redirect } from '@tanstack/react-router';
import { useAtom } from 'jotai/react'; import { useAtom } from 'jotai/react';
import { atomWithObservable } from 'jotai/utils'; import { atomWithObservable } from 'jotai/utils';
import { EventTypes } from 'oidc-client-rx'; import { EventTypes } from 'oidc-client-rx';
@ -11,18 +12,24 @@ import { filter, map } from 'rxjs';
export const Route = createFileRoute('/auth/oidc/callback')({ export const Route = createFileRoute('/auth/oidc/callback')({
component: OidcCallbackRouteComponent, component: OidcCallbackRouteComponent,
beforeLoad: ({ context }) => {
const { authProvider } = authContextFromInjector(context.injector);
if (authProvider.authMethod !== AUTH_METHOD.OIDC) {
throw redirect({ to: '/' });
}
},
}); });
function OidcCallbackRouteComponent() { function OidcCallbackRouteComponent() {
const { authContext } = useAuth(); const { authService } = useAuth();
const isLoading = useAtom( const isLoading = useAtom(
useMemo( useMemo(
() => () =>
atomWithObservable(() => atomWithObservable(() =>
authContext.checkAuthResultEvent$.pipe(map(Boolean)) authService.checkAuthResultEvent$.pipe(map(Boolean))
), ),
[authContext.checkAuthResultEvent$] [authService.checkAuthResultEvent$]
) )
); );
@ -30,7 +37,7 @@ function OidcCallbackRouteComponent() {
useMemo( useMemo(
() => () =>
atomWithObservable(() => atomWithObservable(() =>
authContext.checkAuthResultEvent$.pipe( authService.checkAuthResultEvent$.pipe(
filter( filter(
( (
e e
@ -42,7 +49,7 @@ function OidcCallbackRouteComponent() {
map((e) => e.value) map((e) => e.value)
) )
), ),
[authContext.checkAuthResultEvent$] [authService.checkAuthResultEvent$]
) )
); );
@ -64,27 +71,19 @@ function OidcCallbackRouteComponent() {
<div className="flex justify-center font-bold text-4xl tracking-tighter sm:text-5xl"> <div className="flex justify-center font-bold text-4xl tracking-tighter sm:text-5xl">
<Spinner variant="circle-filled" size="48" /> <Spinner variant="circle-filled" size="48" />
</div> </div>
{AppAuthMethod === AuthMethodEnum.OIDC ? ( {isLoading && (
<>
{isLoading && (
<p className="text-gray-500">
Processing OIDC authentication callback...
</p>
)}
{checkAuthResultError && (
<p className="text-gray-500">
Failed to handle OIDC callback: {checkAuthResultError}
</p>
)}
{!isLoading && !checkAuthResultError && (
<p className="text-gray-500">
Succeed to handle OIDC authentication callback.
</p>
)}
</>
) : (
<p className="text-gray-500"> <p className="text-gray-500">
Error: Current authentication method is not OIDC! Processing OIDC authentication callback...
</p>
)}
{checkAuthResultError && (
<p className="text-gray-500">
Failed to handle OIDC callback: {checkAuthResultError}
</p>
)}
{!isLoading && !checkAuthResultError && (
<p className="text-gray-500">
Succeed to handle OIDC authentication callback.
</p> </p>
)} )}
{renderBackToHome()} {renderBackToHome()}

View File

@ -1,5 +1,5 @@
import { AppAside } from '@/components/layout/app-layout'; import { AppAside } from '@/views/components/layout/app-layout';
import { AppSkeleton } from '@/components/layout/app-skeleton'; import { AppSkeleton } from '@/views/components/layout/app-skeleton';
import { createFileRoute } from '@tanstack/react-router'; import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/')({ export const Route = createFileRoute('/')({

Some files were not shown because too many files have changed in this diff Show More