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": {
"enabled": true,
"clientKind": "git",
@ -108,7 +108,7 @@
"useThrowOnlyError": "error"
},
"suspicious": {
"noExplicitAny": "error",
"noExplicitAny": "info",
"noDebugger": "error",
"noDuplicateJsxProps": "error",
"noDuplicateObjectKeys": "error",
@ -209,7 +209,7 @@
"useKeyWithClickEvents": "error",
"useKeyWithMouseEvents": "error",
"useMediaCaption": "error",
"useSemanticElements": "error",
"useSemanticElements": "info",
"useValidAnchor": "error",
"useValidAriaProps": "error",
"useValidAriaValues": "error",
@ -278,6 +278,9 @@
}
},
"css": {
"parser": {
"tailwindDirectives": true
},
"formatter": {
"enabled": true,
"indentStyle": "space",
@ -349,7 +352,7 @@
}
},
"suspicious": {
"noExplicitAny": "error"
"noExplicitAny": "info"
},
"complexity": {
"noExcessiveCognitiveComplexity": {

View File

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

View File

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

View File

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

View File

@ -1,17 +1,17 @@
import { FilterField } from "./FilterField";
import { FilterOperator } from "./FilterOperator";
import { FilterValue } from "./FilterValue";
import type { FilterField } from "./FilterField";
import type { FilterOperator } from "./FilterOperator";
import type { FilterValue } from "./FilterValue";
export type FiltersPrimitives = {
field: string;
operator: string;
value: string;
field: string;
operator: string;
value: string;
};
export declare class Filter {
readonly field: FilterField;
readonly operator: FilterOperator;
readonly value: FilterValue;
constructor(field: FilterField, operator: FilterOperator, value: FilterValue);
static fromPrimitives(field: string, operator: string, value: string): Filter;
toPrimitives(): FiltersPrimitives;
readonly field: FilterField;
readonly operator: FilterOperator;
readonly value: FilterValue;
constructor(field: FilterField, operator: FilterOperator, value: FilterValue);
static fromPrimitives(field: string, operator: string, value: string): Filter;
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";
export type FiltersPrimitives = {
field: string;
operator: string;
value: string;
field: string;
operator: string;
value: string;
};
export class Filter {
readonly field: FilterField;
readonly operator: FilterOperator;
readonly value: FilterValue;
readonly field: FilterField;
readonly operator: FilterOperator;
readonly value: FilterValue;
constructor(field: FilterField, operator: FilterOperator, value: FilterValue) {
this.field = field;
this.operator = operator;
this.value = value;
}
constructor(field: FilterField, operator: FilterOperator, value: FilterValue) {
this.field = field;
this.operator = operator;
this.value = value;
}
static fromPrimitives(field: string, operator: string, value: string): Filter {
return new Filter(
new FilterField(field),
new FilterOperator(Operator[operator as keyof typeof Operator]),
new FilterValue(value),
);
}
static fromPrimitives(field: string, operator: string, value: string): Filter {
return new Filter(
new FilterField(field),
new FilterOperator(Operator[operator as keyof typeof Operator]),
new FilterValue(value)
);
}
toPrimitives(): FiltersPrimitives {
return {
field: this.field.value,
operator: this.operator.value,
value: this.value.value,
};
}
toPrimitives(): FiltersPrimitives {
return {
field: this.field.value,
operator: this.operator.value,
value: this.value.value,
};
}
}

View File

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

View File

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

View File

@ -1,3 +1,3 @@
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 {
constructor(public readonly value: Filter[]) {}
constructor(public readonly value: Filter[]) {}
static fromPrimitives(filters: FiltersPrimitives[]): Filters {
return new Filters(
filters.map((filter) => Filter.fromPrimitives(filter.field, filter.operator, filter.value)),
);
}
static fromPrimitives(filters: FiltersPrimitives[]): Filters {
return new Filters(
filters.map((filter) => Filter.fromPrimitives(filter.field, filter.operator, filter.value))
);
}
toPrimitives(): FiltersPrimitives[] {
return this.value.map((filter) => filter.toPrimitives());
}
toPrimitives(): FiltersPrimitives[] {
return this.value.map((filter) => filter.toPrimitives());
}
isEmpty(): boolean {
return this.value.length === 0;
}
isEmpty(): boolean {
return this.value.length === 0;
}
}

View File

@ -1,5 +1,5 @@
export class InvalidCriteria extends Error {
constructor() {
super("Page size is required when page number is defined");
}
constructor() {
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";
export class Order {
constructor(
public readonly orderBy: OrderBy,
public readonly orderType: OrderType,
) {}
constructor(
public readonly orderBy: OrderBy,
public readonly orderType: OrderType
) {}
static none(): Order {
return new Order(new OrderBy(""), new OrderType(OrderTypes.NONE));
}
static none(): Order {
return new Order(new OrderBy(""), new OrderType(OrderTypes.NONE));
}
static fromPrimitives(orderBy: string | null, orderType: string | null): Order {
return orderBy !== null
? new Order(new OrderBy(orderBy), new OrderType(orderType as OrderTypes))
: Order.none();
}
static fromPrimitives(orderBy: string | null, orderType: string | null): Order {
return orderBy !== null
? new Order(new OrderBy(orderBy), new OrderType(orderType as OrderTypes))
: Order.none();
}
isNone(): boolean {
return this.orderType.isNone();
}
isNone(): boolean {
return this.orderType.isNone();
}
}

View File

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

View File

@ -1,13 +1,13 @@
export enum OrderTypes {
ASC = "ASC",
DESC = "DESC",
NONE = "NONE",
ASC = "ASC",
DESC = "DESC",
NONE = "NONE",
}
export class OrderType {
constructor(public readonly value: OrderTypes) {}
constructor(public readonly value: OrderTypes) {}
isNone(): boolean {
return this.value === OrderTypes.NONE;
}
isNone(): boolean {
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";
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 { DEFAULT_ORDER, INITIAL_PAGE_INDEX, INITIAL_PAGE_SIZE } from "./defaults";
@ -64,7 +64,7 @@ export class CriteriaFromUrlConverter {
searchParams.forEach((value, key) => {
const match = key.match(/filters\[(\d+)]\[(.+)]/);
if (match) {
const index = match[1];
const index = match[1]!;
const property = match[2] as keyof FiltersPrimitives;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!tempFilters[index]) {

View File

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

View File

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

View File

@ -9,7 +9,7 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger,
} 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 { useTranslation } from "../../locales/i18n.ts";
@ -24,7 +24,7 @@ export function DataTableViewOptions<TData>({ table }: { table: Table<TData> })
{t("components.datatable_view_options.view_button")}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-[150px]">
<DropdownMenuContent align="end">
<DropdownMenuLabel>
{t("components.datatable_view_options.toggle_columns")}
</DropdownMenuLabel>
@ -36,11 +36,10 @@ export function DataTableViewOptions<TData>({ table }: { table: Table<TData> })
return (
<DropdownMenuCheckboxItem
checked={column.getIsVisible()}
className="capitalize"
key={column.id}
onCheckedChange={(value) => column.toggleVisibility(!!value)}
>
{column.id}
{getColumnLabel(column)}
</DropdownMenuCheckboxItem>
);
})}
@ -48,3 +47,19 @@ export function DataTableViewOptions<TData>({ table }: { table: Table<TData> })
</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>;
// Configuración
columnVisibility?: VisibilityState;
readOnly?: boolean;
enablePagination?: boolean;
pageSize?: number;
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;
@ -99,6 +100,7 @@ export function DataTable<TData, TValue>({
data,
meta,
columnVisibility: inititalcolumnVisibility = {},
readOnly = false,
enablePagination = true,
pageSize = 10,
@ -119,7 +121,8 @@ export function DataTable<TData, TValue>({
const [rowSelection, setRowSelection] = React.useState({});
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 [colSizes, setColSizes] = React.useState<ColumnSizingState>({});
const [editIndex, setEditIndex] = React.useState<number | null>(null);

View File

@ -1,4 +1,4 @@
@source "../components";
@source "**/*.{ts,tsx}";
@layer components {
/**
@ -8,36 +8,28 @@
/* Fondo suave diagonal */
.brand-surface-50-br {
@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;
@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;
}
.brand-surface-100-br {
@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;
@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;
}
/* Fondo suave horizontal */
.brand-surface-50-x {
@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;
@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;
}
.brand-surface-100-x {
@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;
@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;
}
.brand-surface-200-x {
@apply bg-gradient-to-r from-blue-200 to-violet-200
dark:from-blue-800 dark:to-violet-800;
@apply bg-gradient-to-r from-blue-200 to-violet-200 dark:from-blue-800 dark:to-violet-800;
}
/* Gradiente para texto (intenso) */
.brand-text-strong-x {
@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;
@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;
}
}

View File

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

View File

@ -10,109 +10,7 @@
@custom-variant dark (&:is(.dark *));
/**
*
* 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 {
@theme {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
@ -163,6 +61,150 @@
--shadow-lg: var(--shadow-lg);
--shadow-xl: var(--shadow-xl);
--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 {

View File

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