Compare commits

...

5 Commits

Author SHA1 Message Date
9b874eebf8 . 2025-11-16 20:29:36 +01:00
8089959fd0 Ampliación de opciones 2025-11-16 20:29:30 +01:00
9db84b3999 . 2025-11-16 20:29:18 +01:00
c77705b8b6 Formateo 2025-11-16 20:29:07 +01:00
8d0002bfb4 Solucionado problema de estilos 2025-11-16 20:28:58 +01:00
24 changed files with 345 additions and 290 deletions

View File

@ -1,5 +1,5 @@
{ {
"$schema": "https://biomejs.dev/schemas/2.2.4/schema.json", "$schema": "https://biomejs.dev/schemas/2.3.1/schema.json",
"vcs": { "vcs": {
"enabled": true, "enabled": true,
"clientKind": "git", "clientKind": "git",
@ -108,7 +108,7 @@
"useThrowOnlyError": "error" "useThrowOnlyError": "error"
}, },
"suspicious": { "suspicious": {
"noExplicitAny": "error", "noExplicitAny": "info",
"noDebugger": "error", "noDebugger": "error",
"noDuplicateJsxProps": "error", "noDuplicateJsxProps": "error",
"noDuplicateObjectKeys": "error", "noDuplicateObjectKeys": "error",
@ -209,7 +209,7 @@
"useKeyWithClickEvents": "error", "useKeyWithClickEvents": "error",
"useKeyWithMouseEvents": "error", "useKeyWithMouseEvents": "error",
"useMediaCaption": "error", "useMediaCaption": "error",
"useSemanticElements": "error", "useSemanticElements": "info",
"useValidAnchor": "error", "useValidAnchor": "error",
"useValidAriaProps": "error", "useValidAriaProps": "error",
"useValidAriaValues": "error", "useValidAriaValues": "error",
@ -278,6 +278,9 @@
} }
}, },
"css": { "css": {
"parser": {
"tailwindDirectives": true
},
"formatter": { "formatter": {
"enabled": true, "enabled": true,
"indentStyle": "space", "indentStyle": "space",
@ -349,7 +352,7 @@
} }
}, },
"suspicious": { "suspicious": {
"noExplicitAny": "error" "noExplicitAny": "info"
}, },
"complexity": { "complexity": {
"noExcessiveCognitiveComplexity": { "noExcessiveCognitiveComplexity": {

View File

@ -1 +1 @@
@source "./components"; @source "**/*.{ts,tsx}";

View File

@ -1,2 +1 @@
@source "./components"; @source "**/*.{ts,tsx}";
@source "./pages";

View File

@ -1,44 +1,44 @@
import { FiltersPrimitives } from "./Filter"; import type { FiltersPrimitives } from "./Filter";
import { Filters } from "./Filters"; import { Filters } from "./Filters";
import { InvalidCriteria } from "./InvalidCriteria"; import { InvalidCriteria } from "./InvalidCriteria";
import { Order } from "./Order"; import { Order } from "./Order";
export class Criteria { export class Criteria {
constructor( constructor(
public readonly filters: Filters, public readonly filters: Filters,
public readonly order: Order, public readonly order: Order,
public readonly pageSize: number | null, public readonly pageSize: number | null,
public readonly pageNumber: number | null, public readonly pageNumber: number | null
) { ) {
if (pageNumber !== null && pageSize === null) { if (pageNumber !== null && pageSize === null) {
throw new InvalidCriteria(); throw new InvalidCriteria();
} }
} }
static fromPrimitives( static fromPrimitives(
filters: FiltersPrimitives[], filters: FiltersPrimitives[],
orderBy: string | null, orderBy: string | null,
orderType: string | null, orderType: string | null,
pageSize: number | null, pageSize: number | null,
pageNumber: number | null, pageNumber: number | null
): Criteria { ): Criteria {
return new Criteria( return new Criteria(
Filters.fromPrimitives(filters), Filters.fromPrimitives(filters),
Order.fromPrimitives(orderBy, orderType), Order.fromPrimitives(orderBy, orderType),
pageSize, pageSize,
pageNumber, pageNumber
); );
} }
static withFilters(filters: FiltersPrimitives[]): Criteria { static withFilters(filters: FiltersPrimitives[]): Criteria {
return Criteria.fromPrimitives(filters, null, null, null, null); return Criteria.fromPrimitives(filters, null, null, null, null);
} }
hasOrder(): boolean { hasOrder(): boolean {
return !this.order.isNone(); return !this.order.isNone();
} }
hasFilters(): boolean { hasFilters(): boolean {
return !this.filters.isEmpty(); return !this.filters.isEmpty();
} }
} }

View File

@ -1,17 +1,17 @@
import { FilterField } from "./FilterField"; import type { FilterField } from "./FilterField";
import { FilterOperator } from "./FilterOperator"; import type { FilterOperator } from "./FilterOperator";
import { FilterValue } from "./FilterValue"; import type { FilterValue } from "./FilterValue";
export type FiltersPrimitives = { export type FiltersPrimitives = {
field: string; field: string;
operator: string; operator: string;
value: string; value: string;
}; };
export declare class Filter { export declare class Filter {
readonly field: FilterField; readonly field: FilterField;
readonly operator: FilterOperator; readonly operator: FilterOperator;
readonly value: FilterValue; readonly value: FilterValue;
constructor(field: FilterField, operator: FilterOperator, value: FilterValue); constructor(field: FilterField, operator: FilterOperator, value: FilterValue);
static fromPrimitives(field: string, operator: string, value: string): Filter; static fromPrimitives(field: string, operator: string, value: string): Filter;
toPrimitives(): FiltersPrimitives; toPrimitives(): FiltersPrimitives;
} }
//# sourceMappingURL=Filter.d.ts.map //# sourceMappingURL=Filter.d.ts.map

View File

@ -3,35 +3,35 @@ import { FilterOperator, Operator } from "./FilterOperator";
import { FilterValue } from "./FilterValue"; import { FilterValue } from "./FilterValue";
export type FiltersPrimitives = { export type FiltersPrimitives = {
field: string; field: string;
operator: string; operator: string;
value: string; value: string;
}; };
export class Filter { export class Filter {
readonly field: FilterField; readonly field: FilterField;
readonly operator: FilterOperator; readonly operator: FilterOperator;
readonly value: FilterValue; readonly value: FilterValue;
constructor(field: FilterField, operator: FilterOperator, value: FilterValue) { constructor(field: FilterField, operator: FilterOperator, value: FilterValue) {
this.field = field; this.field = field;
this.operator = operator; this.operator = operator;
this.value = value; this.value = value;
} }
static fromPrimitives(field: string, operator: string, value: string): Filter { static fromPrimitives(field: string, operator: string, value: string): Filter {
return new Filter( return new Filter(
new FilterField(field), new FilterField(field),
new FilterOperator(Operator[operator as keyof typeof Operator]), new FilterOperator(Operator[operator as keyof typeof Operator]),
new FilterValue(value), new FilterValue(value)
); );
} }
toPrimitives(): FiltersPrimitives { toPrimitives(): FiltersPrimitives {
return { return {
field: this.field.value, field: this.field.value,
operator: this.operator.value, operator: this.operator.value,
value: this.value.value, value: this.value.value,
}; };
} }
} }

View File

@ -1,3 +1,3 @@
export class FilterField { export class FilterField {
constructor(public readonly value: string) {} constructor(public readonly value: string) {}
} }

View File

@ -1,42 +1,42 @@
export enum Operator { export enum Operator {
EQUAL = "=", EQUAL = "=",
NOT_EQUAL = "!=", NOT_EQUAL = "!=",
GREATER_THAN = ">", GREATER_THAN = ">",
GREATER_THAN_OR_EQUAL = ">=", GREATER_THAN_OR_EQUAL = ">=",
LOWER_THAN = "<", LOWER_THAN = "<",
LOWER_THAN_OR_EQUAL = "<=", LOWER_THAN_OR_EQUAL = "<=",
CONTAINS = "CONTAINS", CONTAINS = "CONTAINS",
NOT_CONTAINS = "NOT_CONTAINS", NOT_CONTAINS = "NOT_CONTAINS",
} }
export class FilterOperator { export class FilterOperator {
constructor(public readonly value: Operator) {} constructor(public readonly value: Operator) {}
isContains(): boolean { isContains(): boolean {
return this.value.valueOf() === Operator.CONTAINS.valueOf(); return this.value.valueOf() === Operator.CONTAINS.valueOf();
} }
isNotContains(): boolean { isNotContains(): boolean {
return this.value.valueOf() === Operator.NOT_CONTAINS.valueOf(); return this.value.valueOf() === Operator.NOT_CONTAINS.valueOf();
} }
isNotEquals(): boolean { isNotEquals(): boolean {
return this.value.valueOf() === Operator.NOT_EQUAL.valueOf(); return this.value.valueOf() === Operator.NOT_EQUAL.valueOf();
} }
isGreaterThan(): boolean { isGreaterThan(): boolean {
return this.value.valueOf() === Operator.GREATER_THAN.valueOf(); return this.value.valueOf() === Operator.GREATER_THAN.valueOf();
} }
isGreaterThanOrEqual(): boolean { isGreaterThanOrEqual(): boolean {
return this.value.valueOf() === Operator.GREATER_THAN_OR_EQUAL.valueOf(); return this.value.valueOf() === Operator.GREATER_THAN_OR_EQUAL.valueOf();
} }
isLowerThan(): boolean { isLowerThan(): boolean {
return this.value.valueOf() === Operator.LOWER_THAN.valueOf(); return this.value.valueOf() === Operator.LOWER_THAN.valueOf();
} }
isLowerThanOrEqual(): boolean { isLowerThanOrEqual(): boolean {
return this.value.valueOf() === Operator.LOWER_THAN_OR_EQUAL.valueOf(); return this.value.valueOf() === Operator.LOWER_THAN_OR_EQUAL.valueOf();
} }
} }

View File

@ -1,3 +1,3 @@
export class FilterValue { export class FilterValue {
constructor(public readonly value: string) {} constructor(public readonly value: string) {}
} }

View File

@ -1,19 +1,19 @@
import { Filter, FiltersPrimitives } from "./Filter"; import { Filter, type FiltersPrimitives } from "./Filter";
export class Filters { export class Filters {
constructor(public readonly value: Filter[]) {} constructor(public readonly value: Filter[]) {}
static fromPrimitives(filters: FiltersPrimitives[]): Filters { static fromPrimitives(filters: FiltersPrimitives[]): Filters {
return new Filters( return new Filters(
filters.map((filter) => Filter.fromPrimitives(filter.field, filter.operator, filter.value)), filters.map((filter) => Filter.fromPrimitives(filter.field, filter.operator, filter.value))
); );
} }
toPrimitives(): FiltersPrimitives[] { toPrimitives(): FiltersPrimitives[] {
return this.value.map((filter) => filter.toPrimitives()); return this.value.map((filter) => filter.toPrimitives());
} }
isEmpty(): boolean { isEmpty(): boolean {
return this.value.length === 0; return this.value.length === 0;
} }
} }

View File

@ -1,5 +1,5 @@
export class InvalidCriteria extends Error { export class InvalidCriteria extends Error {
constructor() { constructor() {
super("Page size is required when page number is defined"); super("Page size is required when page number is defined");
} }
} }

View File

@ -2,22 +2,22 @@ import { OrderBy } from "./OrderBy";
import { OrderType, OrderTypes } from "./OrderType"; import { OrderType, OrderTypes } from "./OrderType";
export class Order { export class Order {
constructor( constructor(
public readonly orderBy: OrderBy, public readonly orderBy: OrderBy,
public readonly orderType: OrderType, public readonly orderType: OrderType
) {} ) {}
static none(): Order { static none(): Order {
return new Order(new OrderBy(""), new OrderType(OrderTypes.NONE)); return new Order(new OrderBy(""), new OrderType(OrderTypes.NONE));
} }
static fromPrimitives(orderBy: string | null, orderType: string | null): Order { static fromPrimitives(orderBy: string | null, orderType: string | null): Order {
return orderBy !== null return orderBy !== null
? new Order(new OrderBy(orderBy), new OrderType(orderType as OrderTypes)) ? new Order(new OrderBy(orderBy), new OrderType(orderType as OrderTypes))
: Order.none(); : Order.none();
} }
isNone(): boolean { isNone(): boolean {
return this.orderType.isNone(); return this.orderType.isNone();
} }
} }

View File

@ -1,3 +1,3 @@
export class OrderBy { export class OrderBy {
constructor(public readonly value: string) {} constructor(public readonly value: string) {}
} }

View File

@ -1,13 +1,13 @@
export enum OrderTypes { export enum OrderTypes {
ASC = "ASC", ASC = "ASC",
DESC = "DESC", DESC = "DESC",
NONE = "NONE", NONE = "NONE",
} }
export class OrderType { export class OrderType {
constructor(public readonly value: OrderTypes) {} constructor(public readonly value: OrderTypes) {}
isNone(): boolean { isNone(): boolean {
return this.value === OrderTypes.NONE; return this.value === OrderTypes.NONE;
} }
} }

View File

@ -1,4 +1,4 @@
import { Criteria as BaseCriteria, Filters, FiltersPrimitives, Order } from "./codelytv"; import { Criteria as BaseCriteria, Filters, type FiltersPrimitives, Order } from "./codelytv";
import { INITIAL_PAGE_INDEX, INITIAL_PAGE_SIZE } from "./defaults"; import { INITIAL_PAGE_INDEX, INITIAL_PAGE_SIZE } from "./defaults";
export class Criteria extends BaseCriteria { export class Criteria extends BaseCriteria {

View File

@ -1,4 +1,4 @@
import { FiltersPrimitives } from "./codelytv"; import type { FiltersPrimitives } from "./codelytv";
import { Criteria } from "./critera"; import { Criteria } from "./critera";
import { DEFAULT_ORDER, INITIAL_PAGE_INDEX, INITIAL_PAGE_SIZE } from "./defaults"; import { DEFAULT_ORDER, INITIAL_PAGE_INDEX, INITIAL_PAGE_SIZE } from "./defaults";
@ -64,7 +64,7 @@ export class CriteriaFromUrlConverter {
searchParams.forEach((value, key) => { searchParams.forEach((value, key) => {
const match = key.match(/filters\[(\d+)]\[(.+)]/); const match = key.match(/filters\[(\d+)]\[(.+)]/);
if (match) { if (match) {
const index = match[1]; const index = match[1]!;
const property = match[2] as keyof FiltersPrimitives; const property = match[2] as keyof FiltersPrimitives;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!tempFilters[index]) { if (!tempFilters[index]) {

View File

@ -1,5 +1,6 @@
import { FindOptions, Sequelize } from "sequelize"; import type { FindOptions, Sequelize } from "sequelize";
import { Criteria } from "./critera.js";
import type { Criteria } from "./critera.js";
/** /**
* Mapeo lógicofísico de campos. * Mapeo lógicofísico de campos.

View File

@ -35,7 +35,7 @@
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"typescript": "^5.6.0", "typescript": "^5.6.0",
"tailwindcss": "^4.1.5", "tailwindcss": "^4.1.10",
"tsup": "^8.4.0", "tsup": "^8.4.0",
"tw-animate-css": "^1.2.9", "tw-animate-css": "^1.2.9",
"typescript-plugin-css-modules": "^5.1.0", "typescript-plugin-css-modules": "^5.1.0",

View File

@ -9,7 +9,7 @@ import {
DropdownMenuSeparator, DropdownMenuSeparator,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@repo/shadcn-ui/components"; } from "@repo/shadcn-ui/components";
import type { Table } from "@tanstack/react-table"; import type { Column, Table } from "@tanstack/react-table";
import { Settings2 } from "lucide-react"; import { Settings2 } from "lucide-react";
import { useTranslation } from "../../locales/i18n.ts"; import { useTranslation } from "../../locales/i18n.ts";
@ -24,7 +24,7 @@ export function DataTableViewOptions<TData>({ table }: { table: Table<TData> })
{t("components.datatable_view_options.view_button")} {t("components.datatable_view_options.view_button")}
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-[150px]"> <DropdownMenuContent align="end">
<DropdownMenuLabel> <DropdownMenuLabel>
{t("components.datatable_view_options.toggle_columns")} {t("components.datatable_view_options.toggle_columns")}
</DropdownMenuLabel> </DropdownMenuLabel>
@ -36,11 +36,10 @@ export function DataTableViewOptions<TData>({ table }: { table: Table<TData> })
return ( return (
<DropdownMenuCheckboxItem <DropdownMenuCheckboxItem
checked={column.getIsVisible()} checked={column.getIsVisible()}
className="capitalize"
key={column.id} key={column.id}
onCheckedChange={(value) => column.toggleVisibility(!!value)} onCheckedChange={(value) => column.toggleVisibility(!!value)}
> >
{column.id} {getColumnLabel(column)}
</DropdownMenuCheckboxItem> </DropdownMenuCheckboxItem>
); );
})} })}
@ -48,3 +47,19 @@ export function DataTableViewOptions<TData>({ table }: { table: Table<TData> })
</DropdownMenu> </DropdownMenu>
); );
} }
const getColumnLabel = <TData, TValue>(column: Column<TData, TValue>): string => {
let label = String(column.id);
const h = column.columnDef.header;
// header como string literal
if (typeof h === "string") label = h;
// header función → intentar obtener title si lo usas en tus componentes
if (typeof h === "function") {
// tu DataTableColumnHeader recibe `title` como prop → está en column.columnDef.meta
const meta = column.columnDef.meta as { title?: string } | undefined;
label = meta?.title ?? column.id;
}
return label;
};

View File

@ -75,11 +75,12 @@ export interface DataTableProps<TData, TValue> {
meta?: DataTableMeta<TData>; meta?: DataTableMeta<TData>;
// Configuración // Configuración
columnVisibility?: VisibilityState;
readOnly?: boolean; readOnly?: boolean;
enablePagination?: boolean; enablePagination?: boolean;
pageSize?: number; pageSize?: number;
enableRowSelection?: boolean; enableRowSelection?: boolean;
EditorComponent?: React.ComponentType<{ row: TData; index: number; onClose: () => void }>; EditorComponent?: React.ComponentType<{ row?: TData; index: number; onClose: () => void }>;
getRowId?: (originalRow: TData, index: number, parent?: Row<TData>) => string; getRowId?: (originalRow: TData, index: number, parent?: Row<TData>) => string;
@ -99,6 +100,7 @@ export function DataTable<TData, TValue>({
data, data,
meta, meta,
columnVisibility: inititalcolumnVisibility = {},
readOnly = false, readOnly = false,
enablePagination = true, enablePagination = true,
pageSize = 10, pageSize = 10,
@ -119,7 +121,8 @@ export function DataTable<TData, TValue>({
const [rowSelection, setRowSelection] = React.useState({}); const [rowSelection, setRowSelection] = React.useState({});
const [sorting, setSorting] = React.useState<SortingState>([]); const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({}); const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>(inititalcolumnVisibility);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([]); const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([]);
const [colSizes, setColSizes] = React.useState<ColumnSizingState>({}); const [colSizes, setColSizes] = React.useState<ColumnSizingState>({});
const [editIndex, setEditIndex] = React.useState<number | null>(null); const [editIndex, setEditIndex] = React.useState<number | null>(null);

View File

@ -1,4 +1,4 @@
@source "../components"; @source "**/*.{ts,tsx}";
@layer components { @layer components {
/** /**
@ -8,36 +8,28 @@
/* Fondo suave diagonal */ /* Fondo suave diagonal */
.brand-surface-50-br { .brand-surface-50-br {
@apply bg-gradient-to-br from-blue-50 via-violet-50 to-purple-50 @apply bg-gradient-to-br from-blue-50 via-violet-50 to-purple-50 dark:from-blue-950 dark:via-violet-950 dark:to-purple-950;
dark:from-blue-950 dark:via-violet-950 dark:to-purple-950;
} }
.brand-surface-100-br { .brand-surface-100-br {
@apply bg-gradient-to-br from-blue-100 via-violet-100 to-purple-100 @apply bg-gradient-to-br from-blue-100 via-violet-100 to-purple-100 dark:from-blue-900 dark:via-violet-900 dark:to-purple-900;
dark:from-blue-900 dark:via-violet-900 dark:to-purple-900;
} }
/* Fondo suave horizontal */ /* Fondo suave horizontal */
.brand-surface-50-x { .brand-surface-50-x {
@apply bg-gradient-to-r from-blue-50 to-violet-50 @apply bg-gradient-to-r from-blue-50 to-violet-50 hover:from-blue-50 hover:to-violet-50 dark:from-blue-900 dark:to-violet-900;
hover:from-blue-50 hover:to-violet-50
dark:from-blue-900 dark:to-violet-900;
} }
.brand-surface-100-x { .brand-surface-100-x {
@apply bg-gradient-to-r from-blue-100 to-violet-100 @apply bg-gradient-to-r from-blue-100 to-violet-100 hover:from-blue-100 hover:to-violet-100 dark:from-blue-900 dark:to-violet-900;
hover:from-blue-100 hover:to-violet-100
dark:from-blue-900 dark:to-violet-900;
} }
.brand-surface-200-x { .brand-surface-200-x {
@apply bg-gradient-to-r from-blue-200 to-violet-200 @apply bg-gradient-to-r from-blue-200 to-violet-200 dark:from-blue-800 dark:to-violet-800;
dark:from-blue-800 dark:to-violet-800;
} }
/* Gradiente para texto (intenso) */ /* Gradiente para texto (intenso) */
.brand-text-strong-x { .brand-text-strong-x {
@apply bg-gradient-to-r from-blue-600 to-violet-600 bg-clip-text text-transparent antialiased @apply bg-gradient-to-r from-blue-600 to-violet-600 bg-clip-text text-transparent antialiased dark:from-blue-400 dark:to-violet-400;
dark:from-blue-400 dark:to-violet-400;
} }
} }

View File

@ -26,6 +26,7 @@
"devDependencies": { "devDependencies": {
"@biomejs/biome": "^2.3.1", "@biomejs/biome": "^2.3.1",
"@repo/typescript-config": "workspace:*", "@repo/typescript-config": "workspace:*",
"@tailwindcss/cli": "^4.1.5",
"@tailwindcss/postcss": "^4.1.5", "@tailwindcss/postcss": "^4.1.5",
"@turbo/gen": "^2.5.2", "@turbo/gen": "^2.5.2",
"@types/node": "^22.15.12", "@types/node": "^22.15.12",
@ -34,8 +35,7 @@
"postcss": "^8.5.3", "postcss": "^8.5.3",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"typescript": "^5.6.0", "typescript": "^5.6.0"
"tailwindcss": "^4.1.5"
}, },
"dependencies": { "dependencies": {
"@hookform/resolvers": "^5.2.2", "@hookform/resolvers": "^5.2.2",
@ -65,7 +65,6 @@
"@radix-ui/react-toggle": "^1.1.10", "@radix-ui/react-toggle": "^1.1.10",
"@radix-ui/react-toggle-group": "^1.1.11", "@radix-ui/react-toggle-group": "^1.1.11",
"@radix-ui/react-tooltip": "^1.2.8", "@radix-ui/react-tooltip": "^1.2.8",
"@tailwindcss/cli": "^4.1.5",
"add": "^2.0.6", "add": "^2.0.6",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
@ -83,6 +82,7 @@
"recharts": "^2.15.4", "recharts": "^2.15.4",
"sonner": "^2.0.7", "sonner": "^2.0.7",
"tailwind-merge": "^3.2.0", "tailwind-merge": "^3.2.0",
"tailwindcss": "^4.1.10",
"tw-animate-css": "^1.2.9", "tw-animate-css": "^1.2.9",
"vaul": "^1.1.2", "vaul": "^1.1.2",
"zod": "^3.25.76" "zod": "^3.25.76"

View File

@ -10,109 +10,7 @@
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));
/** @theme {
*
* https://tweakcn.com/
* https://themux.vercel.app/shadcn-themes
* https://shadcnstudio.com/theme-generator
*
**/
:root {
--font-sans: "Noto Sans", ui-sans-serif, sans-serif, system-ui;
--font-serif: "Noto Serif", ui-serif, serif;
--font-mono: "Noto Sans Mono", ui-monospace, monospace;
--background: oklch(1 0 0);
--foreground: oklch(13.636% 0.02685 282.25);
--card: oklch(1.0 0 0);
--card-foreground: oklch(0.2035 0.0139 285.1021);
--popover: oklch(1.0 0 0);
--popover-foreground: oklch(0.2035 0.0139 285.1021);
--primary: oklch(0.623 0.214 259.815);
--primary-foreground: oklch(1.0 0 0);
--secondary: oklch(0.9574 0.0011 197.1383);
--secondary-foreground: oklch(0.2069 0.0098 285.5081);
--muted: oklch(0.9674 0.0013 286.3752);
--muted-foreground: oklch(0.5466 0.0216 285.664);
--accent: oklch(0.9299 0.0334 272.7879);
--accent-foreground: oklch(0.3729 0.0306 259.7328);
--destructive: oklch(0.583 0.2387 28.4765);
--destructive-foreground: oklch(1.0 0 0);
--border: oklch(0.9273 0.0067 286.2663);
--input: oklch(0.9173 0.0067 286.2663);
--ring: oklch(0.6187 0.2067 259.2316);
--chart-1: oklch(0.6471 0.2173 36.8511);
--chart-2: oklch(37.973% 0.0506 187.591);
--chart-3: oklch(0.4247 0.0852 230.5827);
--chart-4: oklch(0.829 0.1712 81.0381);
--chart-5: oklch(0.7724 0.1728 65.367);
--sidebar: oklch(0.957 0.007 272.5840410480741);
--sidebar-foreground: oklch(0.2035 0.0139 285.1021);
--sidebar-primary: oklch(0.623 0.214 259.815);
--sidebar-primary-foreground: oklch(1.0 0 0);
--sidebar-accent: oklch(0.9674 0.0013 286.3752);
--sidebar-accent-foreground: oklch(0.2069 0.0098 285.5081);
--sidebar-border: oklch(0.9173 0.0067 286.2663);
--sidebar-ring: oklch(0.623 0.214 259.815);
--radius: 0.40rem;
--shadow-2xs: 1px 1px 6px 0px hsl(0 0% 0% / 0.05);
--shadow-xs: 1px 1px 6px 0px hsl(0 0% 0% / 0.05);
--shadow-sm: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 1px 2px -1px hsl(0 0% 0% / 0.1);
--shadow: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 1px 2px -1px hsl(0 0% 0% / 0.1);
--shadow-md: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 2px 4px -1px hsl(0 0% 0% / 0.1);
--shadow-lg: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 4px 6px -1px hsl(0 0% 0% / 0.1);
--shadow-xl: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 8px 10px -1px hsl(0 0% 0% / 0.1);
--shadow-2xl: 1px 1px 6px 0px hsl(0 0% 0% / 0.25);
--tracking-normal: 0rem;
--spacing: 0.22rem;
}
.dark {
--background: oklch(0.1448 0 0);
--foreground: oklch(0.9851 0 0);
--card: oklch(0.2046 0 0);
--card-foreground: oklch(0.9851 0 0);
--popover: oklch(0.2046 0 0);
--popover-foreground: oklch(0.9851 0 0);
--primary: oklch(0.5471 0.2506 262.8726);
--primary-foreground: oklch(0.9705 0.0142 254.6042);
--secondary: oklch(0.2707 0.0092 285.7705);
--secondary-foreground: oklch(0.9851 0 0);
--muted: oklch(0.2686 0 0);
--muted-foreground: oklch(0.709 0 0);
--accent: oklch(0.3729 0.0306 259.7328);
--accent-foreground: oklch(0.8717 0.0093 258.3382);
--destructive: oklch(0.7022 0.1892 22.2279);
--destructive-foreground: oklch(0.2558 0.0412 235.1561);
--border: oklch(1.0 0 0);
--input: oklch(1.0 0 0);
--ring: oklch(0.4915 0.2776 263.8724);
--chart-1: oklch(0.4915 0.2776 263.8724);
--chart-2: oklch(0.7019 0.1577 160.4375);
--chart-3: oklch(0.7724 0.1728 65.367);
--chart-4: oklch(0.6217 0.2589 305.309);
--chart-5: oklch(0.6435 0.2452 16.501);
--sidebar: oklch(0.2046 0 0);
--sidebar-foreground: oklch(0.9851 0 0);
--sidebar-primary: oklch(0.5471 0.2506 262.8726);
--sidebar-primary-foreground: oklch(0.9705 0.0142 254.6042);
--sidebar-accent: oklch(0.2686 0 0);
--sidebar-accent-foreground: oklch(0.9851 0 0);
--sidebar-border: oklch(1.0 0 0);
--sidebar-ring: oklch(0.4915 0.2776 263.8724);
--radius: 0.25rem;
--shadow-2xs: 1px 1px 6px 0px hsl(0 0% 0% / 0.05);
--shadow-xs: 1px 1px 6px 0px hsl(0 0% 0% / 0.05);
--shadow-sm: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 1px 2px -1px hsl(0 0% 0% / 0.1);
--shadow: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 1px 2px -1px hsl(0 0% 0% / 0.1);
--shadow-md: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 2px 4px -1px hsl(0 0% 0% / 0.1);
--shadow-lg: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 4px 6px -1px hsl(0 0% 0% / 0.1);
--shadow-xl: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 8px 10px -1px hsl(0 0% 0% / 0.1);
--shadow-2xl: 1px 1px 6px 0px hsl(0 0% 0% / 0.25);
}
@theme inline {
--color-background: var(--background); --color-background: var(--background);
--color-foreground: var(--foreground); --color-foreground: var(--foreground);
--color-card: var(--card); --color-card: var(--card);
@ -163,6 +61,150 @@
--shadow-lg: var(--shadow-lg); --shadow-lg: var(--shadow-lg);
--shadow-xl: var(--shadow-xl); --shadow-xl: var(--shadow-xl);
--shadow-2xl: var(--shadow-2xl); --shadow-2xl: var(--shadow-2xl);
@keyframes accordion-down {
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
}
@keyframes accordion-up {
from {
height: var(--radix-accordion-content-height);
}
to {
height: 0;
}
}
}
/*
The default border color has changed to `currentColor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}
@layer utilities {
body {
font-family: Arial, Helvetica, sans-serif;
}
}
/**
*
* https://tweakcn.com/
* https://themux.vercel.app/shadcn-themes
* https://shadcnstudio.com/theme-generator
*
**/
@layer base {
:root {
--font-sans: "Noto Sans", ui-sans-serif, sans-serif, system-ui;
--font-serif: "Noto Serif", ui-serif, serif;
--font-mono: "Noto Sans Mono", ui-monospace, monospace;
--background: oklch(1 0 0);
--foreground: oklch(13.636% 0.02685 282.25);
--card: oklch(1 0 0);
--card-foreground: oklch(0.2035 0.0139 285.1021);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.2035 0.0139 285.1021);
--primary: oklch(0.623 0.214 259.815);
--primary-foreground: oklch(1 0 0);
--secondary: oklch(0.9574 0.0011 197.1383);
--secondary-foreground: oklch(0.2069 0.0098 285.5081);
--muted: oklch(0.9674 0.0013 286.3752);
--muted-foreground: oklch(0.5466 0.0216 285.664);
--accent: oklch(0.9299 0.0334 272.7879);
--accent-foreground: oklch(0.3729 0.0306 259.7328);
--destructive: oklch(0.583 0.2387 28.4765);
--destructive-foreground: oklch(1 0 0);
--border: oklch(0.9273 0.0067 286.2663);
--input: oklch(0.9173 0.0067 286.2663);
--ring: oklch(0.6187 0.2067 259.2316);
--chart-1: oklch(0.6471 0.2173 36.8511);
--chart-2: oklch(37.973% 0.0506 187.591);
--chart-3: oklch(0.4247 0.0852 230.5827);
--chart-4: oklch(0.829 0.1712 81.0381);
--chart-5: oklch(0.7724 0.1728 65.367);
--sidebar: oklch(0.957 0.007 272.5840410480741);
--sidebar-foreground: oklch(0.2035 0.0139 285.1021);
--sidebar-primary: oklch(0.623 0.214 259.815);
--sidebar-primary-foreground: oklch(1 0 0);
--sidebar-accent: oklch(0.9674 0.0013 286.3752);
--sidebar-accent-foreground: oklch(0.2069 0.0098 285.5081);
--sidebar-border: oklch(0.9173 0.0067 286.2663);
--sidebar-ring: oklch(0.623 0.214 259.815);
--radius: 0.4rem;
--shadow-2xs: 1px 1px 6px 0px hsl(0 0% 0% / 0.05);
--shadow-xs: 1px 1px 6px 0px hsl(0 0% 0% / 0.05);
--shadow-sm: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 1px 2px -1px hsl(0 0% 0% / 0.1);
--shadow: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 1px 2px -1px hsl(0 0% 0% / 0.1);
--shadow-md: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 2px 4px -1px hsl(0 0% 0% / 0.1);
--shadow-lg: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 4px 6px -1px hsl(0 0% 0% / 0.1);
--shadow-xl: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 8px 10px -1px hsl(0 0% 0% / 0.1);
--shadow-2xl: 1px 1px 6px 0px hsl(0 0% 0% / 0.25);
--tracking-normal: 0rem;
--spacing: 0.22rem;
}
.dark {
--background: oklch(0.1448 0 0);
--foreground: oklch(0.9851 0 0);
--card: oklch(0.2046 0 0);
--card-foreground: oklch(0.9851 0 0);
--popover: oklch(0.2046 0 0);
--popover-foreground: oklch(0.9851 0 0);
--primary: oklch(0.5471 0.2506 262.8726);
--primary-foreground: oklch(0.9705 0.0142 254.6042);
--secondary: oklch(0.2707 0.0092 285.7705);
--secondary-foreground: oklch(0.9851 0 0);
--muted: oklch(0.2686 0 0);
--muted-foreground: oklch(0.709 0 0);
--accent: oklch(0.3729 0.0306 259.7328);
--accent-foreground: oklch(0.8717 0.0093 258.3382);
--destructive: oklch(0.7022 0.1892 22.2279);
--destructive-foreground: oklch(0.2558 0.0412 235.1561);
--border: oklch(1 0 0);
--input: oklch(1 0 0);
--ring: oklch(0.4915 0.2776 263.8724);
--chart-1: oklch(0.4915 0.2776 263.8724);
--chart-2: oklch(0.7019 0.1577 160.4375);
--chart-3: oklch(0.7724 0.1728 65.367);
--chart-4: oklch(0.6217 0.2589 305.309);
--chart-5: oklch(0.6435 0.2452 16.501);
--sidebar: oklch(0.2046 0 0);
--sidebar-foreground: oklch(0.9851 0 0);
--sidebar-primary: oklch(0.5471 0.2506 262.8726);
--sidebar-primary-foreground: oklch(0.9705 0.0142 254.6042);
--sidebar-accent: oklch(0.2686 0 0);
--sidebar-accent-foreground: oklch(0.9851 0 0);
--sidebar-border: oklch(1 0 0);
--sidebar-ring: oklch(0.4915 0.2776 263.8724);
--radius: 0.25rem;
--shadow-2xs: 1px 1px 6px 0px hsl(0 0% 0% / 0.05);
--shadow-xs: 1px 1px 6px 0px hsl(0 0% 0% / 0.05);
--shadow-sm: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 1px 2px -1px hsl(0 0% 0% / 0.1);
--shadow: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 1px 2px -1px hsl(0 0% 0% / 0.1);
--shadow-md: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 2px 4px -1px hsl(0 0% 0% / 0.1);
--shadow-lg: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 4px 6px -1px hsl(0 0% 0% / 0.1);
--shadow-xl: 1px 1px 6px 0px hsl(0 0% 0% / 0.1), 1px 8px 10px -1px hsl(0 0% 0% / 0.1);
--shadow-2xl: 1px 1px 6px 0px hsl(0 0% 0% / 0.25);
}
} }
@layer base { @layer base {

View File

@ -861,7 +861,7 @@ importers:
specifier: ^19.1.0 specifier: ^19.1.0
version: 19.2.0(react@19.2.0) version: 19.2.0(react@19.2.0)
tailwindcss: tailwindcss:
specifier: ^4.1.5 specifier: ^4.1.10
version: 4.1.16 version: 4.1.16
tsup: tsup:
specifier: ^8.4.0 specifier: ^8.4.0
@ -981,9 +981,6 @@ importers:
'@radix-ui/react-tooltip': '@radix-ui/react-tooltip':
specifier: ^1.2.8 specifier: ^1.2.8
version: 1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) version: 1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@tailwindcss/cli':
specifier: ^4.1.5
version: 4.1.16
add: add:
specifier: ^2.0.6 specifier: ^2.0.6
version: 2.0.6 version: 2.0.6
@ -1035,6 +1032,9 @@ importers:
tailwind-merge: tailwind-merge:
specifier: ^3.2.0 specifier: ^3.2.0
version: 3.3.1 version: 3.3.1
tailwindcss:
specifier: ^4.1.10
version: 4.1.16
tw-animate-css: tw-animate-css:
specifier: ^1.2.9 specifier: ^1.2.9
version: 1.4.0 version: 1.4.0
@ -1051,6 +1051,9 @@ importers:
'@repo/typescript-config': '@repo/typescript-config':
specifier: workspace:* specifier: workspace:*
version: link:../typescript-config version: link:../typescript-config
'@tailwindcss/cli':
specifier: ^4.1.5
version: 4.1.16
'@tailwindcss/postcss': '@tailwindcss/postcss':
specifier: ^4.1.5 specifier: ^4.1.5
version: 4.1.16 version: 4.1.16
@ -1075,9 +1078,6 @@ importers:
react-dom: react-dom:
specifier: ^19.1.0 specifier: ^19.1.0
version: 19.2.0(react@19.2.0) version: 19.2.0(react@19.2.0)
tailwindcss:
specifier: ^4.1.5
version: 4.1.16
typescript: typescript:
specifier: ^5.6.0 specifier: ^5.6.0
version: 5.9.3 version: 5.9.3