design signup and login

This commit is contained in:
Mengisteab
2026-06-11 06:55:40 +00:00
parent 2dca5e846d
commit 2aac777d2c
5 changed files with 985 additions and 112 deletions

View File

@@ -0,0 +1,164 @@
import type { ReactNode } from 'react';
import {
Box,
Center,
Flex,
Group,
Stack,
Text,
ThemeIcon,
Title,
rem,
useMantineTheme,
} from '@mantine/core';
import { IconAnchor, IconCheck } from '@tabler/icons-react';
const FEATURES = [
'Submit applications online, 24/7',
'Real-time status tracking & alerts',
'Available in English & አማርኛ',
];
/**
* EMA brand mark — mirrors the logo used in the portal header
* (gradient tile + anchor glyph). Use `variant="white"` on dark backgrounds.
*/
export function BrandMark({
size = 44,
variant = 'gradient',
}: {
size?: number;
variant?: 'gradient' | 'white';
}) {
return (
<ThemeIcon
size={size}
radius="md"
variant={variant === 'white' ? 'white' : 'gradient'}
color={variant === 'white' ? 'emaPrimary' : undefined}
gradient={{ from: 'emaPrimary.7', to: 'emaTeal.5', deg: 135 }}
>
<IconAnchor size={Math.round(size * 0.52)} />
</ThemeIcon>
);
}
interface AuthShellProps {
children: ReactNode;
brandTitle?: string;
brandSubtitle?: string;
}
/**
* Two-pane auth layout: a branded gradient panel (hidden below `md`) and the
* form pane. Standalone (rendered outside the portal chrome and i18n provider),
* so copy here is plain English to match the other auth pages.
*/
export function AuthShell({
children,
brandTitle = 'Maritime licensing, made simple.',
brandSubtitle = 'Apply for vessel and seafarer licenses, upload documents, and track every application in one secure portal.',
}: AuthShellProps) {
const theme = useMantineTheme();
const heroGradient = theme.other.heroGradient as string;
return (
<Flex mih="100vh">
{/* ---- Brand panel ---------------------------------------------- */}
<Box
visibleFrom="md"
w={500}
p={48}
pos="relative"
style={{ background: heroGradient, overflow: 'hidden' }}
>
{/* Decorative blurred orbs for depth */}
<Box
pos="absolute"
top={-120}
right={-80}
w={360}
h={360}
style={{ borderRadius: '50%', background: 'rgba(255,255,255,0.10)' }}
/>
<Box
pos="absolute"
bottom={-140}
left={-100}
w={320}
h={320}
style={{ borderRadius: '50%', background: 'rgba(255,255,255,0.08)' }}
/>
<Flex
direction="column"
justify="space-between"
h="100%"
pos="relative"
style={{ zIndex: 1 }}
>
<Group gap="sm" wrap="nowrap">
<BrandMark variant="white" size={46} />
<div>
<Text c="white" fw={700} fz="lg" lh={1.1}>
EMA Portal
</Text>
<Text fz="xs" lh={1.2} style={{ color: 'rgba(255,255,255,0.75)' }}>
Ethiopian Maritime Authority
</Text>
</div>
</Group>
<Stack gap="xl" maw={400}>
<Stack gap="sm">
<Title order={1} c="white" fz={rem(36)} lh={1.15} fw={700}>
{brandTitle}
</Title>
<Text fz="md" lh={1.6} style={{ color: 'rgba(255,255,255,0.85)' }}>
{brandSubtitle}
</Text>
</Stack>
<Stack gap="md">
{FEATURES.map((feature) => (
<Group key={feature} gap="sm" wrap="nowrap">
<Center
w={24}
h={24}
style={{
borderRadius: '50%',
background: 'rgba(255,255,255,0.2)',
flexShrink: 0,
}}
>
<IconCheck size={14} color="white" stroke={2.4} />
</Center>
<Text c="white" fz="sm" fw={500}>
{feature}
</Text>
</Group>
))}
</Stack>
</Stack>
<Text fz="xs" style={{ color: 'rgba(255,255,255,0.7)' }}>
© 2026 Ethiopian Maritime Authority
</Text>
</Flex>
</Box>
{/* ---- Form panel ----------------------------------------------- */}
<Center flex={1} p="xl">
<Box w="100%" maw={420}>
<Group hiddenFrom="md" gap="sm" mb="xl">
<BrandMark size={40} />
<Text fw={700} fz="lg">
EMA Portal
</Text>
</Group>
{children}
</Box>
</Center>
</Flex>
);
}

