updated colors and styling
This commit is contained in:
parent
57f3344641
commit
a747f3712d
6 changed files with 237 additions and 231 deletions
|
|
@ -3,7 +3,7 @@ import { cva, type VariantProps } from "class-variance-authority";
|
|||
import * as React from "react";
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-70 disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
|
@ -11,7 +11,7 @@ const buttonVariants = cva(
|
|||
destructive:
|
||||
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input hover:bg-muted hover:text-accent-foreground",
|
||||
"border border-input hover:bg-muted hover:text-accent-foreground disabled:bg-muted disabled:!border-none",
|
||||
primary:
|
||||
"border bg-background text-secondary-foreground hover:bg-muted hover:shadow-sm",
|
||||
warning:
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
--accent-emerald-foreground: 161.4 93.5% 30.4%;
|
||||
--accent-pink-foreground: 333.3 71.4% 50.6%;
|
||||
--accent-amber-foreground: 26 90.5% 37.1%;
|
||||
|
||||
/* Status Colors */
|
||||
--status-red: #ef4444;
|
||||
|
|
@ -90,6 +91,7 @@
|
|||
|
||||
--accent-emerald-foreground: 158.1 64.4% 51.6%;
|
||||
--accent-pink-foreground: 328.6 85.5% 70.2%;
|
||||
--accent-amber-foreground: 45.9 96.7% 64.5%;
|
||||
|
||||
/* Dark mode data type colors */
|
||||
--datatype-blue: 211.7 96.4% 78.4%;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { useState } from "react";
|
||||
import { LabelInput } from "@/components/label-input";
|
||||
import IBMLogo from "@/components/logo/ibm-logo";
|
||||
import { useDebouncedValue } from "@/lib/debounce";
|
||||
import type { OnboardingVariables } from "../../api/mutations/useOnboardingMutation";
|
||||
import { useGetIBMModelsQuery } from "../../api/queries/useGetModelsQuery";
|
||||
import { useModelSelection } from "../hooks/useModelSelection";
|
||||
import { useUpdateSettings } from "../hooks/useUpdateSettings";
|
||||
import { useDebouncedValue } from "@/lib/debounce";
|
||||
import { AdvancedOnboarding } from "./advanced";
|
||||
|
||||
export function IBMOnboarding({
|
||||
|
|
@ -96,19 +96,21 @@ export function IBMOnboarding({
|
|||
onChange={(e) => setProjectId(e.target.value)}
|
||||
/>
|
||||
{isLoadingModels && (
|
||||
<p className="text-sm text-muted-foreground">
|
||||
<p className="text-mmd text-muted-foreground">
|
||||
Validating configuration...
|
||||
</p>
|
||||
)}
|
||||
{modelsError && (
|
||||
<p className="text-sm text-red-500">
|
||||
<p className="text-mmd text-accent-amber-foreground">
|
||||
Invalid configuration or connection failed
|
||||
</p>
|
||||
)}
|
||||
{modelsData &&
|
||||
(modelsData.language_models?.length > 0 ||
|
||||
modelsData.embedding_models?.length > 0) && (
|
||||
<p className="text-sm text-green-600">Configuration is valid</p>
|
||||
<p className="text-mmd text-accent-emerald-foreground">
|
||||
Configuration is valid
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<AdvancedOnboarding
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import { useState } from "react";
|
|||
import { LabelInput } from "@/components/label-input";
|
||||
import { LabelWrapper } from "@/components/label-wrapper";
|
||||
import OllamaLogo from "@/components/logo/ollama-logo";
|
||||
import { useDebouncedValue } from "@/lib/debounce";
|
||||
import type { OnboardingVariables } from "../../api/mutations/useOnboardingMutation";
|
||||
import { useGetOllamaModelsQuery } from "../../api/queries/useGetModelsQuery";
|
||||
import { useModelSelection } from "../hooks/useModelSelection";
|
||||
import { useUpdateSettings } from "../hooks/useUpdateSettings";
|
||||
import { useDebouncedValue } from "@/lib/debounce";
|
||||
import { AdvancedOnboarding } from "./advanced";
|
||||
import { ModelSelector } from "./model-selector";
|
||||
|
||||
|
|
@ -70,62 +70,66 @@ export function OllamaOnboarding({
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="space-y-1">
|
||||
<LabelInput
|
||||
label="Ollama Endpoint"
|
||||
helperText="The endpoint for your Ollama server."
|
||||
id="api-endpoint"
|
||||
required
|
||||
placeholder="http://localhost:11434"
|
||||
value={endpoint}
|
||||
onChange={(e) => setEndpoint(e.target.value)}
|
||||
/>
|
||||
{isConnecting && (
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Connecting to Ollama server...
|
||||
</p>
|
||||
)}
|
||||
{hasConnectionError && (
|
||||
<p className="text-sm text-red-500">
|
||||
Cannot connect to Ollama server. Please check the endpoint.
|
||||
</p>
|
||||
)}
|
||||
{hasNoModels && (
|
||||
<p className="text-sm text-yellow-600">
|
||||
No models found. Please install some models on your Ollama server.
|
||||
</p>
|
||||
)}
|
||||
{isValidConnection && (
|
||||
<p className="text-sm text-green-600">Connected successfully</p>
|
||||
)}
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-1">
|
||||
<LabelInput
|
||||
label="Ollama Endpoint"
|
||||
helperText="The endpoint for your Ollama server."
|
||||
id="api-endpoint"
|
||||
required
|
||||
placeholder="http://localhost:11434"
|
||||
value={endpoint}
|
||||
onChange={(e) => setEndpoint(e.target.value)}
|
||||
/>
|
||||
{isConnecting && (
|
||||
<p className="text-mmd text-muted-foreground">
|
||||
Connecting to Ollama server...
|
||||
</p>
|
||||
)}
|
||||
{hasConnectionError && (
|
||||
<p className="text-mmd text-accent-amber-foreground">
|
||||
Can’t reach Ollama at {debouncedEndpoint}. Update the endpoint or
|
||||
start the server.
|
||||
</p>
|
||||
)}
|
||||
{hasNoModels && (
|
||||
<p className="text-mmd text-accent-amber-foreground">
|
||||
No models found. Please install some models on your Ollama server.
|
||||
</p>
|
||||
)}
|
||||
{isValidConnection && (
|
||||
<p className="text-mmd text-accent-emerald-foreground">
|
||||
Connected successfully
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<LabelWrapper
|
||||
label="Embedding model"
|
||||
helperText="The embedding model for your Ollama server."
|
||||
id="embedding-model"
|
||||
required={true}
|
||||
>
|
||||
<ModelSelector
|
||||
options={embeddingModels}
|
||||
icon={<OllamaLogo className="w-4 h-4" />}
|
||||
value={embeddingModel}
|
||||
onValueChange={setEmbeddingModel}
|
||||
/>
|
||||
</LabelWrapper>
|
||||
<LabelWrapper
|
||||
label="Language model"
|
||||
helperText="The embedding model for your Ollama server."
|
||||
id="embedding-model"
|
||||
required={true}
|
||||
>
|
||||
<ModelSelector
|
||||
options={languageModels}
|
||||
icon={<OllamaLogo className="w-4 h-4" />}
|
||||
value={languageModel}
|
||||
onValueChange={setLanguageModel}
|
||||
/>
|
||||
</LabelWrapper>
|
||||
</div>
|
||||
<LabelWrapper
|
||||
label="Embedding model"
|
||||
helperText="The embedding model for your Ollama server."
|
||||
id="embedding-model"
|
||||
required={true}
|
||||
>
|
||||
<ModelSelector
|
||||
options={embeddingModels}
|
||||
icon={<OllamaLogo className="w-4 h-4" />}
|
||||
value={embeddingModel}
|
||||
onValueChange={setEmbeddingModel}
|
||||
/>
|
||||
</LabelWrapper>
|
||||
<LabelWrapper
|
||||
label="Language model"
|
||||
helperText="The embedding model for your Ollama server."
|
||||
id="embedding-model"
|
||||
required={true}
|
||||
>
|
||||
<ModelSelector
|
||||
options={languageModels}
|
||||
icon={<OllamaLogo className="w-4 h-4" />}
|
||||
value={languageModel}
|
||||
onValueChange={setLanguageModel}
|
||||
/>
|
||||
</LabelWrapper>
|
||||
|
||||
<AdvancedOnboarding
|
||||
sampleDataset={sampleDataset}
|
||||
setSampleDataset={handleSampleDatasetChange}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { useState } from "react";
|
||||
import { LabelInput } from "@/components/label-input";
|
||||
import OpenAILogo from "@/components/logo/openai-logo";
|
||||
import { useDebouncedValue } from "@/lib/debounce";
|
||||
import type { OnboardingVariables } from "../../api/mutations/useOnboardingMutation";
|
||||
import { useGetOpenAIModelsQuery } from "../../api/queries/useGetModelsQuery";
|
||||
import { useModelSelection } from "../hooks/useModelSelection";
|
||||
import { useUpdateSettings } from "../hooks/useUpdateSettings";
|
||||
import { useDebouncedValue } from "@/lib/debounce";
|
||||
import { AdvancedOnboarding } from "./advanced";
|
||||
|
||||
export function OpenAIOnboarding({
|
||||
|
|
@ -64,17 +64,21 @@ export function OpenAIOnboarding({
|
|||
onChange={(e) => setApiKey(e.target.value)}
|
||||
/>
|
||||
{isLoadingModels && (
|
||||
<p className="text-sm text-muted-foreground">Validating API key...</p>
|
||||
<p className="text-mmd text-muted-foreground">
|
||||
Validating API key...
|
||||
</p>
|
||||
)}
|
||||
{modelsError && (
|
||||
<p className="text-sm text-red-500">
|
||||
Invalid API key or configuration
|
||||
<p className="text-mmd text-accent-amber-foreground">
|
||||
Invalid API key
|
||||
</p>
|
||||
)}
|
||||
{modelsData &&
|
||||
(modelsData.language_models?.length > 0 ||
|
||||
modelsData.embedding_models?.length > 0) && (
|
||||
<p className="text-sm text-green-600">Configuration is valid</p>
|
||||
<p className="text-mmd text-accent-emerald-foreground">
|
||||
API Key is valid
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<AdvancedOnboarding
|
||||
|
|
|
|||
|
|
@ -14,170 +14,164 @@ const config = {
|
|||
"./src/**/*.{ts,tsx}",
|
||||
],
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
screens: {
|
||||
'2xl': '1400px',
|
||||
'3xl': '1500px'
|
||||
}
|
||||
},
|
||||
extend: {
|
||||
screens: {
|
||||
xl: '1200px',
|
||||
'2xl': '1400px',
|
||||
'3xl': '1500px'
|
||||
},
|
||||
keyframes: {
|
||||
overlayShow: {
|
||||
from: {
|
||||
opacity: 0
|
||||
},
|
||||
to: {
|
||||
opacity: 1
|
||||
}
|
||||
},
|
||||
contentShow: {
|
||||
from: {
|
||||
opacity: 0,
|
||||
transform: 'translate(-50%, -50%) scale(0.95)',
|
||||
clipPath: 'inset(50% 0)'
|
||||
},
|
||||
to: {
|
||||
opacity: 1,
|
||||
transform: 'translate(-50%, -50%) scale(1)',
|
||||
clipPath: 'inset(0% 0)'
|
||||
}
|
||||
},
|
||||
wiggle: {
|
||||
'0%, 100%': {
|
||||
transform: 'scale(100%)'
|
||||
},
|
||||
'50%': {
|
||||
transform: 'scale(120%)'
|
||||
}
|
||||
},
|
||||
'accordion-down': {
|
||||
from: {
|
||||
height: '0'
|
||||
},
|
||||
to: {
|
||||
height: 'var(--radix-accordion-content-height)'
|
||||
}
|
||||
},
|
||||
'accordion-up': {
|
||||
from: {
|
||||
height: 'var(--radix-accordion-content-height)'
|
||||
},
|
||||
to: {
|
||||
height: '0'
|
||||
}
|
||||
}
|
||||
},
|
||||
animation: {
|
||||
overlayShow: 'overlayShow 400ms cubic-bezier(0.16, 1, 0.3, 1)',
|
||||
contentShow: 'contentShow 400ms cubic-bezier(0.16, 1, 0.3, 1)',
|
||||
wiggle: 'wiggle 150ms ease-in-out 1',
|
||||
'accordion-down': 'accordion-down 0.2s ease-out',
|
||||
'accordion-up': 'accordion-up 0.2s ease-out'
|
||||
},
|
||||
colors: {
|
||||
border: 'hsl(var(--border))',
|
||||
input: 'hsl(var(--input))',
|
||||
ring: 'hsl(var(--ring))',
|
||||
background: 'hsl(var(--background))',
|
||||
foreground: 'hsl(var(--foreground))',
|
||||
primary: {
|
||||
DEFAULT: 'hsl(var(--primary))',
|
||||
foreground: 'hsl(var(--primary-foreground))',
|
||||
hover: 'hsl(var(--primary-hover))'
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: 'hsl(var(--secondary))',
|
||||
foreground: 'hsl(var(--secondary-foreground))',
|
||||
hover: 'hsl(var(--secondary-hover))'
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: 'hsl(var(--destructive))',
|
||||
foreground: 'hsl(var(--destructive-foreground))'
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: 'hsl(var(--muted))',
|
||||
foreground: 'hsl(var(--muted-foreground))'
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: 'hsl(var(--accent))',
|
||||
foreground: 'hsl(var(--accent-foreground))'
|
||||
},
|
||||
'accent-emerald-foreground': {
|
||||
DEFAULT: 'hsl(var(--accent-emerald-foreground))'
|
||||
},
|
||||
'accent-pink-foreground': {
|
||||
DEFAULT: 'hsl(var(--accent-pink-foreground))'
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: 'hsl(var(--popover))',
|
||||
foreground: 'hsl(var(--popover-foreground))'
|
||||
},
|
||||
card: {
|
||||
DEFAULT: 'hsl(var(--card))',
|
||||
foreground: 'hsl(var(--card-foreground))'
|
||||
},
|
||||
'status-blue': 'var(--status-blue)',
|
||||
'status-green': 'var(--status-green)',
|
||||
'status-red': 'var(--status-red)',
|
||||
'status-yellow': 'var(--status-yellow)',
|
||||
'component-icon': 'var(--component-icon)',
|
||||
'flow-icon': 'var(--flow-icon)',
|
||||
'placeholder-foreground': 'hsl(var(--placeholder-foreground))',
|
||||
'datatype-blue': {
|
||||
DEFAULT: 'hsl(var(--datatype-blue))',
|
||||
foreground: 'hsl(var(--datatype-blue-foreground))'
|
||||
},
|
||||
'datatype-yellow': {
|
||||
DEFAULT: 'hsl(var(--datatype-yellow))',
|
||||
foreground: 'hsl(var(--datatype-yellow-foreground))'
|
||||
},
|
||||
'datatype-red': {
|
||||
DEFAULT: 'hsl(var(--datatype-red))',
|
||||
foreground: 'hsl(var(--datatype-red-foreground))'
|
||||
},
|
||||
'datatype-emerald': {
|
||||
DEFAULT: 'hsl(var(--datatype-emerald))',
|
||||
foreground: 'hsl(var(--datatype-emerald-foreground))'
|
||||
},
|
||||
'datatype-violet': {
|
||||
DEFAULT: 'hsl(var(--datatype-violet))',
|
||||
foreground: 'hsl(var(--datatype-violet-foreground))'
|
||||
},
|
||||
warning: {
|
||||
DEFAULT: 'hsl(var(--warning))',
|
||||
foreground: 'hsl(var(--warning-foreground))'
|
||||
}
|
||||
},
|
||||
borderRadius: {
|
||||
lg: 'var(--radius)',
|
||||
md: 'calc(var(--radius) - 2px)',
|
||||
sm: 'calc(var(--radius) - 4px)'
|
||||
},
|
||||
fontFamily: {
|
||||
sans: [
|
||||
'var(--font-sans)',
|
||||
...fontFamily.sans
|
||||
],
|
||||
mono: [
|
||||
'var(--font-mono)',
|
||||
...fontFamily.mono
|
||||
],
|
||||
chivo: [
|
||||
'var(--font-chivo)',
|
||||
...fontFamily.sans
|
||||
]
|
||||
},
|
||||
fontSize: {
|
||||
xxs: '11px',
|
||||
mmd: '13px'
|
||||
}
|
||||
}
|
||||
container: {
|
||||
center: true,
|
||||
screens: {
|
||||
"2xl": "1400px",
|
||||
"3xl": "1500px",
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
screens: {
|
||||
xl: "1200px",
|
||||
"2xl": "1400px",
|
||||
"3xl": "1500px",
|
||||
},
|
||||
keyframes: {
|
||||
overlayShow: {
|
||||
from: {
|
||||
opacity: 0,
|
||||
},
|
||||
to: {
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
contentShow: {
|
||||
from: {
|
||||
opacity: 0,
|
||||
transform: "translate(-50%, -50%) scale(0.95)",
|
||||
clipPath: "inset(50% 0)",
|
||||
},
|
||||
to: {
|
||||
opacity: 1,
|
||||
transform: "translate(-50%, -50%) scale(1)",
|
||||
clipPath: "inset(0% 0)",
|
||||
},
|
||||
},
|
||||
wiggle: {
|
||||
"0%, 100%": {
|
||||
transform: "scale(100%)",
|
||||
},
|
||||
"50%": {
|
||||
transform: "scale(120%)",
|
||||
},
|
||||
},
|
||||
"accordion-down": {
|
||||
from: {
|
||||
height: "0",
|
||||
},
|
||||
to: {
|
||||
height: "var(--radix-accordion-content-height)",
|
||||
},
|
||||
},
|
||||
"accordion-up": {
|
||||
from: {
|
||||
height: "var(--radix-accordion-content-height)",
|
||||
},
|
||||
to: {
|
||||
height: "0",
|
||||
},
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
overlayShow: "overlayShow 400ms cubic-bezier(0.16, 1, 0.3, 1)",
|
||||
contentShow: "contentShow 400ms cubic-bezier(0.16, 1, 0.3, 1)",
|
||||
wiggle: "wiggle 150ms ease-in-out 1",
|
||||
"accordion-down": "accordion-down 0.2s ease-out",
|
||||
"accordion-up": "accordion-up 0.2s ease-out",
|
||||
},
|
||||
colors: {
|
||||
border: "hsl(var(--border))",
|
||||
input: "hsl(var(--input))",
|
||||
ring: "hsl(var(--ring))",
|
||||
background: "hsl(var(--background))",
|
||||
foreground: "hsl(var(--foreground))",
|
||||
primary: {
|
||||
DEFAULT: "hsl(var(--primary))",
|
||||
foreground: "hsl(var(--primary-foreground))",
|
||||
hover: "hsl(var(--primary-hover))",
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: "hsl(var(--secondary))",
|
||||
foreground: "hsl(var(--secondary-foreground))",
|
||||
hover: "hsl(var(--secondary-hover))",
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: "hsl(var(--destructive))",
|
||||
foreground: "hsl(var(--destructive-foreground))",
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: "hsl(var(--muted))",
|
||||
foreground: "hsl(var(--muted-foreground))",
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: "hsl(var(--accent))",
|
||||
foreground: "hsl(var(--accent-foreground))",
|
||||
},
|
||||
"accent-emerald-foreground": {
|
||||
DEFAULT: "hsl(var(--accent-emerald-foreground))",
|
||||
},
|
||||
"accent-pink-foreground": {
|
||||
DEFAULT: "hsl(var(--accent-pink-foreground))",
|
||||
},
|
||||
"accent-amber-foreground": {
|
||||
DEFAULT: "hsl(var(--accent-amber-foreground))",
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: "hsl(var(--popover))",
|
||||
foreground: "hsl(var(--popover-foreground))",
|
||||
},
|
||||
card: {
|
||||
DEFAULT: "hsl(var(--card))",
|
||||
foreground: "hsl(var(--card-foreground))",
|
||||
},
|
||||
"status-blue": "var(--status-blue)",
|
||||
"status-green": "var(--status-green)",
|
||||
"status-red": "var(--status-red)",
|
||||
"status-yellow": "var(--status-yellow)",
|
||||
"component-icon": "var(--component-icon)",
|
||||
"flow-icon": "var(--flow-icon)",
|
||||
"placeholder-foreground": "hsl(var(--placeholder-foreground))",
|
||||
"datatype-blue": {
|
||||
DEFAULT: "hsl(var(--datatype-blue))",
|
||||
foreground: "hsl(var(--datatype-blue-foreground))",
|
||||
},
|
||||
"datatype-yellow": {
|
||||
DEFAULT: "hsl(var(--datatype-yellow))",
|
||||
foreground: "hsl(var(--datatype-yellow-foreground))",
|
||||
},
|
||||
"datatype-red": {
|
||||
DEFAULT: "hsl(var(--datatype-red))",
|
||||
foreground: "hsl(var(--datatype-red-foreground))",
|
||||
},
|
||||
"datatype-emerald": {
|
||||
DEFAULT: "hsl(var(--datatype-emerald))",
|
||||
foreground: "hsl(var(--datatype-emerald-foreground))",
|
||||
},
|
||||
"datatype-violet": {
|
||||
DEFAULT: "hsl(var(--datatype-violet))",
|
||||
foreground: "hsl(var(--datatype-violet-foreground))",
|
||||
},
|
||||
warning: {
|
||||
DEFAULT: "hsl(var(--warning))",
|
||||
foreground: "hsl(var(--warning-foreground))",
|
||||
},
|
||||
},
|
||||
borderRadius: {
|
||||
lg: "var(--radius)",
|
||||
md: "calc(var(--radius) - 2px)",
|
||||
sm: "calc(var(--radius) - 4px)",
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ["var(--font-sans)", ...fontFamily.sans],
|
||||
mono: ["var(--font-mono)", ...fontFamily.mono],
|
||||
chivo: ["var(--font-chivo)", ...fontFamily.sans],
|
||||
},
|
||||
fontSize: {
|
||||
xxs: "11px",
|
||||
mmd: "13px",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
tailwindcssAnimate,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue