🎨(frontend) replace hardcoded hex values with design tokens

Clean up fast-shipped features that broke design system by using proper
primary/semantic tokens instead of hardcoded colors. Enables better theme
customization for all implementations.
This commit is contained in:
lebaudantoine
2025-06-06 16:40:26 +02:00
committed by aleb_the_flash
parent 260eab23be
commit 1b9af5bf6d
19 changed files with 77 additions and 48 deletions

View File

@@ -315,6 +315,10 @@ const config: Config = {
'subtle-text': { value: '{colors.red.700}' }, 'subtle-text': { value: '{colors.red.700}' },
...pandaPreset.theme.tokens.colors.red, ...pandaPreset.theme.tokens.colors.red,
}, },
alert: {
DEFAULT: { value: '{colors.blue.700}' },
notification: { value: '{colors.red.600}' },
},
success: { success: {
DEFAULT: { value: '{colors.green.700}' }, DEFAULT: { value: '{colors.green.700}' },
hover: { value: '{colors.green.800}' }, hover: { value: '{colors.green.800}' },

View File

@@ -14,8 +14,8 @@ export const FeedbackBanner = () => {
<div <div
className={css({ className={css({
width: '100%', width: '100%',
backgroundColor: '#E8EDFF', backgroundColor: 'primary.50',
color: '#0063CB', color: 'primary.600',
display: { base: 'none', sm: 'flex' }, display: { base: 'none', sm: 'flex' },
justifyContent: 'center', justifyContent: 'center',
padding: '0.5rem 0', padding: '0.5rem 0',

View File

@@ -53,10 +53,10 @@ const Dot = styled('div', {
variants: { variants: {
selected: { selected: {
true: { true: {
backgroundColor: '#000091', backgroundColor: 'primary.800',
}, },
false: { false: {
backgroundColor: '#CACAFB', backgroundColor: 'primary.300',
}, },
}, },
}, },

View File

@@ -4,6 +4,7 @@ import { getRouteUrl } from '@/navigation/getRouteUrl'
import { Button, Dialog, type DialogProps, P, Text } from '@/primitives' import { Button, Dialog, type DialogProps, P, Text } from '@/primitives'
import { HStack } from '@/styled-system/jsx' import { HStack } from '@/styled-system/jsx'
import { RiCheckLine, RiFileCopyLine, RiSpam2Fill } from '@remixicon/react' import { RiCheckLine, RiFileCopyLine, RiSpam2Fill } from '@remixicon/react'
import { css } from '@/styled-system/css'
// fixme - duplication with the InviteDialog // fixme - duplication with the InviteDialog
export const LaterMeetingDialog = ({ export const LaterMeetingDialog = ({
@@ -76,14 +77,19 @@ export const LaterMeetingDialog = ({
</Button> </Button>
<HStack> <HStack>
<div <div
style={{ className={css({
backgroundColor: '#d9e5ff', backgroundColor: 'primary.200',
borderRadius: '50%', borderRadius: '50%',
padding: '4px', padding: '4px',
marginTop: '1rem', marginTop: '1rem',
}} })}
> >
<RiSpam2Fill size={22} style={{ fill: '#4c84fc' }} /> <RiSpam2Fill
size={22}
className={css({
fill: 'primary.500',
})}
/>
</div> </div>
<Text variant="sm" style={{ marginTop: '1rem' }}> <Text variant="sm" style={{ marginTop: '1rem' }}>
{t('laterMeetingDialog.permissions')} {t('laterMeetingDialog.permissions')}

View File

@@ -111,7 +111,7 @@ const RightColumn = ({ children }: { children?: ReactNode }) => {
const Separator = styled('div', { const Separator = styled('div', {
base: { base: {
borderBottom: '1px solid', borderBottom: '1px solid',
borderColor: '#747775', borderColor: 'greyscale.500',
marginTop: '2.5rem', marginTop: '2.5rem',
maxWidth: '30rem', maxWidth: '30rem',
width: '100%', width: '100%',

View File

@@ -12,7 +12,7 @@ export const StyledToastContainer = styled('div', {
margin: 0.5, margin: 0.5,
boxShadow: boxShadow:
'rgba(0, 0, 0, 0.5) 0px 4px 8px 0px, rgba(0, 0, 0, 0.3) 0px 6px 20px 4px', 'rgba(0, 0, 0, 0.5) 0px 4px 8px 0px, rgba(0, 0, 0, 0.3) 0px 6px 20px 4px',
backgroundColor: '#494c4f', backgroundColor: 'greyscale.700',
color: 'white', color: 'white',
borderRadius: '8px', borderRadius: '8px',
'&[data-entering]': { animation: 'fade 200ms' }, '&[data-entering]': { animation: 'fade 200ms' },

View File

@@ -5,6 +5,7 @@ import { StyledToastContainer, ToastProps } from './Toast'
import { HStack } from '@/styled-system/jsx' import { HStack } from '@/styled-system/jsx'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Button } from '@/primitives' import { Button } from '@/primitives'
import { css } from '@/styled-system/css'
export function ToastLowerHand({ state, ...props }: ToastProps) { export function ToastLowerHand({ state, ...props }: ToastProps) {
const { t } = useTranslation('notifications', { keyPrefix: 'lowerHand' }) const { t } = useTranslation('notifications', { keyPrefix: 'lowerHand' })
@@ -31,10 +32,10 @@ export function ToastLowerHand({ state, ...props }: ToastProps) {
<Button <Button
size="sm" size="sm"
variant="text" variant="text"
style={{ className={css({
color: '#60a5fa', color: 'primary.300',
marginLeft: '0.5rem', marginLeft: '0.5rem',
}} })}
onPress={() => handleDismiss()} onPress={() => handleDismiss()}
> >
{t('dismiss')} {t('dismiss')}

View File

@@ -7,6 +7,7 @@ import { Button, Div } from '@/primitives'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { RiCloseLine, RiHand } from '@remixicon/react' import { RiCloseLine, RiHand } from '@remixicon/react'
import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel' import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel'
import { css } from '@/styled-system/css'
export function ToastRaised({ state, ...props }: ToastProps) { export function ToastRaised({ state, ...props }: ToastProps) {
const { t } = useTranslation('notifications') const { t } = useTranslation('notifications')
@@ -46,9 +47,9 @@ export function ToastRaised({ state, ...props }: ToastProps) {
<Button <Button
size="sm" size="sm"
variant="text" variant="text"
style={{ className={css({
color: '#60a5fa', color: 'primary.300',
}} })}
onPress={(e) => { onPress={(e) => {
toggleParticipants() toggleParticipants()
closeButtonProps.onPress?.(e) closeButtonProps.onPress?.(e)

View File

@@ -124,9 +124,9 @@ export const WaitingParticipantNotification = () => {
<Button <Button
size="sm" size="sm"
variant="text" variant="text"
style={{ className={css({
color: '#60a5fa', color: 'primary.300',
}} })}
onPress={async () => { onPress={async () => {
await handleParticipantEntry(waitingParticipants[0], true) await handleParticipantEntry(waitingParticipants[0], true)
setShowQuickActionsMessage(false) setShowQuickActionsMessage(false)
@@ -137,9 +137,9 @@ export const WaitingParticipantNotification = () => {
<Button <Button
size="sm" size="sm"
variant="text" variant="text"
style={{ className={css({
color: '#60a5fa', color: 'primary.300',
}} })}
onPress={() => { onPress={() => {
toggleParticipants() toggleParticipants()
setShowQuickActionsMessage(false) setShowQuickActionsMessage(false)
@@ -207,9 +207,9 @@ export const WaitingParticipantNotification = () => {
<Button <Button
size="sm" size="sm"
variant="text" variant="text"
style={{ className={css({
color: '#60a5fa', color: 'primary.300',
}} })}
onPress={() => { onPress={() => {
toggleParticipants() toggleParticipants()
}} }}

View File

@@ -19,8 +19,8 @@ const StyledContainer = styled('div', {
width: '58px', width: '58px',
borderLeftRadius: 8, borderLeftRadius: 8,
borderRightRadius: 0, borderRightRadius: 0,
backgroundColor: '#dbeafe', backgroundColor: 'primary.200',
border: '1px solid #3b82f6', border: '1px solid primary.500',
gap: '3px', gap: '3px',
}, },
}, },

View File

@@ -11,6 +11,7 @@ import {
RiSpam2Fill, RiSpam2Fill,
} from '@remixicon/react' } from '@remixicon/react'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { css } from '@/styled-system/css'
// fixme - extract in a proper primitive this dialog without overlay // fixme - extract in a proper primitive this dialog without overlay
const StyledRACDialog = styled(Dialog, { const StyledRACDialog = styled(Dialog, {
@@ -100,14 +101,19 @@ export const InviteDialog = ({
</Button> </Button>
<HStack> <HStack>
<div <div
style={{ className={css({
backgroundColor: '#d9e5ff', backgroundColor: 'primary.200',
borderRadius: '50%', borderRadius: '50%',
padding: '4px', padding: '4px',
marginTop: '1rem', marginTop: '1rem',
}} })}
> >
<RiSpam2Fill size={22} style={{ fill: '#4c84fc' }} /> <RiSpam2Fill
size={22}
className={css({
fill: 'primary.500',
})}
/>
</div> </div>
<Text variant="sm" style={{ marginTop: '1rem' }}> <Text variant="sm" style={{ marginTop: '1rem' }}>
{t('shareDialog.permissions')} {t('shareDialog.permissions')}

View File

@@ -52,7 +52,7 @@ export const Admin = () => {
border: 'none', border: 'none',
height: '1px', height: '1px',
width: '100%', width: '100%',
background: '#dadce0', background: 'greyscale.250',
})} })}
/> />
<H <H

View File

@@ -1,8 +1,8 @@
import { useTrackMutedIndicator } from '@livekit/components-react' import { useTrackMutedIndicator } from '@livekit/components-react'
import { Participant, Track } from 'livekit-client' import { Participant, Track } from 'livekit-client'
import Source = Track.Source import Source = Track.Source
import { Div } from '@/primitives'
import { RiMicOffFill } from '@remixicon/react' import { RiMicOffFill } from '@remixicon/react'
import { css } from '@/styled-system/css'
export const MutedMicIndicator = ({ export const MutedMicIndicator = ({
participant, participant,
@@ -19,8 +19,14 @@ export const MutedMicIndicator = ({
} }
return ( return (
<Div padding={0.25} backgroundColor="#E1000F" borderRadius="4px"> <div
className={css({
backgroundColor: 'red.600',
borderRadius: '4px',
padding: 0.25,
})}
>
<RiMicOffFill size={16} color="white" /> <RiMicOffFill size={16} color="white" />
</Div> </div>
) )
} }

View File

@@ -4,6 +4,7 @@ import { RiSendPlane2Fill } from '@remixicon/react'
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { RefObject } from 'react' import { RefObject } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { css } from '@/styled-system/css'
const MAX_ROWS = 6 const MAX_ROWS = 6
@@ -70,12 +71,12 @@ export const ChatInput = ({
return ( return (
<HStack <HStack
style={{ className={css({
margin: '0.75rem 0 1.5rem', margin: '0.75rem 0 1.5rem',
padding: '0.5rem', padding: '0.5rem',
backgroundColor: '#f3f4f6', backgroundColor: 'gray.100',
borderRadius: 4, borderRadius: 4,
}} })}
> >
<TextArea <TextArea
ref={inputRef} ref={inputRef}

View File

@@ -48,10 +48,11 @@ export const ChatToggle = ({
right: '-.25rem', right: '-.25rem',
width: '1rem', width: '1rem',
height: '1rem', height: '1rem',
backgroundColor: '#E1000F', backgroundColor: 'alert.notification',
borderRadius: '50%', borderRadius: '50%',
zIndex: 1, zIndex: 1,
border: '2px solid #d1d5db', border: '2px solid',
borderColor: 'greyscale.250',
})} })}
/> />
)} )}

View File

@@ -17,14 +17,15 @@ const ToggleHeader = styled(ToggleButton, {
transition: 'background 200ms', transition: 'background 200ms',
borderTopRadius: '7px', borderTopRadius: '7px',
'&[data-hovered]': { '&[data-hovered]': {
backgroundColor: '#f5f5f5', backgroundColor: 'greyscale.50',
}, },
}, },
}) })
const Container = styled('div', { const Container = styled('div', {
base: { base: {
border: '1px solid #dadce0', border: '1px solid',
borderColor: 'greyscale.250',
borderRadius: '8px', borderRadius: '8px',
margin: '0 .625rem', margin: '0 .625rem',
}, },
@@ -32,7 +33,8 @@ const Container = styled('div', {
const ListContainer = styled(VStack, { const ListContainer = styled(VStack, {
base: { base: {
borderTop: '1px solid #dadce0', borderTop: '1px solid',
borderTopColor: 'greyscale.250',
alignItems: 'start', alignItems: 'start',
overflowY: 'scroll', overflowY: 'scroll',
overflowX: 'hidden', overflowX: 'hidden',

View File

@@ -51,7 +51,7 @@ export const ParticipantsList = () => {
className={css({ className={css({
fontSize: '0.875rem', fontSize: '0.875rem',
fontWeight: 'bold', fontWeight: 'bold',
color: '#5f6368', color: 'greyscale.600',
padding: '0 1.5rem', padding: '0 1.5rem',
marginBottom: '0.83em', marginBottom: '0.83em',
})} })}

View File

@@ -230,7 +230,7 @@ export const EffectsConfiguration = ({
layout === 'horizontal' layout === 'horizontal'
? { ? {
md: { md: {
borderLeft: '1px solid #dadce0', borderLeft: '1px solid greyscale.250',
paddingLeft: '1.5rem', paddingLeft: '1.5rem',
width: '420px', width: '420px',
flexShrink: 0, flexShrink: 0,

View File

@@ -14,6 +14,7 @@ import { ChatInput } from '../components/chat/Input'
import { ChatEntry } from '../components/chat/Entry' import { ChatEntry } from '../components/chat/Entry'
import { useSidePanel } from '../hooks/useSidePanel' import { useSidePanel } from '../hooks/useSidePanel'
import { LocalParticipant, RemoteParticipant, RoomEvent } from 'livekit-client' import { LocalParticipant, RemoteParticipant, RoomEvent } from 'livekit-client'
import { css } from '@/styled-system/css'
export interface ChatProps export interface ChatProps
extends React.HTMLAttributes<HTMLDivElement>, extends React.HTMLAttributes<HTMLDivElement>,
@@ -122,12 +123,12 @@ export function Chat({ ...props }: ChatProps) {
> >
<Text <Text
variant="sm" variant="sm"
style={{ className={css({
padding: '0.75rem', padding: '0.75rem',
backgroundColor: '#f3f4f6', backgroundColor: 'greyscale.50',
borderRadius: 4, borderRadius: 4,
marginBottom: '0.75rem', marginBottom: '0.75rem',
}} })}
> >
{t('disclaimer')} {t('disclaimer')}
</Text> </Text>