View File

@@ -1,15 +1,22 @@
import { useState } from 'react'; import { useState } from 'react';
import { import {
Paper,
TextInput,
PasswordInput,
Button,
Stack,
Title,
Center,
Text,
Anchor, Anchor,
Button,
Checkbox,
Divider,
Group,
PasswordInput,
Stack,
Text,
TextInput,
Title,
} from '@mantine/core'; } from '@mantine/core';
import {
IconArrowRight,
IconDeviceMobile,
IconLock,
IconMail,
} from '@tabler/icons-react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod'; import { z } from 'zod';
@@ -19,6 +26,7 @@ import { loginSuccess, setUser } from '../store/auth.slice';
import type { LoginPayload, AuthUser } from '../types/auth.types'; import type { LoginPayload, AuthUser } from '../types/auth.types';
import { useApiMutation } from '@ema-platform/api'; import { useApiMutation } from '@ema-platform/api';
import { notify } from '@ema-platform/ui'; import { notify } from '@ema-platform/ui';
import { AuthShell } from '../components/AuthShell';
const schema = z.object({ const schema = z.object({
email: z.string().email({ message: 'Enter a valid email' }), email: z.string().email({ message: 'Enter a valid email' }),
@@ -31,6 +39,7 @@ export function LoginPage() {
const navigate = useNavigate(); const navigate = useNavigate();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [rememberMe, setRememberMe] = useState(true);
const [loginTrigger] = useApiMutation<LoginPayload>(); const [loginTrigger] = useApiMutation<LoginPayload>();
const [meTrigger] = useApiMutation<AuthUser>(); const [meTrigger] = useApiMutation<AuthUser>();
@@ -73,37 +82,83 @@ export function LoginPage() {
}; };
return ( return (
<Center h="100vh"> <AuthShell>
<Paper p="xl" shadow="md" radius="md" w={400}> <Stack gap="lg">
<Stack gap="md"> <div>
<Title order={3}>Sign in to Portal</Title> <Title order={2} fz={30}>
<form onSubmit={handleSubmit(onSubmit)}> Welcome back
<Stack gap="sm"> </Title>
<TextInput <Text c="dimmed" mt={6}>
label="Email" Sign in to access your maritime licensing dashboard.
placeholder="you@example.com"
error={errors.email?.message}
{...register('email')}
/>
<PasswordInput
label="Password"
placeholder="Your password"
error={errors.password?.message}
{...register('password')}
/>
<Button type="submit" loading={isLoading} fullWidth mt="sm">
Sign in
</Button>
</Stack>
</form>
<Text ta="center" size="sm" c="dimmed">
Don't have an account?{' '}
<Anchor component={Link} to="/signup">
Sign up
</Anchor>
</Text> </Text>
</Stack> </div>
</Paper>
</Center> <form onSubmit={handleSubmit(onSubmit)}>
<Stack gap="md">
<TextInput
label="Email or phone"
placeholder="you@example.com"
size="md"
leftSection={<IconMail size={18} />}
error={errors.email?.message}
{...register('email')}
/>
<PasswordInput
label="Password"
placeholder="Your password"
size="md"
leftSection={<IconLock size={18} />}
error={errors.password?.message}
{...register('password')}
/>
<Group justify="space-between">
<Checkbox
label="Remember me"
size="sm"
checked={rememberMe}
onChange={(e) => setRememberMe(e.currentTarget.checked)}
/>
<Anchor
size="sm"
fw={600}
onClick={() => notify.info('Password reset is coming soon.')}
>
Forgot password?
</Anchor>
</Group>
<Button
type="submit"
loading={isLoading}
fullWidth
size="md"
rightSection={<IconArrowRight size={18} />}
>
Sign in
</Button>
</Stack>
</form>
<Divider label="or" labelPosition="center" />
<Button
variant="default"
fullWidth
size="md"
leftSection={<IconDeviceMobile size={18} />}
onClick={() => notify.info('Phone sign-in is coming soon.')}
>
Sign in with phone number
</Button>
<Text ta="center" size="sm" c="dimmed">
Don&apos;t have an account?{' '}
<Anchor component={Link} to="/signup" fw={700}>
Create one
</Anchor>
</Text>
</Stack>
</AuthShell>
); );
} }

View File

@@ -1,18 +1,21 @@
import { import {
Paper, Anchor,
TextInput,
Button, Button,
Group,
Stack, Stack,
Title,
Center,
Text, Text,
TextInput,
ThemeIcon,
Title,
} from '@mantine/core'; } from '@mantine/core';
import { IconArrowRight, IconShieldLock } from '@tabler/icons-react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod'; import { z } from 'zod';
import { useNavigate, useLocation } from 'react-router-dom'; import { useNavigate, useLocation } from 'react-router-dom';
import { useApiMutation } from '@ema-platform/api'; import { useApiMutation } from '@ema-platform/api';
import { notify } from '@ema-platform/ui'; import { notify } from '@ema-platform/ui';
import { AuthShell } from '../components/AuthShell';
const schema = z.object({ const schema = z.object({
verificationCode: z.string().min(1, { message: 'Verification code is required' }), verificationCode: z.string().min(1, { message: 'Verification code is required' }),
@@ -72,38 +75,63 @@ export function OTPVerificationPage() {
}; };
return ( return (
<Center h="100vh"> <AuthShell
<Paper p="xl" shadow="md" radius="md" w={400}> brandTitle="One last step to secure your account."
<Stack gap="md"> brandSubtitle="We use a one-time code to confirm it's really you before granting access to the licensing portal."
<Title order={3}>Verify your email</Title> >
<Text c="dimmed" size="sm"> <Stack gap="lg">
A verification code has been sent to {email || 'your email'}. Enter it <ThemeIcon size={56} radius="md" variant="light" color="emaPrimary">
below to complete your registration. <IconShieldLock size={30} />
</ThemeIcon>
<div>
<Title order={2} fz={30}>
Verify your account
</Title>
<Text c="dimmed" mt={6}>
A verification code has been sent to{' '}
<Text span fw={600} c="dark">
{email || 'your email'}
</Text>
. Enter it below to continue.
</Text> </Text>
<form onSubmit={handleSubmit(onSubmit)}> </div>
<Stack gap="sm">
<TextInput <form onSubmit={handleSubmit(onSubmit)}>
label="Verification Code" <Stack gap="md">
placeholder="Enter the code from your email" <TextInput
error={errors.verificationCode?.message} label="Verification code"
{...register('verificationCode')} placeholder="Enter the 6-digit code"
/> size="md"
<Button type="submit" loading={loading} fullWidth mt="sm"> error={errors.verificationCode?.message}
Verify {...register('verificationCode')}
</Button> />
</Stack> <Button
</form> type="submit"
<Button loading={loading}
variant="subtle" fullWidth
size="md"
rightSection={<IconArrowRight size={18} />}
>
Verify
</Button>
</Stack>
</form>
<Group justify="center" gap={6}>
<Text size="sm" c="dimmed">
Didn&apos;t receive a code?
</Text>
<Anchor
size="sm" size="sm"
loading={resending} fw={600}
onClick={handleResendOtp} onClick={handleResendOtp}
fullWidth style={resending ? { pointerEvents: 'none', opacity: 0.6 } : undefined}
> >
Send OTP again Resend code
</Button> </Anchor>
</Stack> </Group>
</Paper> </Stack>
</Center> </AuthShell>
); );
} }

View File

@@ -1,14 +1,24 @@
import { useState } from 'react';
import { import {
Paper,
TextInput,
PasswordInput,
Button,
Stack,
Title,
Center,
Text,
Anchor, Anchor,
Button,
Checkbox,
Group,
PasswordInput,
SimpleGrid,
Stack,
Text,
TextInput,
Title,
} from '@mantine/core'; } from '@mantine/core';
import {
IconArrowRight,
IconAt,
IconDeviceMobile,
IconLock,
IconMail,
IconUser,
} from '@tabler/icons-react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod'; import { z } from 'zod';
@@ -17,6 +27,7 @@ import { useAppDispatch } from '../../../store/hooks';
import { loginSuccess } from '../store/auth.slice'; import { loginSuccess } from '../store/auth.slice';
import { useApiMutation } from '@ema-platform/api'; import { useApiMutation } from '@ema-platform/api';
import { notify } from '@ema-platform/ui'; import { notify } from '@ema-platform/ui';
import { AuthShell } from '../components/AuthShell';
const schema = z const schema = z
.object({ .object({
@@ -52,6 +63,7 @@ interface SignupPayload {
export function SignupPage() { export function SignupPage() {
const navigate = useNavigate(); const navigate = useNavigate();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [agreed, setAgreed] = useState(false);
const [signupTrigger, { isLoading: loading }] = useApiMutation<{ const [signupTrigger, { isLoading: loading }] = useApiMutation<{
token: string; token: string;
refreshToken: string; refreshToken: string;
@@ -103,67 +115,119 @@ export function SignupPage() {
}; };
return ( return (
<Center h="100vh"> <AuthShell
<Paper p="xl" shadow="md" radius="md" w={400}> brandTitle="Join Ethiopia's maritime community."
<Stack gap="md"> brandSubtitle="Create your account to apply for licenses, manage documents, and track approvals from anywhere."
<Title order={3}>Create an account</Title> >
<form onSubmit={handleSubmit(onSubmit)}> <Stack gap="lg">
<Stack gap="sm"> <div>
<Title order={2} fz={30}>
Create account
</Title>
<Text c="dimmed" mt={6}>
It only takes a minute to get started.
</Text>
</div>
<form onSubmit={handleSubmit(onSubmit)}>
<Stack gap="md">
<SimpleGrid cols={{ base: 1, xs: 2 }} spacing="md">
<TextInput <TextInput
label="Name (English)" label="Name (English)"
placeholder="Your name in English" placeholder="Abebe Bekele"
leftSection={<IconUser size={18} />}
error={errors.nameEn?.message} error={errors.nameEn?.message}
{...register('nameEn')} {...register('nameEn')}
/> />
<TextInput <TextInput
label="Name (Amharic)" label="Name (Amharic)"
placeholder="Your name in Amharic" placeholder="ስም"
leftSection={<IconUser size={18} />}
error={errors.nameAm?.message} error={errors.nameAm?.message}
{...register('nameAm')} {...register('nameAm')}
/> />
</SimpleGrid>
<SimpleGrid cols={{ base: 1, xs: 2 }} spacing="md">
<TextInput <TextInput
label="Email" label="Email address"
placeholder="you@example.com" placeholder="you@example.com"
leftSection={<IconMail size={18} />}
error={errors.email?.message} error={errors.email?.message}
{...register('email')} {...register('email')}
/> />
<TextInput <TextInput
label="Username" label="Username"
placeholder="Choose a username" placeholder="Choose a username"
leftSection={<IconAt size={18} />}
error={errors.username?.message} error={errors.username?.message}
{...register('username')} {...register('username')}
/> />
<TextInput </SimpleGrid>
label="Phone Number"
placeholder="+251 911 234 567" <TextInput
error={errors.phoneNumber?.message} label="Phone number"
{...register('phoneNumber')} placeholder="+251 911 234 567"
/> leftSection={<IconDeviceMobile size={18} />}
error={errors.phoneNumber?.message}
{...register('phoneNumber')}
/>
<SimpleGrid cols={{ base: 1, xs: 2 }} spacing="md">
<PasswordInput <PasswordInput
label="Password" label="Password"
placeholder="Enter a password" placeholder="At least 8 characters"
leftSection={<IconLock size={18} />}
error={errors.password?.message} error={errors.password?.message}
{...register('password')} {...register('password')}
/> />
<PasswordInput <PasswordInput
label="Confirm Password" label="Confirm password"
placeholder="Confirm your password" placeholder="Re-enter password"
leftSection={<IconLock size={18} />}
error={errors.confirmPassword?.message} error={errors.confirmPassword?.message}
{...register('confirmPassword')} {...register('confirmPassword')}
/> />
<Button type="submit" loading={loading} fullWidth mt="sm"> </SimpleGrid>
Sign up
</Button> <Checkbox
</Stack> size="sm"
</form> checked={agreed}
<Text ta="center" size="sm" c="dimmed"> onChange={(e) => setAgreed(e.currentTarget.checked)}
Already have an account?{' '} label={
<Anchor component={Link} to="/login"> <Text size="sm">
Sign in I agree to the{' '}
</Anchor> <Anchor
</Text> size="sm"
</Stack> fw={600}
</Paper> onClick={(e) => e.preventDefault()}
</Center> >
Terms &amp; Privacy Policy
</Anchor>
</Text>
}
/>
<Button
type="submit"
loading={loading}
disabled={!agreed}
fullWidth
size="md"
rightSection={<IconArrowRight size={18} />}
>
Create account
</Button>
</Stack>
</form>
<Text ta="center" size="sm" c="dimmed">
Already have an account?{' '}
<Anchor component={Link} to="/login" fw={700}>
Sign in
</Anchor>
</Text>
</Stack>
</AuthShell>
); );
} }

562
ema-portal.pen Normal file
View File

@@ -0,0 +1,562 @@
{
"version": "2.13",
"children": [
{
"type": "frame",
"id": "YKsGt",
"x": 0,
"y": 0,
"name": "Welcome to Pencil",
"clip": true,
"width": 1000,
"height": 1458,
"layout": "none",
"children": [
{
"type": "text",
"id": "Lmqy1",
"x": 38,
"y": 297,
"name": "Start here",
"fill": "#ff8303ff",
"textGrowth": "fixed-width-height",
"width": 923,
"height": 307,
"content": "Ask agent to \ndesign something",
"lineHeight": 1.399999976158142,
"textAlign": "center",
"fontFamily": "Noto Sans",
"fontSize": 100,
"fontWeight": "500",
"letterSpacing": -4
},
{
"type": "path",
"id": "AmD9T",
"x": 267.8010819142764,
"y": 632,
"rotation": -45,
"geometry": "M7 0l0 14m7-7l-7 7-7-7",
"width": 366,
"height": 366,
"stroke": "#ff8302ff",
"strokeWidth": 50,
"strokeLinejoin": "round",
"strokeLinecap": "round"
}
]
}
],
"themes": {
"Mode": [
"Light",
"Dark"
]
},
"variables": {
"--sidebar": {
"type": "color",
"value": [
{
"value": "#E7E8E5"
},
{
"value": "#18181b",
"theme": {
"Mode": "Dark"
}
}
]
},
"--sidebar-foreground": {
"type": "color",
"value": [
{
"value": "#666666"
},
{
"value": "#fafafa",
"theme": {
"Mode": "Dark"
}
}
]
},
"--sidebar-primary": {
"type": "color",
"value": [
{
"value": "#18181b"
},
{
"value": "#18181b",
"theme": {
"Mode": "Dark"
}
}
]
},
"--sidebar-primary-foreground": {
"type": "color",
"value": [
{
"value": "#fafafa"
},
{
"value": "#fafafa",
"theme": {
"Mode": "Dark"
}
}
]
},
"--sidebar-border": {
"type": "color",
"value": [
{
"value": "#CBCCC9"
},
{
"value": "#ffffff1a",
"theme": {
"Mode": "Dark"
}
}
]
},
"--sidebar-accent": {
"type": "color",
"value": [
{
"value": "#CBCCC9"
},
{
"value": "#2a2a30",
"theme": {
"Mode": "Dark"
}
}
]
},
"--sidebar-accent-foreground": {
"type": "color",
"value": [
{
"value": "#18181b"
},
{
"value": "#fafafa",
"theme": {
"Mode": "Dark"
}
}
]
},
"--sidebar-ring": {
"type": "color",
"value": [
{
"value": "#71717a"
},
{
"value": "#71717a",
"theme": {
"Mode": "Dark"
}
}
]
},
"--background": {
"type": "color",
"value": [
{
"value": "#F2F3F0"
},
{
"value": "#111111",
"theme": {
"Mode": "Dark"
}
}
]
},
"--foreground": {
"type": "color",
"value": [
{
"value": "#111111"
},
{
"value": "#FFFFFF",
"theme": {
"Mode": "Dark"
}
}
]
},
"--card": {
"type": "color",
"value": [
{
"value": "#FFFFFF"
},
{
"value": "#1A1A1A",
"theme": {
"Mode": "Dark"
}
}
]
},
"--card-foreground": {
"type": "color",
"value": [
{
"value": "#111111"
},
{
"value": "#FFFFFF",
"theme": {
"Mode": "Dark"
}
}
]
},
"--popover": {
"type": "color",
"value": [
{
"value": "#FFFFFF"
},
{
"value": "#1A1A1A",
"theme": {
"Mode": "Dark"
}
}
]
},
"--popover-foreground": {
"type": "color",
"value": [
{
"value": "#111111"
},
{
"value": "#FFFFFF",
"theme": {
"Mode": "Dark"
}
}
]
},
"--primary": {
"type": "color",
"value": [
{
"value": "#FF8400"
},
{
"value": "#FF8400",
"theme": {
"Mode": "Dark"
}
}
]
},
"--primary-foreground": {
"type": "color",
"value": [
{
"value": "#111111"
},
{
"value": "#111111",
"theme": {
"Mode": "Dark"
}
}
]
},
"--secondary": {
"type": "color",
"value": [
{
"value": "#E7E8E5"
},
{
"value": "#2E2E2E",
"theme": {
"Mode": "Dark"
}
}
]
},
"--secondary-foreground": {
"type": "color",
"value": [
{
"value": "#111111"
},
{
"value": "#FFFFFF",
"theme": {
"Mode": "Dark"
}
}
]
},
"--muted": {
"type": "color",
"value": [
{
"value": "#F2F3F0"
},
{
"value": "#2E2E2E",
"theme": {
"Mode": "Dark"
}
}
]
},
"--muted-foreground": {
"type": "color",
"value": [
{
"value": "#666666"
},
{
"value": "#B8B9B6",
"theme": {
"Mode": "Dark"
}
}
]
},
"--accent": {
"type": "color",
"value": [
{
"value": "#F2F3F0"
},
{
"value": "#111111",
"theme": {
"Mode": "Dark"
}
}
]
},
"--accent-foreground": {
"type": "color",
"value": [
{
"value": "#111111"
},
{
"value": "#F2F3F0",
"theme": {
"Mode": "Dark"
}
}
]
},
"--destructive": {
"type": "color",
"value": [
{
"value": "#D93C15"
},
{
"value": "#FF5C33",
"theme": {
"Mode": "Dark"
}
}
]
},
"--border": {
"type": "color",
"value": [
{
"value": "#CBCCC9"
},
{
"value": "#2E2E2E",
"theme": {
"Mode": "Dark"
}
}
]
},
"--input": {
"type": "color",
"value": [
{
"value": "#CBCCC9"
},
{
"value": "#2E2E2E",
"theme": {
"Mode": "Dark"
}
}
]
},
"--ring": {
"type": "color",
"value": [
{
"value": "#666666"
},
{
"value": "#666666",
"theme": {
"Mode": "Dark"
}
}
]
},
"--white": {
"type": "color",
"value": "#FFFFFF"
},
"--black": {
"type": "color",
"value": "#000000"
},
"--font-primary": {
"type": "string",
"value": "JetBrains Mono"
},
"--font-secondary": {
"type": "string",
"value": "Geist"
},
"--radius-none": {
"type": "number",
"value": 0
},
"--radius-pill": {
"type": "number",
"value": 999
},
"--color-success": {
"type": "color",
"value": [
{
"value": "#DFE6E1"
},
{
"value": "#222924",
"theme": {
"Mode": "Dark"
}
}
]
},
"--color-success-foreground": {
"type": "color",
"value": [
{
"value": "#004D1A"
},
{
"value": "#B6FFCE",
"theme": {
"Mode": "Dark"
}
}
]
},
"--color-warning": {
"type": "color",
"value": [
{
"value": "#E9E3D8"
},
{
"value": "#291C0F",
"theme": {
"Mode": "Dark"
}
}
]
},
"--color-warning-foreground": {
"type": "color",
"value": [
{
"value": "#804200"
},
{
"value": "#FF8400",
"theme": {
"Mode": "Dark"
}
}
]
},
"--color-error": {
"type": "color",
"value": [
{
"value": "#E5DCDA"
},
{
"value": "#24100B",
"theme": {
"Mode": "Dark"
}
}
]
},
"--color-error-foreground": {
"type": "color",
"value": [
{
"value": "#8C1C00"
},
{
"value": "#FF5C33",
"theme": {
"Mode": "Dark"
}
}
]
},
"--color-info": {
"type": "color",
"value": [
{
"value": "#DFDFE6"
},
{
"value": "#222229",
"theme": {
"Mode": "Dark"
}
}
]
},
"--color-info-foreground": {
"type": "color",
"value": [
{
"value": "#000066"
},
{
"value": "#B2B2FF",
"theme": {
"Mode": "Dark"
}
}
]
},
"--radius-m": {
"type": "number",
"value": 16
}
}
}