Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
Son Of Anton
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Son Of Anton
Commits
4918e579
Commit
4918e579
authored
Apr 03, 2026
by
Administrator
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update 13 files via Son of Anton
parent
b02ad490
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
870 additions
and
240 deletions
+870
-240
package.json
frontend/package.json
+45
-6
badge.jsx
frontend/src/components/ui/badge.jsx
+30
-0
button.jsx
frontend/src/components/ui/button.jsx
+53
-0
card.jsx
frontend/src/components/ui/card.jsx
+41
-0
input.jsx
frontend/src/components/ui/input.jsx
+23
-0
motion.jsx
frontend/src/components/ui/motion.jsx
+102
-0
separator.jsx
frontend/src/components/ui/separator.jsx
+22
-0
skeleton.jsx
frontend/src/components/ui/skeleton.jsx
+15
-0
sonner.jsx
frontend/src/components/ui/sonner.jsx
+30
-0
tooltip.jsx
frontend/src/components/ui/tooltip.jsx
+28
-0
index.css
frontend/src/index.css
+235
-222
utils.js
frontend/src/lib/utils.js
+42
-0
tailwind.config.js
frontend/tailwind.config.js
+204
-12
No files found.
frontend/package.json
View file @
4918e579
{
"name"
:
"son-of-anton-frontend"
,
"version"
:
"
1
.0.0"
,
"version"
:
"
2
.0.0"
,
"private"
:
true
,
"type"
:
"module"
,
"scripts"
:
{
"dev"
:
"vite"
,
"build"
:
"vite build"
,
"preview"
:
"vite preview"
},
"dependencies"
:
{
"lucide-react"
:
"^0.469.0"
,
"react"
:
"^18.3.1"
,
"react-dom"
:
"^18.3.1"
,
"react-markdown"
:
"^9.0.1"
,
"react-router-dom"
:
"^7.1.1"
,
"react-markdown"
:
"^9.0.1"
,
"react-syntax-highlighter"
:
"^15.6.1"
,
"remark-gfm"
:
"^4.0.0"
"remark-gfm"
:
"^4.0.0"
,
"lucide-react"
:
"^0.469.0"
,
"@radix-ui/react-dialog"
:
"^1.1.4"
,
"@radix-ui/react-dropdown-menu"
:
"^2.1.4"
,
"@radix-ui/react-popover"
:
"^1.1.4"
,
"@radix-ui/react-select"
:
"^2.1.4"
,
"@radix-ui/react-slider"
:
"^1.2.2"
,
"@radix-ui/react-switch"
:
"^1.1.2"
,
"@radix-ui/react-tabs"
:
"^1.1.2"
,
"@radix-ui/react-tooltip"
:
"^1.1.6"
,
"@radix-ui/react-accordion"
:
"^1.2.2"
,
"@radix-ui/react-avatar"
:
"^1.1.2"
,
"@radix-ui/react-checkbox"
:
"^1.1.3"
,
"@radix-ui/react-context-menu"
:
"^2.2.4"
,
"@radix-ui/react-scroll-area"
:
"^1.2.2"
,
"@radix-ui/react-separator"
:
"^1.1.1"
,
"@radix-ui/react-toggle"
:
"^1.1.1"
,
"@radix-ui/react-toggle-group"
:
"^1.1.1"
,
"@radix-ui/react-progress"
:
"^1.1.1"
,
"@radix-ui/react-alert-dialog"
:
"^1.1.4"
,
"framer-motion"
:
"^11.18.0"
,
"sonner"
:
"^1.7.1"
,
"cmdk"
:
"^1.0.4"
,
"vaul"
:
"^1.1.2"
,
"recharts"
:
"^2.15.0"
,
"react-hot-toast"
:
"^2.5.2"
,
"input-otp"
:
"^1.4.2"
,
"react-resizable-panels"
:
"^2.1.7"
,
"embla-carousel-react"
:
"^8.5.1"
,
"class-variance-authority"
:
"^0.7.1"
,
"clsx"
:
"^2.1.1"
,
"tailwind-merge"
:
"^2.6.0"
,
"date-fns"
:
"^4.1.0"
,
"react-day-picker"
:
"^9.5.0"
,
"zustand"
:
"^5.0.3"
,
"usehooks-ts"
:
"^3.1.0"
},
"devDependencies"
:
{
"@types/react"
:
"^18.3.18"
,
...
...
@@ -23,6 +58,10 @@
"autoprefixer"
:
"^10.4.20"
,
"postcss"
:
"^8.4.49"
,
"tailwindcss"
:
"^3.4.17"
,
"vite"
:
"^6.0.7"
"vite"
:
"^6.0.7"
,
"@tailwindcss/typography"
:
"^0.5.16"
,
"@tailwindcss/forms"
:
"^0.5.10"
,
"@tailwindcss/container-queries"
:
"^0.1.1"
,
"tailwindcss-animate"
:
"^1.0.7"
}
}
\ No newline at end of file
frontend/src/components/ui/badge.jsx
0 → 100644
View file @
4918e579
import
React
from
"react"
;
import
{
cva
}
from
"class-variance-authority"
;
import
{
cn
}
from
"../../lib/utils"
;
const
badgeVariants
=
cva
(
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
,
{
variants
:
{
variant
:
{
default
:
"border-transparent bg-primary text-primary-foreground"
,
secondary
:
"border-transparent bg-secondary text-secondary-foreground"
,
destructive
:
"border-transparent bg-destructive text-destructive-foreground"
,
outline
:
"text-foreground"
,
success
:
"border-transparent bg-green-500/15 text-green-400 border-green-500/20"
,
warning
:
"border-transparent bg-yellow-500/15 text-yellow-400 border-yellow-500/20"
,
info
:
"border-transparent bg-blue-500/15 text-blue-400 border-blue-500/20"
,
accent
:
"border-transparent bg-primary/15 text-primary border-primary/20"
,
},
},
defaultVariants
:
{
variant
:
"default"
,
},
}
);
function
Badge
({
className
,
variant
,
...
props
})
{
return
<
div
className=
{
cn
(
badgeVariants
({
variant
}),
className
)
}
{
...
props
}
/>;
}
export
{
Badge
,
badgeVariants
};
\ No newline at end of file
frontend/src/components/ui/button.jsx
0 → 100644
View file @
4918e579
import
React
from
"react"
;
import
{
cva
}
from
"class-variance-authority"
;
import
{
cn
}
from
"../../lib/utils"
;
import
{
Loader2
}
from
"lucide-react"
;
const
buttonVariants
=
cva
(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 active:scale-[0.98]"
,
{
variants
:
{
variant
:
{
default
:
"bg-primary text-primary-foreground hover:bg-primary/90 shadow-sm"
,
destructive
:
"bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-sm"
,
outline
:
"border border-border bg-transparent hover:bg-white/5 hover:text-foreground"
,
secondary
:
"bg-secondary text-secondary-foreground hover:bg-secondary/80"
,
ghost
:
"hover:bg-white/5 hover:text-foreground"
,
link
:
"text-primary underline-offset-4 hover:underline"
,
glow
:
"bg-primary text-primary-foreground hover:bg-primary/90 shadow-glow hover:shadow-glow-lg"
,
},
size
:
{
default
:
"h-9 px-4 py-2"
,
sm
:
"h-8 rounded-md px-3 text-xs"
,
lg
:
"h-11 rounded-lg px-8 text-base"
,
xl
:
"h-12 rounded-xl px-10 text-base"
,
icon
:
"h-9 w-9"
,
"icon-sm"
:
"h-8 w-8"
,
"icon-lg"
:
"h-11 w-11"
,
},
},
defaultVariants
:
{
variant
:
"default"
,
size
:
"default"
,
},
}
);
const
Button
=
React
.
forwardRef
(
({
className
,
variant
,
size
,
loading
,
children
,
disabled
,
...
props
},
ref
)
=>
{
return
(
<
button
className=
{
cn
(
buttonVariants
({
variant
,
size
,
className
}))
}
ref=
{
ref
}
disabled=
{
disabled
||
loading
}
{
...
props
}
>
{
loading
&&
<
Loader2
className=
"animate-spin"
/>
}
{
children
}
</
button
>
);
}
);
Button
.
displayName
=
"Button"
;
export
{
Button
,
buttonVariants
};
\ No newline at end of file
frontend/src/components/ui/card.jsx
0 → 100644
View file @
4918e579
import
React
from
"react"
;
import
{
cn
}
from
"../../lib/utils"
;
const
Card
=
React
.
forwardRef
(({
className
,
...
props
},
ref
)
=>
(
<
div
ref=
{
ref
}
className=
{
cn
(
"rounded-xl border border-border bg-card text-card-foreground shadow-sm transition-shadow hover:shadow-card-hover"
,
className
)
}
{
...
props
}
/>
));
Card
.
displayName
=
"Card"
;
const
CardHeader
=
React
.
forwardRef
(({
className
,
...
props
},
ref
)
=>
(
<
div
ref=
{
ref
}
className=
{
cn
(
"flex flex-col space-y-1.5 p-6"
,
className
)
}
{
...
props
}
/>
));
CardHeader
.
displayName
=
"CardHeader"
;
const
CardTitle
=
React
.
forwardRef
(({
className
,
...
props
},
ref
)
=>
(
<
h3
ref=
{
ref
}
className=
{
cn
(
"font-semibold leading-none tracking-tight text-white"
,
className
)
}
{
...
props
}
/>
));
CardTitle
.
displayName
=
"CardTitle"
;
const
CardDescription
=
React
.
forwardRef
(({
className
,
...
props
},
ref
)
=>
(
<
p
ref=
{
ref
}
className=
{
cn
(
"text-sm text-muted-foreground"
,
className
)
}
{
...
props
}
/>
));
CardDescription
.
displayName
=
"CardDescription"
;
const
CardContent
=
React
.
forwardRef
(({
className
,
...
props
},
ref
)
=>
(
<
div
ref=
{
ref
}
className=
{
cn
(
"p-6 pt-0"
,
className
)
}
{
...
props
}
/>
));
CardContent
.
displayName
=
"CardContent"
;
const
CardFooter
=
React
.
forwardRef
(({
className
,
...
props
},
ref
)
=>
(
<
div
ref=
{
ref
}
className=
{
cn
(
"flex items-center p-6 pt-0"
,
className
)
}
{
...
props
}
/>
));
CardFooter
.
displayName
=
"CardFooter"
;
export
{
Card
,
CardHeader
,
CardFooter
,
CardTitle
,
CardDescription
,
CardContent
};
\ No newline at end of file
frontend/src/components/ui/input.jsx
0 → 100644
View file @
4918e579
import
React
from
"react"
;
import
{
cn
}
from
"../../lib/utils"
;
const
Input
=
React
.
forwardRef
(({
className
,
type
,
...
props
},
ref
)
=>
{
return
(
<
input
type=
{
type
}
className=
{
cn
(
"flex h-9 w-full rounded-lg border border-border bg-transparent px-3 py-1 text-sm shadow-sm transition-colors"
,
"file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground"
,
"placeholder:text-muted-foreground"
,
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background"
,
"disabled:cursor-not-allowed disabled:opacity-50"
,
className
)
}
ref=
{
ref
}
{
...
props
}
/>
);
});
Input
.
displayName
=
"Input"
;
export
{
Input
};
\ No newline at end of file
frontend/src/components/ui/motion.jsx
0 → 100644
View file @
4918e579
import
{
motion
,
AnimatePresence
}
from
"framer-motion"
;
/**
* Pre-configured motion variants for common animations.
* Use these instead of raw CSS animations for buttery-smooth UX.
*/
export
const
fadeIn
=
{
initial
:
{
opacity
:
0
},
animate
:
{
opacity
:
1
},
exit
:
{
opacity
:
0
},
transition
:
{
duration
:
0.2
},
};
export
const
fadeInUp
=
{
initial
:
{
opacity
:
0
,
y
:
12
},
animate
:
{
opacity
:
1
,
y
:
0
},
exit
:
{
opacity
:
0
,
y
:
12
},
transition
:
{
duration
:
0.25
,
ease
:
"easeOut"
},
};
export
const
fadeInDown
=
{
initial
:
{
opacity
:
0
,
y
:
-
12
},
animate
:
{
opacity
:
1
,
y
:
0
},
exit
:
{
opacity
:
0
,
y
:
-
12
},
transition
:
{
duration
:
0.25
,
ease
:
"easeOut"
},
};
export
const
scaleIn
=
{
initial
:
{
opacity
:
0
,
scale
:
0.95
},
animate
:
{
opacity
:
1
,
scale
:
1
},
exit
:
{
opacity
:
0
,
scale
:
0.95
},
transition
:
{
duration
:
0.2
,
ease
:
"easeOut"
},
};
export
const
slideInRight
=
{
initial
:
{
opacity
:
0
,
x
:
20
},
animate
:
{
opacity
:
1
,
x
:
0
},
exit
:
{
opacity
:
0
,
x
:
20
},
transition
:
{
duration
:
0.25
,
ease
:
"easeOut"
},
};
export
const
slideInLeft
=
{
initial
:
{
opacity
:
0
,
x
:
-
20
},
animate
:
{
opacity
:
1
,
x
:
0
},
exit
:
{
opacity
:
0
,
x
:
-
20
},
transition
:
{
duration
:
0.25
,
ease
:
"easeOut"
},
};
export
const
staggerContainer
=
{
animate
:
{
transition
:
{
staggerChildren
:
0.05
,
delayChildren
:
0.1
,
},
},
};
export
const
staggerItem
=
{
initial
:
{
opacity
:
0
,
y
:
10
},
animate
:
{
opacity
:
1
,
y
:
0
},
transition
:
{
duration
:
0.2
},
};
/**
* MotionDiv — a pre-configured motion.div with fadeInUp by default.
* Pass any variant prop to override.
*/
export
function
MotionDiv
({
children
,
className
,
variants
=
fadeInUp
,
...
props
})
{
return
(
<
motion
.
div
className=
{
className
}
{
...
variants
}
{
...
props
}
>
{
children
}
</
motion
.
div
>
);
}
/**
* MotionList — staggered list animation
*/
export
function
MotionList
({
children
,
className
,
...
props
})
{
return
(
<
motion
.
div
className=
{
className
}
variants=
{
staggerContainer
}
initial=
"initial"
animate=
"animate"
{
...
props
}
>
{
children
}
</
motion
.
div
>
);
}
export
function
MotionItem
({
children
,
className
,
...
props
})
{
return
(
<
motion
.
div
className=
{
className
}
variants=
{
staggerItem
}
{
...
props
}
>
{
children
}
</
motion
.
div
>
);
}
export
{
motion
,
AnimatePresence
};
\ No newline at end of file
frontend/src/components/ui/separator.jsx
0 → 100644
View file @
4918e579
import
*
as
React
from
"react"
;
import
*
as
SeparatorPrimitive
from
"@radix-ui/react-separator"
;
import
{
cn
}
from
"../../lib/utils"
;
const
Separator
=
React
.
forwardRef
(
({
className
,
orientation
=
"horizontal"
,
decorative
=
true
,
...
props
},
ref
)
=>
(
<
SeparatorPrimitive
.
Root
ref=
{
ref
}
decorative=
{
decorative
}
orientation=
{
orientation
}
className=
{
cn
(
"shrink-0 bg-border"
,
orientation
===
"horizontal"
?
"h-[1px] w-full"
:
"h-full w-[1px]"
,
className
)
}
{
...
props
}
/>
)
);
Separator
.
displayName
=
SeparatorPrimitive
.
Root
.
displayName
;
export
{
Separator
};
\ No newline at end of file
frontend/src/components/ui/skeleton.jsx
0 → 100644
View file @
4918e579
import
{
cn
}
from
"../../lib/utils"
;
function
Skeleton
({
className
,
...
props
})
{
return
(
<
div
className=
{
cn
(
"animate-pulse rounded-md bg-white/[0.06]"
,
className
)
}
{
...
props
}
/>
);
}
export
{
Skeleton
};
\ No newline at end of file
frontend/src/components/ui/sonner.jsx
0 → 100644
View file @
4918e579
import
{
Toaster
as
SonnerToaster
}
from
"sonner"
;
/**
* Drop this into App.jsx: <Toaster />
* Then use: toast("Hello"), toast.success("Done"), toast.error("Shit")
*/
export
function
Toaster
()
{
return
(
<
SonnerToaster
position=
"bottom-right"
toastOptions=
{
{
style
:
{
background
:
"hsl(230, 18%, 8%)"
,
border
:
"1px solid hsl(230, 14%, 16%)"
,
color
:
"hsl(220, 15%, 85%)"
,
fontSize
:
"13px"
,
},
classNames
:
{
success
:
"!border-green-500/30"
,
error
:
"!border-red-500/30"
,
warning
:
"!border-yellow-500/30"
,
info
:
"!border-blue-500/30"
,
},
}
}
theme=
"dark"
richColors
closeButton
/>
);
}
\ No newline at end of file
frontend/src/components/ui/tooltip.jsx
0 → 100644
View file @
4918e579
import
*
as
React
from
"react"
;
import
*
as
TooltipPrimitive
from
"@radix-ui/react-tooltip"
;
import
{
cn
}
from
"../../lib/utils"
;
const
TooltipProvider
=
TooltipPrimitive
.
Provider
;
const
Tooltip
=
TooltipPrimitive
.
Root
;
const
TooltipTrigger
=
TooltipPrimitive
.
Trigger
;
const
TooltipContent
=
React
.
forwardRef
(
({
className
,
sideOffset
=
4
,
...
props
},
ref
)
=>
(
<
TooltipPrimitive
.
Content
ref=
{
ref
}
sideOffset=
{
sideOffset
}
className=
{
cn
(
"z-50 overflow-hidden rounded-md bg-popover border border-border px-3 py-1.5 text-xs text-popover-foreground shadow-md"
,
"animate-in fade-in-0 zoom-in-95"
,
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95"
,
"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2"
,
"data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2"
,
className
)
}
{
...
props
}
/>
)
);
TooltipContent
.
displayName
=
TooltipPrimitive
.
Content
.
displayName
;
export
{
Tooltip
,
TooltipTrigger
,
TooltipContent
,
TooltipProvider
};
\ No newline at end of file
frontend/src/index.css
View file @
4918e579
...
...
@@ -3,283 +3,296 @@
@tailwind
utilities
;
/* ═══════════════════════════════════════════════════
ROOT VARIABLES & BASE
DESIGN TOKENS — HSL values for complete theming
═══════════════════════════════════════════════════ */
:root
{
--sat
:
env
(
safe-area-inset-top
,
0px
);
--sar
:
env
(
safe-area-inset-right
,
0px
);
--sab
:
env
(
safe-area-inset-bottom
,
0px
);
--sal
:
env
(
safe-area-inset-left
,
0px
);
--header-h
:
3.25rem
;
color-scheme
:
dark
;
}
@layer
base
{
:root
{
/* ── Anton Brand Tokens ── */
--anton-bg
:
230
20%
4%
;
--anton-surface
:
230
18%
7%
;
--anton-card
:
230
16%
10%
;
--anton-border
:
230
14%
16%
;
--anton-text
:
220
15%
85%
;
--anton-muted
:
220
10%
45%
;
--anton-accent
:
0
75%
58%
;
--anton-success
:
142
70%
45%
;
--anton-danger
:
0
85%
60%
;
--anton-warning
:
38
92%
50%
;
--anton-info
:
217
91%
60%
;
/* ── shadcn-compatible Semantic Tokens ── */
--background
:
230
20%
4%
;
--foreground
:
220
15%
85%
;
--card
:
230
16%
10%
;
--card-foreground
:
220
15%
85%
;
--popover
:
230
18%
8%
;
--popover-foreground
:
220
15%
85%
;
--primary
:
0
75%
58%
;
--primary-foreground
:
0
0%
100%
;
--secondary
:
230
16%
14%
;
--secondary-foreground
:
220
15%
85%
;
--muted
:
230
14%
16%
;
--muted-foreground
:
220
10%
45%
;
--accent
:
230
16%
14%
;
--accent-foreground
:
220
15%
85%
;
--destructive
:
0
85%
60%
;
--destructive-foreground
:
0
0%
100%
;
--border
:
230
14%
16%
;
--input
:
230
14%
16%
;
--ring
:
0
75%
58%
;
--radius
:
0.75rem
;
}
/* ═══════════════════════════════════════════════════
GLOBAL RESETS FOR MOBILE
═══════════════════════════════════════════════════ */
*
{
@apply
border-border;
}
*,
*
::before
,
*
::after
{
-webkit-tap-highlight-color
:
transparent
;
-webkit-touch-callout
:
none
;
body
{
@apply
bg-background
text-foreground
antialiased;
font-feature-settings
:
"rlig"
1
,
"calt"
1
;
}
}
html
{
overflow
:
hidden
;
height
:
100%
;
height
:
100
dvh
;
}
/* ═══════════════════════════════════════════════════
SCROLLBAR — Dark themed, thin, sexy
═══════════════════════════════════════════════════ */
body
{
overflow
:
hidden
;
height
:
100%
;
height
:
100
dvh
;
overscroll-behavior
:
none
;
-webkit-overflow-scrolling
:
touch
;
font-family
:
'Inter'
,
system-ui
,
-apple-system
,
sans-serif
;
position
:
fixed
;
width
:
100%
;
top
:
0
;
left
:
0
;
}
@layer
base
{
*
{
scrollbar-width
:
thin
;
scrollbar-color
:
hsl
(
var
(
--anton-border
))
transparent
;
}
#root
{
height
:
100%
;
height
:
100
dvh
;
overflow
:
hidden
;
display
:
flex
;
flex-direction
:
column
;
::-webkit-scrollbar
{
@apply
w-1.5
h-1.5;
}
::-webkit-scrollbar-track
{
@apply
bg-transparent;
}
::-webkit-scrollbar-thumb
{
@apply
bg-white/10
rounded-full;
}
::-webkit-scrollbar-thumb:hover
{
@apply
bg-white/20;
}
}
/* ═══════════════════════════════════════════════════
SAFE AREA
UTILITIES
COMPONENT
UTILITIES
═══════════════════════════════════════════════════ */
.safe-top
{
padding-top
:
var
(
--sat
);
}
.safe-bottom
{
padding-bottom
:
max
(
var
(
--sab
),
8px
);
}
.safe-left
{
padding-left
:
var
(
--sal
);
}
.safe-right
{
padding-right
:
var
(
--sar
);
}
@layer
utilities
{
/* Glass morphism */
.glass
{
@apply
bg-white/[0.03]
backdrop-blur-xl
border
border-white/[0.06];
}
.glass-heavy
{
@apply
bg-white/[0.06]
backdrop-blur-2xl
border
border-white/[0.08];
}
/* ═══════════════════════════════════════════════════
SCROLLBAR
═══════════════════════════════════════════════════ */
/* Gradient text */
.text-gradient
{
@apply
bg-clip-text
text-transparent
bg-gradient-to-r;
}
.text-gradient-brand
{
@apply
text-gradient
from-red-400
via-orange-400
to-red-500;
}
.text-gradient-cool
{
@apply
text-gradient
from-blue-400
via-purple-400
to-pink-400;
}
::-webkit-scrollbar
{
width
:
4px
;
height
:
4px
;
}
::-webkit-scrollbar-track
{
background
:
transparent
;
}
::-webkit-scrollbar-thumb
{
background
:
rgba
(
255
,
255
,
255
,
0.08
);
border-radius
:
4px
;
}
::-webkit-scrollbar-thumb:hover
{
background
:
rgba
(
255
,
255
,
255
,
0.15
);
}
/* Glow effects */
.glow-sm
{
box-shadow
:
0
0
10px
rgba
(
229
,
62
,
62
,
0.1
);
}
.glow-md
{
box-shadow
:
0
0
20px
rgba
(
229
,
62
,
62
,
0.15
);
}
.glow-lg
{
box-shadow
:
0
0
40px
rgba
(
229
,
62
,
62
,
0.2
);
}
/* ═══════════════════════════════════════════════════
ANIMATIONS
═══════════════════════════════════════════════════ */
/* Noise texture overlay */
.noise
{
position
:
relative
;
}
.noise
::after
{
content
:
""
;
position
:
absolute
;
inset
:
0
;
background-image
:
url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)
' opacity='
0.02
'
/
%
3
E
%
3
C
/
svg
%
3
E
");
pointer-events: none;
z-index: 1;
}
@keyframes
fadeIn
{
from
{
opacity
:
0
;
transform
:
translateY
(
6px
);
}
to
{
opacity
:
1
;
transform
:
translateY
(
0
);
}
}
/* Focus ring */
.focus-ring {
@apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background;
}
@keyframes
slideInLeft
{
from
{
transform
:
translateX
(
-100%
);
}
to
{
transform
:
translateX
(
0
);
}
}
/* Shimmer loading */
.shimmer {
@apply relative overflow-hidden;
background: linear-gradient(
90deg,
transparent 0%,
rgba(255, 255, 255, 0.04) 50%,
transparent 100%
);
background-size: 200% 100%;
@apply animate-shimmer;
}
@keyframes
slideOutLeft
{
from
{
transform
:
translateX
(
0
);
}
to
{
transform
:
translateX
(
-100%
);
}
}
/* Hide scrollbar but keep scroll */
.no-scrollbar::-webkit-scrollbar {
display: none;
}
.no-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
}
@keyframes
fadeOverlayIn
{
from
{
opacity
:
0
;
}
to
{
opacity
:
1
;
}
}
/* Dot grid background */
.bg-dot-grid {
background-image: radial-gradient(
circle,
rgba(255, 255, 255, 0.05) 1px,
transparent 1px
);
background-size: 24px 24px;
}
@keyframes
fadeOverlayOut
{
from
{
opacity
:
1
;
}
to
{
opacity
:
0
;
}
/* Line grid background */
.bg-line-grid {
background-image:
linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
background-size: 40px 40px;
}
}
.animate-fade-in
{
animation
:
fadeIn
0.2s
ease-out
both
;
}
.animate-slide-in
{
animation
:
slideInLeft
0.25s
cubic-bezier
(
0.16
,
1
,
0.3
,
1
)
both
;
}
.animate-slide-out
{
animation
:
slideOutLeft
0.2s
ease-in
both
;
}
.animate-overlay-in
{
animation
:
fadeOverlayIn
0.2s
ease-out
both
;
}
.animate-overlay-out
{
animation
:
fadeOverlayOut
0.15s
ease-in
both
;
}
/* ═══════════════════════════════════════════════════
MOBILE INPUT FIXES
TYPOGRAPHY — Prose overrides for chat
═══════════════════════════════════════════════════ */
textarea
,
input
,
select
{
font-size
:
16px
!important
;
/* Prevents iOS zoom on focus */
}
@media
(
min-width
:
640px
)
{
textarea
,
input
,
select
{
font-size
:
14px
!important
;
@layer components {
.prose-anton {
@apply prose prose-anton prose-sm max-w-none;
}
}
textarea
{
-webkit-appearance
:
none
;
appearance
:
none
;
}
select
{
-webkit-appearance
:
none
;
appearance
:
none
;
background-image
:
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='%23666' viewBox='0 0 16 16'%3E%3Cpath d='M8 11L3 6h10z'/%3E%3C/svg%3E")
;
background-repeat
:
no-repeat
;
background-position
:
right
10px
center
;
padding-right
:
28px
;
}
.prose-anton pre {
@apply bg-[hsl(230,16%,10%)] border border-[hsl(230,14%,16%)] rounded-xl my-4;
}
/* ═══════════════════════════════════════════════════
TOUCH-FRIENDLY RANGE SLIDER
═══════════════════════════════════════════════════ */
.prose-anton table {
@apply w-full text-xs border-collapse;
}
input
[
type
=
"range"
]
{
-webkit-appearance
:
none
;
appearance
:
none
;
width
:
100%
;
height
:
6px
;
border-radius
:
3px
;
background
:
rgba
(
255
,
255
,
255
,
0.08
);
outline
:
none
;
cursor
:
pointer
;
}
.prose-anton th {
@apply bg-white/5 px-3 py-2 text-left font-semibold text-white border-b border-[hsl(230,14%,16%)];
}
input
[
type
=
"range"
]
::-webkit-slider-thumb
{
-webkit-appearance
:
none
;
appearance
:
none
;
width
:
22px
;
height
:
22px
;
border-radius
:
50%
;
background
:
#e53e3e
;
border
:
2px
solid
#1a1a2e
;
cursor
:
pointer
;
box-shadow
:
0
0
8px
rgba
(
229
,
62
,
62
,
0.3
);
}
.prose-anton td {
@apply px-3 py-2 border-b border-[hsl(230,14%,16%)];
}
input
[
type
=
"range"
]
::-moz-range-thumb
{
width
:
22px
;
height
:
22px
;
border-radius
:
50%
;
background
:
#e53e3e
;
border
:
2px
solid
#1a1a2e
;
cursor
:
pointer
;
.prose-anton tr:hover td {
@apply bg-white/[0.02];
}
}
/* ═══════════════════════════════════════════════════
MARKDOWN PROSE
RADIX UI OVERRIDES — Dark theme compatible
═══════════════════════════════════════════════════ */
.prose-anton
{
color
:
#e2e2ea
;
line-height
:
1.65
;
word-break
:
break-word
;
overflow-wrap
:
anywhere
;
}
.prose-anton
h1
,
.prose-anton
h2
,
.prose-anton
h3
,
.prose-anton
h4
,
.prose-anton
h5
,
.prose-anton
h6
{
color
:
#fff
;
font-weight
:
600
;
margin-top
:
1.2em
;
margin-bottom
:
0.5em
;
}
.prose-anton
h1
{
font-size
:
1.4em
;
}
.prose-anton
h2
{
font-size
:
1.2em
;
}
.prose-anton
h3
{
font-size
:
1.05em
;
}
.prose-anton
p
{
margin-bottom
:
0.75em
;
}
@layer components {
/* Dialog */
[data-radix-dialog-overlay] {
@apply fixed inset-0 z-50 bg-black/80 backdrop-blur-sm;
animation: fade-in 0.15s ease-out;
}
.prose-anton
ul
,
.prose-anton
ol
{
padding-left
:
1.4em
;
margin-bottom
:
0.75em
;
}
[data-radix-dialog-content] {
@apply fixed left-1/2 top-1/2 z-50 -translate-x-1/2 -translate-y-1/2;
@apply bg-[hsl(var(--popover))] border border-[hsl(var(--border))];
@apply rounded-xl shadow-elevated p-6;
animation: scale-in 0.2s ease-out;
}
.prose-anton
li
{
margin-bottom
:
0.25em
;
}
.prose-anton
li
::marker
{
color
:
#555
;
}
.prose-anton
code
:not
(
pre
code
)
{
background
:
rgba
(
255
,
255
,
255
,
0.06
);
border
:
1px
solid
rgba
(
255
,
255
,
255
,
0.08
);
border-radius
:
4px
;
padding
:
0.15em
0.35em
;
font-family
:
'JetBrains Mono'
,
monospace
;
font-size
:
0.85em
;
color
:
#ff6b6b
;
word-break
:
break-all
;
}
/* Dropdown */
[data-radix-dropdown-menu-content] {
@apply bg-[hsl(var(--popover))] border border-[hsl(var(--border))];
@apply rounded-lg shadow-elevated p-1 min-w-[8rem];
animation: scale-in 0.15s ease-out;
}
.prose-anton
a
{
color
:
#e53e3e
;
text-decoration
:
underli
ne
;
text-underline-offset
:
2px
;
}
[data-radix-dropdown-menu-item]
{
@apply relative flex cursor-pointer select-none items-center rounded-md px-2 py-1.5 text-sm
;
@apply text-[hsl(var(--foreground))] outline-no
ne;
@apply transition-colors hover:bg-white/5 focus:bg-white/5
;
}
.prose-anton
blockquote
{
border-left
:
3px
solid
#e53e3e
;
padding
:
0.5em
1em
;
margin
:
0.75em
0
;
background
:
rgba
(
229
,
62
,
62
,
0.04
);
border-radius
:
0
6px
6px
0
;
color
:
#aaa
;
}
/* Tooltip */
[data-radix-tooltip-content] {
@apply bg-[hsl(var(--popover))] border border-[hsl(var(--border))];
@apply rounded-md px-3 py-1.5 text-xs shadow-lg;
animation: fade-in 0.1s ease-out;
}
.prose-anton
hr
{
border
:
none
;
border-top
:
1px
solid
rgba
(
255
,
255
,
255
,
0.08
);
margin
:
1.5em
0
;
}
/* Select */
[data-radix-select-content] {
@apply bg-[hsl(var(--popover))] border border-[hsl(var(--border))];
@apply rounded-lg shadow-elevated overflow-hidden;
animation: scale-in 0.15s ease-out;
}
.prose-anton
table
{
width
:
100%
;
border-collapse
:
collapse
;
font-size
:
0.85em
;
margin
:
0.75em
0
;
display
:
block
;
overflow-x
:
auto
;
-webkit-overflow-scrolling
:
touch
;
[data-radix-select-item] {
@apply relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm;
@apply outline-none transition-colors hover:bg-white/5 focus:bg-white/5;
}
}
.prose-anton
th
,
.prose-anton
td
{
border
:
1px
solid
rgba
(
255
,
255
,
255
,
0.08
);
padding
:
0.4em
0.7em
;
text-align
:
left
;
white-space
:
nowrap
;
}
/* ═══════════════════════════════════════════════════
RANGE INPUT — Styled for dark theme
═══════════════════════════════════════════════════ */
.prose-anton
th
{
background
:
rgba
(
255
,
255
,
255
,
0.04
);
font-weight
:
600
;
@layer base {
input[type="
range
"] {
@apply w-full h-1.5 bg-white/10 rounded-full appearance-none cursor-pointer;
}
input[type="
range
"]::-webkit-slider-thumb {
@apply w-4 h-4 bg-[hsl(var(--primary))] rounded-full appearance-none cursor-pointer;
@apply shadow-md hover:scale-110 transition-transform;
}
input[type="
range
"]::-moz-range-thumb {
@apply w-4 h-4 bg-[hsl(var(--primary))] rounded-full border-0 cursor-pointer;
@apply shadow-md hover:scale-110 transition-transform;
}
input[type="
range
"]:focus {
@apply outline-none;
}
input[type="
range
"
]:
focus
::
-webkit-slider-thumb
{
@
apply
ring-2
ring-
[
hsl
(
var
(
--ring
))]
ring-offset-2
ring-offset-
[
hsl
(
var
(
--background
))];
}
}
.prose-anton
strong
{
color
:
#fff
;
font-weight
:
600
;
}
.prose-anton
em
{
font-style
:
italic
;
}
/* ═══════════════════════════════════════════════════
THINKING PULSE
SELECTION
═══════════════════════════════════════════════════ */
@keyframes
thinkPulse
{
0
%,
100
%
{
opacity
:
1
;
}
50
%
{
opacity
:
0.5
;
}
::selection
{
@apply
bg-red-500/30
text-white;
}
.thinking-pulse
{
animation
:
thinkPulse
1.5s
ease-in-out
infinite
;
}
/* ═══════════════════════════════════════════════════
MOBILE-SPECIFIC OVERRIDES
THINKING PULSE (for AI reasoning indicator)
═══════════════════════════════════════════════════ */
@media
(
max-width
:
639px
)
{
.prose-anton
{
font-size
:
0.9rem
;
line-height
:
1.6
;
}
.prose-anton
h1
{
font-size
:
1.25em
;
}
.prose-anton
h2
{
font-size
:
1.15em
;
}
@keyframes
thinking-pulse-kf
{
0
%,
100
%
{
opacity
:
1
;
}
50
%
{
opacity
:
0.5
;
}
}
/* Prevent body scroll when modal/drawer is open */
body
.drawer-open
{
touch-action
:
none
;
.thinking-pulse
{
animation
:
thinking-pulse-kf
1.5s
ease-in-out
infinite
;
}
\ No newline at end of file
frontend/src/lib/utils.js
0 → 100644
View file @
4918e579
import
{
clsx
}
from
"clsx"
;
import
{
twMerge
}
from
"tailwind-merge"
;
/**
* Merge Tailwind classes intelligently — the foundation of
* every good component library. Handles conflicts like a boss.
*
* Usage: cn("px-4 py-2", isActive && "bg-primary", className)
*/
export
function
cn
(...
inputs
)
{
return
twMerge
(
clsx
(
inputs
));
}
/**
* Format a number with locale-aware separators
*/
export
function
formatNumber
(
n
)
{
if
(
n
==
null
)
return
"0"
;
return
Number
(
n
).
toLocaleString
();
}
/**
* Truncate text with ellipsis
*/
export
function
truncate
(
str
,
maxLength
=
50
)
{
if
(
!
str
||
str
.
length
<=
maxLength
)
return
str
||
""
;
return
str
.
slice
(
0
,
maxLength
)
+
"…"
;
}
/**
* Generate initials from a name
*/
export
function
getInitials
(
name
,
maxChars
=
2
)
{
if
(
!
name
)
return
"?"
;
return
name
.
split
(
/
[\s
_-
]
+/
)
.
map
((
w
)
=>
w
[
0
])
.
filter
(
Boolean
)
.
slice
(
0
,
maxChars
)
.
join
(
""
)
.
toUpperCase
();
}
\ No newline at end of file
frontend/tailwind.config.js
View file @
4918e579
/** @type {import('tailwindcss').Config} */
export
default
{
darkMode
:
"class"
,
content
:
[
"./index.html"
,
"./src/**/*.{js,ts,jsx,tsx}"
],
theme
:
{
container
:
{
center
:
true
,
padding
:
"2rem"
,
screens
:
{
"2xl"
:
"1400px"
},
},
extend
:
{
colors
:
{
"anton-bg"
:
"#09090f"
,
"anton-surface"
:
"#0f0f1a"
,
"anton-card"
:
"#16162a"
,
"anton-border"
:
"#1e1e3a"
,
"anton-text"
:
"#e2e2ea"
,
"anton-muted"
:
"#6b6b8a"
,
"anton-accent"
:
"#e53e3e"
,
"anton-success"
:
"#48bb78"
,
"anton-danger"
:
"#e53e3e"
,
// ── Core brand ──
anton
:
{
bg
:
"hsl(var(--anton-bg) / <alpha-value>)"
,
surface
:
"hsl(var(--anton-surface) / <alpha-value>)"
,
card
:
"hsl(var(--anton-card) / <alpha-value>)"
,
border
:
"hsl(var(--anton-border) / <alpha-value>)"
,
text
:
"hsl(var(--anton-text) / <alpha-value>)"
,
muted
:
"hsl(var(--anton-muted) / <alpha-value>)"
,
accent
:
"hsl(var(--anton-accent) / <alpha-value>)"
,
success
:
"hsl(var(--anton-success) / <alpha-value>)"
,
danger
:
"hsl(var(--anton-danger) / <alpha-value>)"
,
warning
:
"hsl(var(--anton-warning) / <alpha-value>)"
,
info
:
"hsl(var(--anton-info) / <alpha-value>)"
,
},
// ── shadcn-compatible semantic tokens ──
border
:
"hsl(var(--border) / <alpha-value>)"
,
input
:
"hsl(var(--input) / <alpha-value>)"
,
ring
:
"hsl(var(--ring) / <alpha-value>)"
,
background
:
"hsl(var(--background) / <alpha-value>)"
,
foreground
:
"hsl(var(--foreground) / <alpha-value>)"
,
primary
:
{
DEFAULT
:
"hsl(var(--primary) / <alpha-value>)"
,
foreground
:
"hsl(var(--primary-foreground) / <alpha-value>)"
,
},
secondary
:
{
DEFAULT
:
"hsl(var(--secondary) / <alpha-value>)"
,
foreground
:
"hsl(var(--secondary-foreground) / <alpha-value>)"
,
},
destructive
:
{
DEFAULT
:
"hsl(var(--destructive) / <alpha-value>)"
,
foreground
:
"hsl(var(--destructive-foreground) / <alpha-value>)"
,
},
muted
:
{
DEFAULT
:
"hsl(var(--muted) / <alpha-value>)"
,
foreground
:
"hsl(var(--muted-foreground) / <alpha-value>)"
,
},
accent
:
{
DEFAULT
:
"hsl(var(--accent) / <alpha-value>)"
,
foreground
:
"hsl(var(--accent-foreground) / <alpha-value>)"
,
},
popover
:
{
DEFAULT
:
"hsl(var(--popover) / <alpha-value>)"
,
foreground
:
"hsl(var(--popover-foreground) / <alpha-value>)"
,
},
card
:
{
DEFAULT
:
"hsl(var(--card) / <alpha-value>)"
,
foreground
:
"hsl(var(--card-foreground) / <alpha-value>)"
,
},
},
borderRadius
:
{
lg
:
"var(--radius)"
,
md
:
"calc(var(--radius) - 2px)"
,
sm
:
"calc(var(--radius) - 4px)"
,
},
fontFamily
:
{
sans
:
[
"Inter"
,
"system-ui"
,
"-apple-system"
,
"sans-serif"
],
mono
:
[
"JetBrains Mono"
,
"Fira Code"
,
"monospace"
],
display
:
[
"Inter"
,
"system-ui"
,
"sans-serif"
],
},
fontSize
:
{
"2xs"
:
[
"0.625rem"
,
{
lineHeight
:
"0.875rem"
}],
},
spacing
:
{
"4.5"
:
"1.125rem"
,
"5.5"
:
"1.375rem"
,
"13"
:
"3.25rem"
,
"15"
:
"3.75rem"
,
"17"
:
"4.25rem"
,
"18"
:
"4.5rem"
,
"112"
:
"28rem"
,
"128"
:
"32rem"
,
"144"
:
"36rem"
,
},
backdropBlur
:
{
xs
:
"2px"
,
},
boxShadow
:
{
glow
:
"0 0 20px rgba(229, 62, 62, 0.15)"
,
"glow-lg"
:
"0 0 40px rgba(229, 62, 62, 0.2)"
,
"inner-glow"
:
"inset 0 0 20px rgba(229, 62, 62, 0.05)"
,
"card-hover"
:
"0 8px 30px rgba(0, 0, 0, 0.3), 0 0 1px rgba(255, 255, 255, 0.05)"
,
"elevated"
:
"0 20px 60px rgba(0, 0, 0, 0.4)"
,
},
keyframes
:
{
"fade-in"
:
{
from
:
{
opacity
:
"0"
,
transform
:
"translateY(8px)"
},
to
:
{
opacity
:
"1"
,
transform
:
"translateY(0)"
},
},
"fade-out"
:
{
from
:
{
opacity
:
"1"
,
transform
:
"translateY(0)"
},
to
:
{
opacity
:
"0"
,
transform
:
"translateY(8px)"
},
},
"slide-in-from-right"
:
{
from
:
{
transform
:
"translateX(100%)"
},
to
:
{
transform
:
"translateX(0)"
},
},
"slide-in-from-left"
:
{
from
:
{
transform
:
"translateX(-100%)"
},
to
:
{
transform
:
"translateX(0)"
},
},
"slide-in-from-top"
:
{
from
:
{
transform
:
"translateY(-100%)"
},
to
:
{
transform
:
"translateY(0)"
},
},
"slide-in-from-bottom"
:
{
from
:
{
transform
:
"translateY(100%)"
},
to
:
{
transform
:
"translateY(0)"
},
},
"scale-in"
:
{
from
:
{
opacity
:
"0"
,
transform
:
"scale(0.95)"
},
to
:
{
opacity
:
"1"
,
transform
:
"scale(1)"
},
},
"spin-slow"
:
{
from
:
{
transform
:
"rotate(0deg)"
},
to
:
{
transform
:
"rotate(360deg)"
},
},
shimmer
:
{
"0%"
:
{
backgroundPosition
:
"-200% 0"
},
"100%"
:
{
backgroundPosition
:
"200% 0"
},
},
"pulse-glow"
:
{
"0%, 100%"
:
{
boxShadow
:
"0 0 5px rgba(229, 62, 62, 0.2)"
},
"50%"
:
{
boxShadow
:
"0 0 20px rgba(229, 62, 62, 0.4)"
},
},
"accordion-down"
:
{
from
:
{
height
:
"0"
},
to
:
{
height
:
"var(--radix-accordion-content-height)"
},
},
"accordion-up"
:
{
from
:
{
height
:
"var(--radix-accordion-content-height)"
},
to
:
{
height
:
"0"
},
},
float
:
{
"0%, 100%"
:
{
transform
:
"translateY(0px)"
},
"50%"
:
{
transform
:
"translateY(-6px)"
},
},
"border-beam"
:
{
"100%"
:
{
offsetDistance
:
"100%"
},
},
},
animation
:
{
"fade-in"
:
"fade-in 0.3s ease-out"
,
"fade-out"
:
"fade-out 0.3s ease-out"
,
"slide-in-right"
:
"slide-in-from-right 0.3s ease-out"
,
"slide-in-left"
:
"slide-in-from-left 0.3s ease-out"
,
"slide-in-top"
:
"slide-in-from-top 0.3s ease-out"
,
"slide-in-bottom"
:
"slide-in-from-bottom 0.3s ease-out"
,
"scale-in"
:
"scale-in 0.2s ease-out"
,
"spin-slow"
:
"spin-slow 3s linear infinite"
,
shimmer
:
"shimmer 2s linear infinite"
,
"pulse-glow"
:
"pulse-glow 2s ease-in-out infinite"
,
"accordion-down"
:
"accordion-down 0.2s ease-out"
,
"accordion-up"
:
"accordion-up 0.2s ease-out"
,
float
:
"float 3s ease-in-out infinite"
,
"border-beam"
:
"border-beam calc(var(--duration)*1s) infinite linear"
,
},
screens
:
{
"xs"
:
"400px"
,
typography
:
{
anton
:
{
css
:
{
"--tw-prose-body"
:
"hsl(var(--anton-text))"
,
"--tw-prose-headings"
:
"#ffffff"
,
"--tw-prose-links"
:
"hsl(var(--anton-accent))"
,
"--tw-prose-bold"
:
"#ffffff"
,
"--tw-prose-code"
:
"hsl(var(--anton-accent))"
,
"--tw-prose-pre-bg"
:
"hsl(var(--anton-card))"
,
"--tw-prose-pre-code"
:
"hsl(var(--anton-text))"
,
"--tw-prose-quotes"
:
"hsl(var(--anton-muted))"
,
"--tw-prose-quote-borders"
:
"hsl(var(--anton-accent))"
,
"--tw-prose-hr"
:
"hsl(var(--anton-border))"
,
"--tw-prose-th-borders"
:
"hsl(var(--anton-border))"
,
"--tw-prose-td-borders"
:
"hsl(var(--anton-border))"
,
maxWidth
:
"none"
,
a
:
{
textDecoration
:
"none"
,
fontWeight
:
"500"
},
"a:hover"
:
{
color
:
"hsl(var(--anton-accent))"
},
code
:
{
backgroundColor
:
"rgba(255,255,255,0.06)"
,
padding
:
"0.15em 0.35em"
,
borderRadius
:
"0.25em"
,
fontWeight
:
"400"
,
},
"code::before"
:
{
content
:
'""'
},
"code::after"
:
{
content
:
'""'
},
pre
:
{
backgroundColor
:
"hsl(var(--anton-card))"
,
border
:
"1px solid hsl(var(--anton-border))"
,
borderRadius
:
"0.75rem"
,
},
table
:
{
fontSize
:
"0.875rem"
},
th
:
{
fontWeight
:
"600"
,
color
:
"#ffffff"
},
img
:
{
borderRadius
:
"0.75rem"
},
hr
:
{
borderColor
:
"hsl(var(--anton-border))"
},
blockquote
:
{
borderLeftColor
:
"hsl(var(--anton-accent))"
,
fontStyle
:
"normal"
,
},
},
},
},
},
},
plugins
:
[],
plugins
:
[
require
(
"@tailwindcss/typography"
),
require
(
"@tailwindcss/forms"
)({
strategy
:
"class"
}),
require
(
"@tailwindcss/container-queries"
),
require
(
"tailwindcss-animate"
),
],
};
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment