Commit 50b8f2a2 by CaIon

refactor: update styling and improve code readability across multiple components

parent a0de4b56
......@@ -21,7 +21,7 @@
"src/routeTree.gen.ts"
],
"rules": {
"curly": "error",
"curly": ["error", "multi-line"],
"eqeqeq": [
"error",
"always",
......
......@@ -17,6 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { cn } from '@/lib/utils'
import type { DataTableColumnClassName, DataTablePinnedColumn } from './types'
export function getResolvedColumnClassName(
......@@ -37,14 +38,18 @@ export function getResolvedColumnClassNameFromMap(
const customClassName = getColumnClassName?.(columnId, kind)
const pinnedColumn = pinnedColumnById?.get(columnId)
if (!pinnedColumn) return customClassName
if (!pinnedColumn) {
return customClassName
}
return cn(customClassName, getPinnedColumnClassName(pinnedColumn, kind))
}
}
export function getPinnedColumnMap(pinnedColumns?: DataTablePinnedColumn[]) {
if (!pinnedColumns?.length) return undefined
if (!pinnedColumns?.length) {
return undefined
}
return new Map(pinnedColumns.map((column) => [column.columnId, column]))
}
......@@ -63,7 +68,7 @@ function getPinnedColumnClassName(
pinnedColumn.side === 'left' ? 'left-0' : 'right-0',
edgeClassName,
kind === 'header'
? '[background-color:var(--table-header-bg,var(--background))] group-hover:[background-color:color-mix(in_oklch,var(--muted)_50%,var(--background))] z-30'
? '[background-color:var(--table-header-bg,var(--table-header))] group-hover:[background-color:var(--table-header-hover)] z-30'
: 'bg-background z-10 group-hover:[background-color:color-mix(in_oklch,var(--muted)_50%,var(--background))] group-data-[state=selected]:bg-muted',
pinnedColumn.className,
kind === 'header'
......
import type { Row, Table as TanstackTable } from '@tanstack/react-table'
/*
Copyright (C) 2023-2026 QuantumNous
......@@ -17,9 +18,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import * as React from 'react'
import { type Row, type Table as TanstackTable } from '@tanstack/react-table'
import { cn } from '@/lib/utils'
import { Table, TableBody, TableCell, TableRow } from '@/components/ui/table'
import { cn } from '@/lib/utils'
import {
getPinnedColumnMap,
getResolvedColumnClassNameFromMap,
......@@ -136,7 +138,7 @@ function SplitHeaderTableView<TData>({
<div
className={cn(
'min-h-0 flex-1 overflow-auto',
'**:data-[slot=table-header]:[--table-header-bg:color-mix(in_oklch,var(--muted)_30%,var(--background))]',
'**:data-[slot=table-header]:[--table-header-bg:var(--table-header)]',
'**:data-[slot=table-header]:bg-(--table-header-bg)',
props.splitHeaderScrollClassName,
props.bodyContainerClassName
......@@ -192,7 +194,9 @@ function getMetaPinnedColumns<TData>(
): DataTablePinnedColumn[] {
return table.getAllColumns().flatMap((column) => {
const side = column.columnDef.meta?.pinned
if (!side) return []
if (!side) {
return []
}
return [{ columnId: column.id, side }]
})
......
......@@ -61,7 +61,7 @@ export {
export { useDebouncedColumnFilter } from './hooks/use-debounced-column-filter'
export const DISABLED_ROW_DESKTOP =
'bg-muted/85 hover:bg-muted [&>td:first-child]:border-l-muted-foreground/35 [&>td:first-child]:border-l-4 [&>td:first-child]:pl-1'
'[--data-table-card-bg:var(--table-disabled)] hover:[--data-table-card-bg:var(--table-disabled-hover)] [background-color:var(--table-disabled)] hover:[background-color:var(--table-disabled-hover)] [&>td:first-child]:[border-left-color:var(--table-disabled-border)] [&>td:first-child]:border-l-4 [&>td:first-child]:pl-1'
export const DISABLED_ROW_MOBILE =
'border-l-4 border-l-muted-foreground/35 bg-muted/85'
'[--data-table-card-bg:var(--table-disabled)] [background-color:var(--table-disabled)] border-l-4 [border-left-color:var(--table-disabled-border)]'
import type { Row, Table } from '@tanstack/react-table'
import { Database } from 'lucide-react'
/*
Copyright (C) 2023-2026 QuantumNous
......@@ -17,10 +19,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import * as React from 'react'
import type { Row, Table } from '@tanstack/react-table'
import { Database } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { cn } from '@/lib/utils'
import {
Empty,
EmptyDescription,
......@@ -29,6 +29,8 @@ import {
EmptyTitle,
} from '@/components/ui/empty'
import { Skeleton } from '@/components/ui/skeleton'
import { cn } from '@/lib/utils'
import { tableHasCompactMeta } from './card-cell-utils'
import { CardRowContent } from './card-row-content'
......@@ -78,7 +80,7 @@ function CardGridSkeleton(props: {
{[1, 2, 3, 4, 5, 6].map((i) => (
<div
key={`${prefix}-${i}`}
className='bg-card space-y-3 rounded-lg border p-3'
className='space-y-3 rounded-lg border [background-color:var(--table-row)] p-3'
>
<div className='flex items-center justify-between gap-2'>
<Skeleton className='h-4 w-32' />
......@@ -157,8 +159,9 @@ export function DataTableCardGrid<TData>(props: DataTableCardGridProps<TData>) {
return (
<div
key={key}
data-slot='data-table-card'
className={cn(
'bg-card rounded-lg border px-3 py-2.5',
'rounded-lg border [background-color:var(--data-table-card-bg,var(--table-row))] px-3 py-2.5',
props.getRowClassName?.(row)
)}
>
......
import type {
ColumnDef,
Row,
Table as TanstackTable,
} from '@tanstack/react-table'
/*
Copyright (C) 2023-2026 QuantumNous
......@@ -17,14 +22,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import * as React from 'react'
import {
type ColumnDef,
type Row,
type Table as TanstackTable,
} from '@tanstack/react-table'
import { PageFooterPortal } from '@/components/layout'
import { useMediaQuery } from '@/hooks'
import { cn } from '@/lib/utils'
import { PageFooterPortal } from '@/components/layout'
import {
DataTableView,
type DataTableColumnClassName,
......@@ -32,15 +34,15 @@ import {
type DataTableRenderRowHelpers,
} from '../core/data-table-view'
import { DataTablePagination } from '../core/pagination'
import { DataTableToolbar } from '../toolbar/toolbar'
import { DataTableViewModeToggle } from '../toolbar/view-mode-toggle'
import {
DATA_TABLE_VIEW_MODES,
useDataTableViewMode,
type DataTableViewMode,
} from '../hooks/use-data-table-view-mode'
import { MobileCardList } from './mobile-card-list'
import { DataTableToolbar } from '../toolbar/toolbar'
import { DataTableViewModeToggle } from '../toolbar/view-mode-toggle'
import { DataTableCardGrid } from './card-grid'
import { MobileCardList } from './mobile-card-list'
/**
* Pass-through configuration for the default {@link DataTableToolbar}.
......@@ -376,7 +378,9 @@ function renderToolbar<TData>(
function renderPagination<TData>(
props: DataTablePageProps<TData>
): React.ReactNode {
if (props.showPagination === false) return null
if (props.showPagination === false) {
return null
}
const pagination = <DataTablePagination table={props.table} />
......@@ -391,7 +395,9 @@ function renderMobile<TData>(
props: DataTablePageProps<TData>,
showMobile: boolean
): React.ReactNode {
if (!showMobile) return null
if (!showMobile) {
return null
}
const ownGetRowClassName = props.getRowClassName
const mobileGetRowClassName =
......@@ -436,7 +442,9 @@ function renderDesktop<TData>(
cardViewActive: boolean,
viewMode: DataTableViewMode
): React.ReactNode {
if (showMobile) return null
if (showMobile) {
return null
}
const isFetchingOnly = props.isFetching && !props.isLoading
const fixedHeight = props.fixedHeight !== false
......@@ -481,8 +489,7 @@ function renderDesktop<TData>(
splitHeader={fixedHeight}
tableContainerClassName={fixedHeight ? 'h-full min-h-0' : undefined}
tableHeaderClassName={cn(
fixedHeight &&
'[background-color:color-mix(in_oklch,var(--muted)_30%,var(--background))]',
fixedHeight && '[background-color:var(--table-header)]',
props.tableHeaderClassName
)}
getColumnClassName={props.getColumnClassName}
......
import type { Row, Table } from '@tanstack/react-table'
import { Database } from 'lucide-react'
/*
Copyright (C) 2023-2026 QuantumNous
......@@ -17,10 +19,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import * as React from 'react'
import type { Row, Table } from '@tanstack/react-table'
import { Database } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { cn } from '@/lib/utils'
import {
Empty,
EmptyDescription,
......@@ -29,6 +29,8 @@ import {
EmptyTitle,
} from '@/components/ui/empty'
import { Skeleton } from '@/components/ui/skeleton'
import { cn } from '@/lib/utils'
import { tableHasCompactMeta } from './card-cell-utils'
import { CardRowContent } from './card-row-content'
......@@ -143,7 +145,10 @@ export function MobileCardList<TData>(props: MobileCardListProps<TData>) {
return (
<div
key={key}
className={cn('bg-card px-3 py-2.5', getRowClassName?.(row))}
className={cn(
'[background-color:var(--data-table-card-bg,var(--table-row))] px-3 py-2.5',
getRowClassName?.(row)
)}
>
<CardRowContent row={row} compact={hasCompactMeta} />
</div>
......
......@@ -23,7 +23,7 @@ export const staticDataTableClassNames = {
compactTable: 'text-sm',
compactHeaderRow: 'hover:bg-transparent',
mutedHeaderRow:
'[background-color:color-mix(in_oklch,var(--muted)_30%,var(--background))] hover:[background-color:color-mix(in_oklch,var(--muted)_30%,var(--background))]',
'[background-color:var(--table-header)] hover:[background-color:var(--table-header-hover)]',
compactHeaderCell:
'text-muted-foreground py-2 text-[10px] font-medium tracking-wider uppercase',
compactHeaderCellRight:
......
import type { LucideIcon } from 'lucide-react'
/*
Copyright (C) 2023-2026 QuantumNous
......@@ -18,10 +19,10 @@ For commercial licensing, please contact support@quantumnous.com
*/
/* eslint-disable react-refresh/only-export-components */
import * as React from 'react'
import { type LucideIcon } from 'lucide-react'
import { useCopyToClipboard } from '@/hooks/use-copy-to-clipboard'
import { stringToColor } from '@/lib/colors'
import { cn } from '@/lib/utils'
import { useCopyToClipboard } from '@/hooks/use-copy-to-clipboard'
export const dotColorMap = {
success: 'bg-success',
......@@ -37,7 +38,7 @@ export const dotColorMap = {
grey: 'bg-neutral',
indigo: 'bg-chart-1',
'light-blue': 'bg-info',
'light-green': 'bg-success',
'light-green': 'bg-emerald-400',
lime: 'bg-chart-3',
orange: 'bg-warning',
pink: 'bg-chart-5',
......@@ -61,7 +62,7 @@ export const textColorMap = {
grey: 'text-muted-foreground',
indigo: 'text-chart-1',
'light-blue': 'text-info',
'light-green': 'text-success',
'light-green': 'text-emerald-500 dark:text-emerald-300',
lime: 'text-chart-3',
orange: 'text-warning',
pink: 'text-chart-5',
......
......@@ -80,8 +80,8 @@ export const CHANNEL_TYPES = {
} as const
const CHANNEL_TYPE_DISPLAY_ORDER: number[] = [
1, 14, 33, 24, 43, 3, 41, 48, 58, 42, 34, 20, 4, 40, 27, 25, 17, 26, 15, 46, 23,
18, 45, 31, 35, 49, 19, 47, 37, 38, 39, 11, 8, 57, 22, 21, 44, 2, 5, 36,
1, 14, 33, 24, 43, 3, 41, 48, 58, 42, 34, 20, 4, 40, 27, 25, 17, 26, 15, 46,
23, 18, 45, 31, 35, 49, 19, 47, 37, 38, 39, 11, 8, 57, 22, 21, 44, 2, 5, 36,
50, 51, 52, 53, 54, 55, 56,
]
......@@ -322,7 +322,7 @@ export const RESPONSE_TIME_THRESHOLDS = {
export const RESPONSE_TIME_CONFIG = {
EXCELLENT: { variant: 'success' as const, label: 'Excellent' },
GOOD: { variant: 'info' as const, label: 'Good' },
GOOD: { variant: 'success' as const, label: 'Good' },
FAIR: { variant: 'warning' as const, label: 'Fair' },
POOR: { variant: 'danger' as const, label: 'Poor' },
UNKNOWN: { variant: 'neutral' as const, label: 'Not tested' },
......
import { useQuery } from '@tanstack/react-query'
import { Copy, ExternalLink, Loader2, RefreshCcw } from 'lucide-react'
/*
Copyright (C) 2023-2026 QuantumNous
......@@ -17,10 +19,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { useMemo } from 'react'
import { useQuery } from '@tanstack/react-query'
import { Copy, ExternalLink, Loader2, RefreshCcw } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { toast } from 'sonner'
import { Dialog } from '@/components/dialog'
import { Button } from '@/components/ui/button'
import {
Collapsible,
......@@ -28,7 +30,7 @@ import {
CollapsibleTrigger,
} from '@/components/ui/collapsible'
import { Separator } from '@/components/ui/separator'
import { Dialog } from '@/components/dialog'
import { getDeployment, listDeploymentContainers } from '../../api'
export function ViewDetailsDialog({
......@@ -73,10 +75,14 @@ export function ViewDetailsDialog({
const locations = useMemo(() => {
const items = details?.locations
if (!Array.isArray(items)) return []
if (!Array.isArray(items)) {
return []
}
return items
.map((x) => {
if (!x || typeof x !== 'object') return null
if (!x || typeof x !== 'object') {
return null
}
const name = (x as Record<string, unknown>)?.name
const iso2 = (x as Record<string, unknown>)?.iso2
const id = (x as Record<string, unknown>)?.id
......@@ -86,7 +92,9 @@ export function ViewDetailsDialog({
}, [details])
const handleCopyId = async () => {
if (deploymentId === null || deploymentId === undefined) return
if (deploymentId === null || deploymentId === undefined) {
return
}
try {
await navigator.clipboard.writeText(String(deploymentId))
toast.success(t('Copied'))
......@@ -108,6 +116,9 @@ export function ViewDetailsDialog({
return ''
}
}, [details])
const isDetailsLoading = isLoadingDetails || isLoadingContainers
const showDetailsError = !isDetailsLoading && !detailsRes?.success
const showDetailsContent = !isDetailsLoading && detailsRes?.success
return (
<Dialog
......@@ -118,7 +129,6 @@ export function ViewDetailsDialog({
contentHeight='auto'
bodyClassName='space-y-4'
footer={
<>
<Button
variant='outline'
onClick={() => onOpenChange(false)}
......@@ -126,7 +136,6 @@ export function ViewDetailsDialog({
>
{t('Close')}
</Button>
</>
}
>
<div className='max-h-[calc(100dvh-8.5rem)] space-y-3 overflow-y-auto py-2 pr-1 sm:max-h-[72vh] sm:space-y-4'>
......@@ -158,15 +167,17 @@ export function ViewDetailsDialog({
<Separator />
{isLoadingDetails || isLoadingContainers ? (
{isDetailsLoading ? (
<div className='flex items-center justify-center py-10'>
<Loader2 className='text-muted-foreground h-6 w-6 animate-spin' />
</div>
) : !detailsRes?.success ? (
) : null}
{showDetailsError ? (
<div className='text-muted-foreground py-10 text-center text-sm'>
{detailsRes?.message || t('Failed to fetch deployment details')}
</div>
) : (
) : null}
{showDetailsContent ? (
<>
<div className='grid gap-3 sm:grid-cols-2'>
<div className='rounded-lg border p-3'>
......@@ -225,7 +236,9 @@ export function ViewDetailsDialog({
<div className='space-y-2'>
{containers.map((c) => {
const id = c?.container_id
if (typeof id !== 'string' || !id) return null
if (typeof id !== 'string' || !id) {
return null
}
const status =
typeof c?.status === 'string' ? c.status : undefined
const url =
......@@ -263,13 +276,13 @@ export function ViewDetailsDialog({
{t('Raw JSON')}
</CollapsibleTrigger>
<CollapsibleContent>
<pre className='mt-3 max-h-[360px] overflow-auto rounded-md bg-black p-3 text-xs text-gray-200'>
<pre className='bg-muted text-foreground mt-3 max-h-[360px] overflow-auto rounded-md p-3 text-xs'>
{payloadJson || '-'}
</pre>
</CollapsibleContent>
</Collapsible>
</>
)}
) : null}
</div>
</Dialog>
)
......
import { useQuery } from '@tanstack/react-query'
import { Download, Loader2, RefreshCcw, Terminal } from 'lucide-react'
/*
Copyright (C) 2023-2026 QuantumNous
......@@ -16,10 +18,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { useEffect, useMemo, useRef, useState } from 'react'
import { useQuery } from '@tanstack/react-query'
import { Download, Loader2, RefreshCcw, Terminal } from 'lucide-react'
import { type ReactNode, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Dialog } from '@/components/dialog'
import { Button } from '@/components/ui/button'
import {
Select,
......@@ -30,7 +32,7 @@ import {
SelectValue,
} from '@/components/ui/select'
import { Switch } from '@/components/ui/switch'
import { Dialog } from '@/components/dialog'
import { getDeploymentLogs, listDeploymentContainers } from '../../api'
interface ViewLogsDialogProps {
......@@ -114,9 +116,17 @@ export function ViewLogsDialog({
}, [logsData?.data])
const logLines = useMemo(() => {
const normalized = logsText.replace(/\r\n?/g, '\n')
const normalized = logsText.replaceAll(/\r\n?/g, '\n')
return normalized ? normalized.split('\n') : []
}, [logsText])
const keyedLogLines = useMemo(() => {
const seen = new Map<string, number>()
return logLines.map((line) => {
const count = seen.get(line) ?? 0
seen.set(line, count + 1)
return { key: `${line}-${count}`, line }
})
}, [logLines])
// Auto-scroll to bottom
useEffect(() => {
......@@ -135,6 +145,44 @@ export function ViewLogsDialog({
a.click()
URL.revokeObjectURL(url)
}
let containerPlaceholder = t('Select')
if (isLoadingContainers) {
containerPlaceholder = t('Loading...')
} else if (containers.length === 0) {
containerPlaceholder = t('No containers')
}
let logsContent: ReactNode
if (isLoadingContainers || isLoadingLogs) {
logsContent = (
<div className='flex items-center justify-center py-8'>
<Loader2 className='h-6 w-6 animate-spin text-gray-400' />
</div>
)
} else if (containers.length === 0) {
logsContent = (
<div className='py-8 text-center text-gray-400'>{t('No containers')}</div>
)
} else if (!containerId) {
logsContent = (
<div className='py-8 text-center text-gray-400'>
{t('Please select a container')}
</div>
)
} else if (!logsText.trim()) {
logsContent = (
<div className='py-8 text-center text-gray-400'>{t('No logs')}</div>
)
} else {
logsContent = (
<div className='font-mono text-sm'>
{keyedLogLines.map(({ key, line }) => (
<div key={key} className='whitespace-pre-wrap text-gray-200'>
{line}
</div>
))}
</div>
)
}
return (
<Dialog
......@@ -191,8 +239,7 @@ export function ViewLogsDialog({
<div className='space-y-1'>
<div className='text-muted-foreground text-xs'>{t('Container')}</div>
<Select
items={[
...containers.flatMap((c) => {
items={containers.flatMap((c) => {
const id = c?.container_id
if (typeof id !== 'string' || !id) return []
const status =
......@@ -210,28 +257,21 @@ export function ViewLogsDialog({
),
},
]
}),
]}
})}
value={containerId}
onValueChange={(v) => v !== null && setContainerId(v)}
disabled={isLoadingContainers || containers.length === 0}
>
<SelectTrigger>
<SelectValue
placeholder={
isLoadingContainers
? t('Loading...')
: containers.length === 0
? t('No containers')
: t('Select')
}
/>
<SelectValue placeholder={containerPlaceholder} />
</SelectTrigger>
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
{containers.map((c) => {
const id = c?.container_id
if (typeof id !== 'string' || !id) return null
if (typeof id !== 'string' || !id) {
return null
}
const status =
typeof c?.status === 'string' && c.status
? ` (${c.status})`
......@@ -279,7 +319,7 @@ export function ViewLogsDialog({
</div>
<div
ref={scrollRef}
className='flex-1 overflow-auto rounded-md border bg-black p-3 sm:p-4'
className='bg-muted flex-1 overflow-auto rounded-md border p-3 sm:p-4'
onScroll={(e) => {
const target = e.target as HTMLDivElement
const isAtBottom =
......@@ -287,29 +327,7 @@ export function ViewLogsDialog({
setAutoScroll(isAtBottom)
}}
>
{isLoadingContainers || isLoadingLogs ? (
<div className='flex items-center justify-center py-8'>
<Loader2 className='h-6 w-6 animate-spin text-gray-400' />
</div>
) : containers.length === 0 ? (
<div className='py-8 text-center text-gray-400'>
{t('No containers')}
</div>
) : !containerId ? (
<div className='py-8 text-center text-gray-400'>
{t('Please select a container')}
</div>
) : !logsText.trim() ? (
<div className='py-8 text-center text-gray-400'>{t('No logs')}</div>
) : (
<div className='font-mono text-sm'>
{logLines.map((line, idx) => (
<div key={idx} className='whitespace-pre-wrap text-gray-200'>
{line}
</div>
))}
</div>
)}
{logsContent}
</div>
</Dialog>
)
......
......@@ -18,14 +18,15 @@ For commercial licensing, please contact support@quantumnous.com
*/
import { Route } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { getLobeIcon } from '@/lib/lobe-icon'
import { cn } from '@/lib/utils'
import { StatusBadge } from '@/components/status-badge'
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/components/ui/popover'
import { StatusBadge } from '@/components/status-badge'
import { getLobeIcon } from '@/lib/lobe-icon'
import { cn } from '@/lib/utils'
interface ModelBadgeProps {
modelName: string
......@@ -109,11 +110,11 @@ function ModelBadgeContent(props: ModelBadgeProps) {
<span className='flex max-w-none items-center gap-1.5'>
{provider && (
<span
className='flex size-3.5 shrink-0 items-center justify-center'
className='flex h-[18px] w-[18px] shrink-0 items-center justify-center'
title={provider.label}
aria-label={provider.label}
>
{getLobeIcon(provider.icon, 14)}
{getLobeIcon(provider.icon, 18)}
</span>
)}
<span className='whitespace-nowrap'>{props.modelName}</span>
......
......@@ -25,8 +25,8 @@ export function showSubmittedData(
toast.message(title, {
description: (
// w-[340px]
<pre className='mt-2 w-full overflow-x-auto rounded-md bg-slate-950 p-4'>
<code className='text-white'>{JSON.stringify(data, null, 2)}</code>
<pre className='bg-muted text-foreground mt-2 w-full overflow-x-auto rounded-md p-4'>
<code>{JSON.stringify(data, null, 2)}</code>
</pre>
),
})
......
......@@ -353,32 +353,32 @@ For commercial licensing, please contact support@quantumnous.com
--spacing: 0.3rem;
}
.dark [data-theme-preset='simple-large'] {
--background: oklch(0.12 0 0);
--foreground: oklch(0.98 0 0);
--card: oklch(0.18 0 0);
--card-foreground: oklch(0.98 0 0);
--popover: oklch(0.2 0 0);
--popover-foreground: oklch(0.98 0 0);
--background: oklch(0.215 0 0);
--foreground: oklch(0.97 0 0);
--card: oklch(0.27 0 0);
--card-foreground: oklch(0.97 0 0);
--popover: oklch(0.29 0 0);
--popover-foreground: oklch(0.97 0 0);
--primary: oklch(0.94 0 0);
--primary-foreground: oklch(0.12 0 0);
--secondary: oklch(0.24 0 0);
--secondary-foreground: oklch(0.98 0 0);
--muted: oklch(0.24 0 0);
--primary-foreground: oklch(0.145 0 0);
--secondary: oklch(0.315 0 0);
--secondary-foreground: oklch(0.97 0 0);
--muted: oklch(0.315 0 0);
--muted-foreground: oklch(0.82 0 0);
--accent: oklch(0.3 0 0);
--accent: oklch(0.36 0 0);
--accent-foreground: oklch(0.98 0 0);
--destructive: oklch(0.68 0.19 25);
--destructive-foreground: oklch(0.98 0 0);
--success: oklch(0.72 0.13 145);
--success-foreground: oklch(0.12 0 0);
--success-foreground: oklch(0.145 0 0);
--warning: oklch(0.82 0.13 75);
--warning-foreground: oklch(0.12 0 0);
--warning-foreground: oklch(0.145 0 0);
--info: oklch(0.72 0.12 250);
--info-foreground: oklch(0.12 0 0);
--info-foreground: oklch(0.145 0 0);
--neutral: oklch(0.82 0 0);
--neutral-foreground: oklch(0.12 0 0);
--neutral-foreground: oklch(0.145 0 0);
--border: oklch(1 0 0 / 18%);
--input: oklch(1 0 0 / 24%);
......@@ -390,17 +390,17 @@ For commercial licensing, please contact support@quantumnous.com
--chart-4: oklch(0.82 0.13 75);
--chart-5: oklch(0.68 0.19 25);
--sidebar: oklch(0.16 0 0);
--sidebar-foreground: oklch(0.98 0 0);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.97 0 0);
--sidebar-primary: oklch(0.94 0 0);
--sidebar-primary-foreground: oklch(0.12 0 0);
--sidebar-accent: oklch(0.28 0 0);
--sidebar-primary-foreground: oklch(0.145 0 0);
--sidebar-accent: oklch(0.34 0 0);
--sidebar-accent-foreground: oklch(0.98 0 0);
--sidebar-border: oklch(1 0 0 / 18%);
--sidebar-ring: oklch(0.94 0 0);
--skeleton-base: oklch(0.24 0 0);
--skeleton-highlight: oklch(0.34 0 0);
--skeleton-base: oklch(0.315 0 0);
--skeleton-highlight: oklch(0.415 0 0);
}
/* ── Semantic surface bridge ──────────────────────────────────────────── */
......@@ -552,21 +552,21 @@ For commercial licensing, please contact support@quantumnous.com
.dark [data-theme-preset='anthropic'] {
/* Warm near-black product surfaces, not pure black — keeps the editorial
* personality even when inverted. Coral lifts slightly for legibility. */
--background: oklch(0.205 0.004 60); /* ≈ #181715 */
--foreground: oklch(0.965 0.005 92); /* ≈ #faf9f5 */
--card: oklch(0.245 0.004 60);
--background: oklch(0.215 0.004 60);
--foreground: oklch(0.965 0.005 92);
--card: oklch(0.255 0.004 60);
--card-foreground: oklch(0.965 0.005 92);
--popover: oklch(0.265 0.004 60);
--popover: oklch(0.275 0.004 60);
--popover-foreground: oklch(0.965 0.005 92);
--primary: oklch(0.72 0.135 40);
--primary-foreground: oklch(0.18 0.005 60);
--secondary: oklch(0.295 0.004 60);
--secondary: oklch(0.305 0.004 60);
--secondary-foreground: oklch(0.945 0.005 92);
--muted: oklch(0.275 0.004 60);
--muted: oklch(0.285 0.004 60);
--muted-foreground: oklch(0.76 0.006 75);
--accent: oklch(0.32 0.006 60);
--accent: oklch(0.33 0.006 60);
--accent-foreground: oklch(0.985 0.005 92);
--destructive: oklch(0.7 0.19 22);
......@@ -590,17 +590,17 @@ For commercial licensing, please contact support@quantumnous.com
--chart-4: oklch(0.78 0.13 0);
--chart-5: oklch(0.83 0.027 175);
--sidebar: oklch(0.175 0.004 60);
--sidebar: oklch(0.205 0.004 60);
--sidebar-foreground: oklch(0.95 0.005 92);
--sidebar-primary: oklch(0.72 0.135 40);
--sidebar-primary-foreground: oklch(0.18 0.005 60);
--sidebar-accent: oklch(0.31 0.006 60);
--sidebar-accent: oklch(0.32 0.006 60);
--sidebar-accent-foreground: oklch(0.985 0.005 92);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-border: oklch(1 0 0 / 11%);
--sidebar-ring: oklch(0.72 0.135 40);
--skeleton-base: oklch(0.295 0.004 60);
--skeleton-highlight: oklch(0.4 0.004 60);
--skeleton-base: oklch(0.305 0.004 60);
--skeleton-highlight: oklch(0.41 0.004 60);
}
/* ── Font axis ────────────────────────────────────────────────────────────
......
......@@ -142,22 +142,48 @@ For commercial licensing, please contact support@quantumnous.com
--sidebar-ring: oklch(0.708 0 0);
--skeleton-base: oklch(0.97 0 0);
--skeleton-highlight: oklch(0.985 0 0);
--table-row: var(--background);
--table-header: color-mix(
in oklch,
var(--foreground) 1.5%,
var(--background)
);
--table-header-hover: color-mix(
in oklch,
var(--foreground) 3%,
var(--background)
);
--table-disabled: color-mix(
in oklch,
var(--foreground) 5.5%,
var(--background)
);
--table-disabled-hover: color-mix(
in oklch,
var(--foreground) 7%,
var(--background)
);
--table-disabled-border: color-mix(
in oklch,
var(--foreground) 24%,
var(--background)
);
}
.dark {
/* OpenAI-like dark mode with a softer charcoal canvas. */
--background: oklch(0.225 0 0);
/* OpenAI-like dark mode with a crisp charcoal canvas. */
--background: oklch(0.235 0 0);
--foreground: oklch(0.965 0 0);
--card: oklch(0.275 0 0);
--card: oklch(0.285 0 0);
--card-foreground: oklch(0.965 0 0);
--popover: oklch(0.295 0 0);
--popover: oklch(0.305 0 0);
--popover-foreground: oklch(0.965 0 0);
--primary: oklch(0.965 0 0);
--primary-foreground: oklch(0.145 0 0);
--secondary: oklch(0.325 0 0);
--primary-foreground: oklch(0.155 0 0);
--secondary: oklch(0.335 0 0);
--secondary-foreground: oklch(0.965 0 0);
--muted: oklch(0.295 0 0);
--muted-foreground: oklch(0.76 0 0);
--muted: oklch(0.305 0 0);
--muted-foreground: oklch(0.78 0 0);
--accent: oklch(0.365 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
......@@ -169,23 +195,49 @@ For commercial licensing, please contact support@quantumnous.com
--info: oklch(0.68 0.17 237.323);
--info-foreground: oklch(0.145 0 0);
--neutral: oklch(0.76 0 0);
--neutral-foreground: oklch(0.145 0 0);
--border: oklch(1 0 0 / 9%);
--input: oklch(1 0 0 / 16%);
--neutral-foreground: oklch(0.155 0 0);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 17%);
--ring: oklch(0.68 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.195 0 0);
--sidebar: oklch(0.225 0 0);
--sidebar-foreground: oklch(0.95 0 0);
--sidebar-primary: oklch(0.965 0 0);
--sidebar-primary-foreground: oklch(0.145 0 0);
--sidebar-accent: oklch(0.35 0 0);
--sidebar-primary-foreground: oklch(0.155 0 0);
--sidebar-accent: oklch(0.355 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-border: oklch(1 0 0 / 11%);
--sidebar-ring: oklch(0.68 0 0);
--skeleton-base: oklch(0.325 0 0);
--skeleton-highlight: oklch(0.43 0 0);
--skeleton-base: oklch(0.335 0 0);
--skeleton-highlight: oklch(0.44 0 0);
--table-row: var(--background);
--table-header: color-mix(
in oklch,
var(--foreground) 6%,
var(--background)
);
--table-header-hover: color-mix(
in oklch,
var(--foreground) 9%,
var(--background)
);
--table-disabled: color-mix(
in oklch,
var(--foreground) 10%,
var(--background)
);
--table-disabled-hover: color-mix(
in oklch,
var(--foreground) 13%,
var(--background)
);
--table-disabled-border: color-mix(
in oklch,
var(--foreground) 34%,
var(--background)
);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment