mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-12 08:25:47 +01:00
Merge branch 'dev' into feature/dashdot-consistency-changes
This commit is contained in:
@@ -33,9 +33,10 @@ export const AppTile = ({ className, app }: AppTileProps) => {
|
||||
justify="space-around"
|
||||
align="center"
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
className="dashboard-tile-app"
|
||||
>
|
||||
<Box hidden={false}>
|
||||
<Title order={5} size="md" ta="center" lineClamp={1} className={classes.appName}>
|
||||
<Title order={5} size="md" ta="center" lineClamp={1} className={cx(classes.appName, 'dashboard-tile-app-title')}>
|
||||
{app.name}
|
||||
</Title>
|
||||
</Box>
|
||||
|
||||
@@ -18,7 +18,7 @@ export const HomarrCardWrapper = ({ ...props }: HomarrCardWrapperProps) => {
|
||||
return (
|
||||
<Card
|
||||
{...restProps}
|
||||
className={cx(restProps.className, cardClass)}
|
||||
className={cx(restProps.className, cardClass, 'dashboard-gs-generic-item')}
|
||||
withBorder
|
||||
style={{ cursor: isEditMode ? 'move' : 'default' }}
|
||||
radius="lg"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import create from 'zustand';
|
||||
import { create } from 'zustand';
|
||||
|
||||
interface EditModeState {
|
||||
enabled: boolean;
|
||||
|
||||
@@ -16,7 +16,7 @@ export const DashboardCategory = ({ category }: DashboardCategoryProps) => {
|
||||
const { refs, apps, widgets } = useGridstack('category', category.id);
|
||||
const isEditMode = useEditModeStore((x) => x.enabled);
|
||||
const { config } = useConfigContext();
|
||||
const { classes: cardClasses } = useCardStyles(true);
|
||||
const { classes: cardClasses, cx } = useCardStyles(true);
|
||||
|
||||
const categoryList = config?.categories.map((x) => x.name) ?? [];
|
||||
const [toggledCategories, setToggledCategories] = useLocalStorage({
|
||||
@@ -28,7 +28,7 @@ export const DashboardCategory = ({ category }: DashboardCategoryProps) => {
|
||||
return (
|
||||
<Accordion
|
||||
classNames={{
|
||||
item: cardClasses.card,
|
||||
item: cx(cardClasses.card, 'dashboard-gs-category'),
|
||||
}}
|
||||
mx={10}
|
||||
chevronPosition="left"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useMantineTheme } from '@mantine/core';
|
||||
import create from 'zustand';
|
||||
import { create } from 'zustand';
|
||||
import { useConfigContext } from '../../../../config/provider';
|
||||
import { GridstackBreakpoints } from '../../../../constants/gridstack-breakpoints';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Accordion, Grid, Group, Stack, Text } from '@mantine/core';
|
||||
import { IconBrush, IconChartCandle, IconDragDrop, IconLayout } from '@tabler/icons';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { Accordion, Checkbox, Grid, Group, Stack, Switch, Text } from '@mantine/core';
|
||||
import { IconBrush, IconChartCandle, IconCode, IconDragDrop, IconLayout } from '@tabler/icons';
|
||||
import { i18n, useTranslation } from 'next-i18next';
|
||||
import { ReactNode } from 'react';
|
||||
import { GridstackConfiguration } from './Layout/GridstackConfiguration';
|
||||
import { LayoutSelector } from './Layout/LayoutSelector';
|
||||
@@ -55,7 +55,7 @@ const getItems = () => {
|
||||
'settings/customization/general',
|
||||
'settings/customization/color-selector',
|
||||
]);
|
||||
return [
|
||||
const items = [
|
||||
{
|
||||
id: 'layout',
|
||||
image: <IconLayout />,
|
||||
@@ -114,4 +114,26 @@ const getItems = () => {
|
||||
),
|
||||
},
|
||||
];
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
items.push({
|
||||
id: 'dev',
|
||||
image: <IconCode />,
|
||||
label: 'Developer options',
|
||||
description: 'Options to help when developing',
|
||||
content: (
|
||||
<Stack>
|
||||
<Checkbox
|
||||
label="Use debug language"
|
||||
defaultChecked={i18n?.language === 'cimode'}
|
||||
description="This will show the translation keys instead of the actual translations"
|
||||
onChange={(e) =>
|
||||
// Change to CI mode language
|
||||
i18n?.changeLanguage(e.target.checked ? 'cimode' : 'en')
|
||||
}
|
||||
/>
|
||||
</Stack>
|
||||
),
|
||||
});
|
||||
}
|
||||
return items;
|
||||
};
|
||||
|
||||
@@ -1,24 +1,13 @@
|
||||
import {
|
||||
Box,
|
||||
createStyles,
|
||||
Group,
|
||||
Loader,
|
||||
ScrollArea,
|
||||
Stack,
|
||||
Text,
|
||||
useMantineTheme,
|
||||
} from '@mantine/core';
|
||||
import { Box, createStyles, Group, Loader, Stack, Text, useMantineTheme } from '@mantine/core';
|
||||
import { useDebouncedValue } from '@mantine/hooks';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { ChangeEvent, useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import Editor from 'react-simple-code-editor';
|
||||
import { highlight, languages } from 'prismjs';
|
||||
import { useConfigContext } from '../../../../config/provider';
|
||||
import { useConfigStore } from '../../../../config/store';
|
||||
|
||||
const CodeEditor = dynamic(
|
||||
() => import('@uiw/react-textarea-code-editor').then((mod) => mod.default),
|
||||
{ ssr: false }
|
||||
);
|
||||
import 'prismjs/components/prism-css';
|
||||
import 'prismjs/themes/prism.css';
|
||||
|
||||
export const CustomCssChanger = () => {
|
||||
const { t } = useTranslation('settings/customization/page-appearance');
|
||||
@@ -53,22 +42,20 @@ export const CustomCssChanger = () => {
|
||||
<Stack spacing={4} mt="xl">
|
||||
<Text>{t('customCSS.label')}</Text>
|
||||
<Text color="dimmed" size="xs">
|
||||
{t('customCSS.description')}
|
||||
{t('customCSS.description')}
|
||||
</Text>
|
||||
<div className={classes.codeEditorRoot}>
|
||||
<ScrollArea style={{ height: codeEditorHeight }}>
|
||||
<CodeEditor
|
||||
className={classes.codeEditor}
|
||||
placeholder={t('customCSS.placeholder')}
|
||||
value={nonDebouncedCustomCSS}
|
||||
onChange={(event: ChangeEvent<HTMLTextAreaElement>) =>
|
||||
setNonDebouncedCustomCSS(event.target.value.trim())
|
||||
}
|
||||
language="css"
|
||||
data-color-mode={colorScheme}
|
||||
minHeight={codeEditorHeight}
|
||||
/>
|
||||
</ScrollArea>
|
||||
<Editor
|
||||
value={nonDebouncedCustomCSS}
|
||||
onValueChange={(code) => setNonDebouncedCustomCSS(code)}
|
||||
highlight={(code) => highlight(code, languages.extend('css', {}), 'css')}
|
||||
padding={10}
|
||||
style={{
|
||||
fontFamily: '"Fira code", "Fira Mono", monospace',
|
||||
fontSize: 12,
|
||||
minHeight: codeEditorHeight,
|
||||
}}
|
||||
/>
|
||||
{codeIsDirty && (
|
||||
<Box className={classes.codeEditorFooter}>
|
||||
<Group p="xs" spacing="xs">
|
||||
|
||||
@@ -19,6 +19,7 @@ export default function Layout({ children }: any) {
|
||||
minHeight: 'calc(100vh - var(--mantine-header-height))',
|
||||
},
|
||||
}}
|
||||
className="dashboard-app-shell"
|
||||
>
|
||||
<Head />
|
||||
<Background />
|
||||
|
||||
@@ -17,12 +17,14 @@ export function Logo({ size = 'md', withoutText = false }: LogoProps) {
|
||||
width={size === 'md' ? 50 : 12}
|
||||
src={config?.settings.customization.logoImageUrl || '/imgs/logo/logo-color.svg'}
|
||||
alt="Homarr Logo"
|
||||
className="dashboard-header-logo-image"
|
||||
/>
|
||||
{withoutText ? null : (
|
||||
<Text
|
||||
size={size === 'md' ? 22 : 10}
|
||||
weight="bold"
|
||||
variant="gradient"
|
||||
className="dashboard-header-logo-text"
|
||||
gradient={primaryGradient}
|
||||
>
|
||||
{config?.settings.customization.pageTitle || 'Homarr'}
|
||||
|
||||
@@ -13,7 +13,7 @@ export const HeaderHeight = 64;
|
||||
|
||||
export function Header(props: any) {
|
||||
const { classes } = useStyles();
|
||||
const { classes: cardClasses } = useCardStyles(false);
|
||||
const { classes: cardClasses, cx } = useCardStyles(false);
|
||||
const { attributes } = usePackageAttributesStore();
|
||||
|
||||
const { isLoading, error, data } = useQuery({
|
||||
@@ -27,12 +27,12 @@ export function Header(props: any) {
|
||||
data?.tag_name > `v${attributes.packageVersion}` ? data?.tag_name : undefined;
|
||||
|
||||
return (
|
||||
<MantineHeader height="auto" className={cardClasses.card}>
|
||||
<MantineHeader height="auto" className={cx(cardClasses.card, 'dashboard-header')}>
|
||||
<Group p="xs" noWrap grow>
|
||||
<Box className={classes.hide}>
|
||||
<Box className={cx(classes.hide, 'dashboard-header-logo-root')}>
|
||||
<Logo />
|
||||
</Box>
|
||||
<Group position="right" style={{ maxWidth: 'none' }} noWrap>
|
||||
<Group className="dashboard-header-group-right" position="right" style={{ maxWidth: 'none' }} noWrap>
|
||||
<Search />
|
||||
<ToggleEditModeAction />
|
||||
<DockerMenuButton />
|
||||
|
||||
@@ -57,7 +57,7 @@ export function Search() {
|
||||
const { config } = useConfigContext();
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [debounced] = useDebouncedValue(searchQuery, 250);
|
||||
const { classes: cardClasses } = useCardStyles(true);
|
||||
const { classes: cardClasses, cx } = useCardStyles(true);
|
||||
|
||||
const isOverseerrEnabled = config?.apps.some(
|
||||
(x) => x.integration.type === 'overseerr' || x.integration.type === 'jellyseerr'
|
||||
@@ -216,7 +216,8 @@ export function Search() {
|
||||
}
|
||||
}}
|
||||
classNames={{
|
||||
input: cardClasses.card,
|
||||
input: cx(cardClasses.card, 'dashboard-header-search-input'),
|
||||
root: 'dashboard-header-search-root',
|
||||
}}
|
||||
radius="lg"
|
||||
size="md"
|
||||
|
||||
Reference in New Issue
Block a user