mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-05 15:44:21 +00:00
Refactor theme styles for hover, accordion, and workspace components
This commit is contained in:
@@ -18,6 +18,7 @@ import { useAuth } from '../../contexts/AuthContext';
|
||||
import AccountSettings from '../settings/account/AccountSettings';
|
||||
import AdminDashboard from '../settings/admin/AdminDashboard';
|
||||
import { UserRole } from '@/types/models';
|
||||
import { getHoverStyle } from '@/utils/themeStyles';
|
||||
|
||||
const UserMenu: React.FC = () => {
|
||||
const [accountSettingsOpened, setAccountSettingsOpened] =
|
||||
@@ -75,15 +76,7 @@ const UserMenu: React.FC = () => {
|
||||
}}
|
||||
px="sm"
|
||||
py="xs"
|
||||
style={(theme: any) => ({
|
||||
borderRadius: theme.radius.sm,
|
||||
'&:hover': {
|
||||
backgroundColor:
|
||||
theme.colorScheme === 'dark'
|
||||
? theme.colors.dark[5]
|
||||
: theme.colors.gray[0],
|
||||
},
|
||||
})}
|
||||
style={(theme) => getHoverStyle(theme)}
|
||||
>
|
||||
<Group>
|
||||
<IconSettings size={16} />
|
||||
@@ -99,15 +92,7 @@ const UserMenu: React.FC = () => {
|
||||
}}
|
||||
px="sm"
|
||||
py="xs"
|
||||
style={(theme: any) => ({
|
||||
borderRadius: theme.radius.sm,
|
||||
'&:hover': {
|
||||
backgroundColor:
|
||||
theme.colorScheme === 'dark'
|
||||
? theme.colors.dark[5]
|
||||
: theme.colors.gray[0],
|
||||
},
|
||||
})}
|
||||
style={(theme) => getHoverStyle(theme)}
|
||||
>
|
||||
<Group>
|
||||
<IconUsers size={16} />
|
||||
@@ -121,15 +106,7 @@ const UserMenu: React.FC = () => {
|
||||
px="sm"
|
||||
py="xs"
|
||||
color="red"
|
||||
style={(theme: any) => ({
|
||||
borderRadius: theme.radius.sm,
|
||||
'&:hover': {
|
||||
backgroundColor:
|
||||
theme.colorScheme === 'dark'
|
||||
? theme.colors.dark[5]
|
||||
: theme.colors.gray[0],
|
||||
},
|
||||
})}
|
||||
style={(theme) => getHoverStyle(theme)}
|
||||
>
|
||||
<Group>
|
||||
<IconLogout size={16} color="red" />
|
||||
|
||||
@@ -20,6 +20,10 @@ import { useModalContext } from '../../contexts/ModalContext';
|
||||
import { listWorkspaces } from '../../api/workspace';
|
||||
import CreateWorkspaceModal from '../modals/workspace/CreateWorkspaceModal';
|
||||
import type { Workspace } from '@/types/models';
|
||||
import {
|
||||
getConditionalColor,
|
||||
getWorkspacePaperStyle,
|
||||
} from '@/utils/themeStyles';
|
||||
|
||||
const WorkspaceSwitcher: React.FC = () => {
|
||||
const { currentWorkspace, switchWorkspace } = useWorkspace();
|
||||
@@ -111,18 +115,9 @@ const WorkspaceSwitcher: React.FC = () => {
|
||||
key={workspace.name}
|
||||
p="xs"
|
||||
withBorder
|
||||
style={(theme: any) => ({
|
||||
backgroundColor: isSelected
|
||||
? theme.colors.blue[
|
||||
theme.colorScheme === 'dark' ? 8 : 1
|
||||
]
|
||||
: undefined,
|
||||
borderColor: isSelected
|
||||
? theme.colors.blue[
|
||||
theme.colorScheme === 'dark' ? 7 : 5
|
||||
]
|
||||
: undefined,
|
||||
})}
|
||||
style={(theme) =>
|
||||
getWorkspacePaperStyle(theme, isSelected)
|
||||
}
|
||||
>
|
||||
<Group justify="space-between" wrap="nowrap">
|
||||
<UnstyledButton
|
||||
@@ -137,27 +132,13 @@ const WorkspaceSwitcher: React.FC = () => {
|
||||
size="sm"
|
||||
fw={500}
|
||||
truncate
|
||||
c={
|
||||
isSelected
|
||||
? (theme as any).colors.blue[
|
||||
(theme as any).colorScheme === 'dark'
|
||||
? 0
|
||||
: 9
|
||||
]
|
||||
: undefined
|
||||
}
|
||||
c={isSelected ? 'blue' : 'inherit'}
|
||||
>
|
||||
{workspace.name}
|
||||
</Text>
|
||||
<Text
|
||||
size="xs"
|
||||
c={
|
||||
isSelected
|
||||
? (theme as any).colorScheme === 'dark'
|
||||
? theme.colors.blue[2]
|
||||
: theme.colors.blue[7]
|
||||
: 'dimmed'
|
||||
}
|
||||
c={getConditionalColor(theme, isSelected)}
|
||||
>
|
||||
{new Date(
|
||||
workspace.createdAt
|
||||
@@ -170,11 +151,7 @@ const WorkspaceSwitcher: React.FC = () => {
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
size="lg"
|
||||
color={
|
||||
(theme as any).colorScheme === 'dark'
|
||||
? 'blue.2'
|
||||
: 'blue.7'
|
||||
}
|
||||
color={getConditionalColor(theme, true)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSettingsModalVisible(true);
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
type SettingsAction,
|
||||
SettingsActionType,
|
||||
} from '@/types/models';
|
||||
import { getAccordionStyles } from '@/utils/themeStyles';
|
||||
|
||||
interface AccountSettingsProps {
|
||||
opened: boolean;
|
||||
@@ -202,25 +203,7 @@ const AccountSettings: React.FC<AccountSettingsProps> = ({
|
||||
<Accordion
|
||||
defaultValue={['profile', 'security', 'danger']}
|
||||
multiple
|
||||
styles={(theme: any) => ({
|
||||
control: {
|
||||
paddingTop: theme.spacing.md,
|
||||
paddingBottom: theme.spacing.md,
|
||||
},
|
||||
item: {
|
||||
borderBottom: `1px solid ${
|
||||
theme.colorScheme === 'dark'
|
||||
? theme.colors.dark[4]
|
||||
: theme.colors.gray[3]
|
||||
}`,
|
||||
'&[data-active]': {
|
||||
backgroundColor:
|
||||
theme.colorScheme === 'dark'
|
||||
? theme.colors.dark[7]
|
||||
: theme.colors.gray[0],
|
||||
},
|
||||
},
|
||||
})}
|
||||
styles={(theme) => getAccordionStyles(theme)}
|
||||
>
|
||||
<Accordion.Item value="profile">
|
||||
<AccordionControl>Profile</AccordionControl>
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
type SettingsAction,
|
||||
SettingsActionType,
|
||||
} from '@/types/models';
|
||||
import { getAccordionStyles } from '@/utils/themeStyles';
|
||||
// State and reducer for workspace settings
|
||||
interface WorkspaceSettingsState {
|
||||
localSettings: Partial<Workspace>;
|
||||
@@ -157,24 +158,8 @@ const WorkspaceSettings: React.FC = () => {
|
||||
<Accordion
|
||||
defaultValue={['general', 'appearance', 'editor', 'git', 'danger']}
|
||||
multiple
|
||||
styles={(theme: any) => ({
|
||||
control: {
|
||||
paddingTop: theme.spacing.md,
|
||||
paddingBottom: theme.spacing.md,
|
||||
},
|
||||
item: {
|
||||
borderBottom: `1px solid ${
|
||||
theme.colorScheme === 'dark'
|
||||
? theme.colors.dark[4]
|
||||
: theme.colors.gray[3]
|
||||
}`,
|
||||
'&[data-active]': {
|
||||
backgroundColor:
|
||||
theme.colorScheme === 'dark'
|
||||
? theme.colors.dark[7]
|
||||
: theme.colors.gray[0],
|
||||
},
|
||||
},
|
||||
styles={(theme) => ({
|
||||
...getAccordionStyles(theme),
|
||||
chevron: {
|
||||
'&[data-rotate]': {
|
||||
transform: 'rotate(180deg)',
|
||||
|
||||
80
app/src/utils/themeStyles.ts
Normal file
80
app/src/utils/themeStyles.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import type { MantineTheme } from '@mantine/core';
|
||||
|
||||
// For type safety - this property exists on the MantineTheme but may not be in types
|
||||
interface ThemeWithColorScheme extends MantineTheme {
|
||||
colorScheme?: 'dark' | 'light';
|
||||
}
|
||||
|
||||
// Type-safe hover style function for unstyledButton and similar components
|
||||
export const getHoverStyle = (theme: MantineTheme) => ({
|
||||
borderRadius: theme.radius.sm,
|
||||
'&:hover': {
|
||||
backgroundColor:
|
||||
(theme as ThemeWithColorScheme).colorScheme === 'dark'
|
||||
? theme.colors.dark[5]
|
||||
: theme.colors.gray[0],
|
||||
},
|
||||
});
|
||||
|
||||
// Type-safe color function for text or components that need conditional colors
|
||||
export const getConditionalColor = (
|
||||
theme: MantineTheme,
|
||||
isSelected = false
|
||||
) => {
|
||||
if (isSelected) {
|
||||
return (theme as ThemeWithColorScheme).colorScheme === 'dark'
|
||||
? theme.colors.blue[2]
|
||||
: theme.colors.blue[7];
|
||||
}
|
||||
return 'dimmed';
|
||||
};
|
||||
|
||||
// Helper for accordion styling
|
||||
export const getAccordionStyles = (theme: MantineTheme) => ({
|
||||
control: {
|
||||
paddingTop: theme.spacing.md,
|
||||
paddingBottom: theme.spacing.md,
|
||||
},
|
||||
item: {
|
||||
borderBottom: `1px solid ${
|
||||
(theme as ThemeWithColorScheme).colorScheme === 'dark'
|
||||
? theme.colors.dark[4]
|
||||
: theme.colors.gray[3]
|
||||
}`,
|
||||
'&[data-active]': {
|
||||
backgroundColor:
|
||||
(theme as ThemeWithColorScheme).colorScheme === 'dark'
|
||||
? theme.colors.dark[7]
|
||||
: theme.colors.gray[0],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Helper for workspace paper styling
|
||||
export const getWorkspacePaperStyle = (
|
||||
theme: MantineTheme,
|
||||
isSelected: boolean
|
||||
) => ({
|
||||
backgroundColor: isSelected
|
||||
? theme.colors.blue[
|
||||
(theme as ThemeWithColorScheme).colorScheme === 'dark' ? 8 : 1
|
||||
]
|
||||
: undefined,
|
||||
borderColor: isSelected
|
||||
? theme.colors.blue[
|
||||
(theme as ThemeWithColorScheme).colorScheme === 'dark' ? 7 : 5
|
||||
]
|
||||
: undefined,
|
||||
});
|
||||
|
||||
// Helper for text color based on theme and selection
|
||||
export const getTextColor = (
|
||||
theme: MantineTheme,
|
||||
isSelected: boolean
|
||||
): string | null => {
|
||||
if (!isSelected) return null;
|
||||
|
||||
return (theme as ThemeWithColorScheme).colorScheme === 'dark'
|
||||
? theme.colors.blue[0]
|
||||
: theme.colors.blue[9];
|
||||
};
|
||||
Reference in New Issue
Block a user