diff --git a/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx b/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx index dc240d764..1d939c919 100644 --- a/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx +++ b/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx @@ -2,13 +2,14 @@ import type { PropsWithChildren } from "react"; import type { MantineColorScheme, MantineColorSchemeManager } from "@mantine/core"; -import { createTheme, DirectionProvider, MantineProvider } from "@mantine/core"; +import { DirectionProvider, MantineProvider } from "@mantine/core"; import dayjs from "dayjs"; import { clientApi } from "@homarr/api/client"; import { useSession } from "@homarr/auth/client"; import { parseCookies, setClientCookie } from "@homarr/common"; import { colorSchemeCookieKey } from "@homarr/definitions"; +import { theme } from "@homarr/ui"; export const CustomMantineProvider = ({ children, diff --git a/apps/nextjs/src/app/[locale]/auth/invite/[id]/page.tsx b/apps/nextjs/src/app/[locale]/auth/invite/[id]/page.tsx index cc6535703..dbf6306c3 100644 --- a/apps/nextjs/src/app/[locale]/auth/invite/[id]/page.tsx +++ b/apps/nextjs/src/app/[locale]/auth/invite/[id]/page.tsx @@ -59,7 +59,7 @@ export default async function InviteUsagePage(props: InviteUsagePageProps) { {t("subtitle")} - + diff --git a/apps/nextjs/src/app/[locale]/auth/login/page.tsx b/apps/nextjs/src/app/[locale]/auth/login/page.tsx index 22adf3b87..6cf00b6b3 100644 --- a/apps/nextjs/src/app/[locale]/auth/login/page.tsx +++ b/apps/nextjs/src/app/[locale]/auth/login/page.tsx @@ -37,7 +37,7 @@ export default async function Login(props: LoginProps) { {t("subtitle")} - + { }, [openAppSelectModal, createItem]); return ( - + @@ -183,7 +183,7 @@ const SelectBoardsMenu = () => { const { data: boards = [] } = clientApi.board.getAllBoards.useQuery(); return ( - + diff --git a/apps/nextjs/src/app/[locale]/init/_steps/finish/init-finish.tsx b/apps/nextjs/src/app/[locale]/init/_steps/finish/init-finish.tsx index 288b9adae..133581d58 100644 --- a/apps/nextjs/src/app/[locale]/init/_steps/finish/init-finish.tsx +++ b/apps/nextjs/src/app/[locale]/init/_steps/finish/init-finish.tsx @@ -15,7 +15,7 @@ export const InitFinish = async () => { const tFinish = await getScopedI18n("init.step.finish"); return ( - + {tFinish("description")} diff --git a/apps/nextjs/src/app/[locale]/init/_steps/group/init-group.tsx b/apps/nextjs/src/app/[locale]/init/_steps/group/init-group.tsx index 0a91d4ced..94424ef7d 100644 --- a/apps/nextjs/src/app/[locale]/init/_steps/group/init-group.tsx +++ b/apps/nextjs/src/app/[locale]/init/_steps/group/init-group.tsx @@ -34,7 +34,7 @@ export const InitGroup = () => { }; return ( - +
{ const tFileInfo = useScopedI18n("init.step.import.fileInfo"); return ( - + diff --git a/apps/nextjs/src/app/[locale]/init/_steps/import/init-import.tsx b/apps/nextjs/src/app/[locale]/init/_steps/import/init-import.tsx index 8b7124a03..cdb3faf50 100644 --- a/apps/nextjs/src/app/[locale]/init/_steps/import/init-import.tsx +++ b/apps/nextjs/src/app/[locale]/init/_steps/import/init-import.tsx @@ -20,7 +20,7 @@ export const InitImport = () => { if (!file) { return ( - + { diff --git a/apps/nextjs/src/app/[locale]/init/_steps/settings/init-settings.tsx b/apps/nextjs/src/app/[locale]/init/_steps/settings/init-settings.tsx index 3badc014e..cb024fc2f 100644 --- a/apps/nextjs/src/app/[locale]/init/_steps/settings/init-settings.tsx +++ b/apps/nextjs/src/app/[locale]/init/_steps/settings/init-settings.tsx @@ -30,7 +30,7 @@ export const InitSettings = () => { return ( - + {tSection("analytics.title")} @@ -39,7 +39,7 @@ export const InitSettings = () => { - + {tSection("crawlingAndIndexing.title")} diff --git a/apps/nextjs/src/app/[locale]/init/_steps/start/init-start.tsx b/apps/nextjs/src/app/[locale]/init/_steps/start/init-start.tsx index b5005f8b4..da858f1f4 100644 --- a/apps/nextjs/src/app/[locale]/init/_steps/start/init-start.tsx +++ b/apps/nextjs/src/app/[locale]/init/_steps/start/init-start.tsx @@ -10,7 +10,7 @@ export const InitStart = async () => { const tStart = await getScopedI18n("init.step.start"); return ( - + {tStart("description")} diff --git a/apps/nextjs/src/app/[locale]/init/_steps/user/init-user.tsx b/apps/nextjs/src/app/[locale]/init/_steps/user/init-user.tsx index 0f52de3dc..fa0ed777d 100644 --- a/apps/nextjs/src/app/[locale]/init/_steps/user/init-user.tsx +++ b/apps/nextjs/src/app/[locale]/init/_steps/user/init-user.tsx @@ -4,7 +4,7 @@ import { InitUserForm } from "./init-user-form"; export const InitUser = () => { return ( - + ); diff --git a/apps/nextjs/src/app/[locale]/layout.tsx b/apps/nextjs/src/app/[locale]/layout.tsx index 9342e0d30..e88f1965b 100644 --- a/apps/nextjs/src/app/[locale]/layout.tsx +++ b/apps/nextjs/src/app/[locale]/layout.tsx @@ -44,13 +44,13 @@ const fontSans = Inter({ export const generateMetadata = async (): Promise => ({ title: "Homarr", description: - "Simplify the management of your server with Homarr - a sleek, modern dashboard that puts all of your apps and services at your fingertips.", + "A self-hosted dashboard for the *arr stack and your entire homelab. Integrates with 50+ services, real-time widgets, no config files.", openGraph: { title: "Homarr Dashboard", description: - "Simplify the management of your server with Homarr - a sleek, modern dashboard that puts all of your apps and services at your fingertips.", + "A self-hosted dashboard for the *arr stack and your entire homelab. Integrates with 50+ services, real-time widgets, no config files.", url: "https://homarr.dev", - siteName: "Homarr Documentation", + siteName: "Homarr", }, icons: { icon: "/logo/logo.png", diff --git a/apps/nextjs/src/app/[locale]/manage/_components/hero-banner.tsx b/apps/nextjs/src/app/[locale]/manage/_components/hero-banner.tsx index b694ee81d..66c9e0398 100644 --- a/apps/nextjs/src/app/[locale]/manage/_components/hero-banner.tsx +++ b/apps/nextjs/src/app/[locale]/manage/_components/hero-banner.tsx @@ -45,7 +45,6 @@ export const HeroBanner = async () => { { - - Homarr - + Homarr {t("version", { version })} @@ -195,9 +193,9 @@ export default async function AboutPage() { href={`https://www.npmjs.com/package/${name}`} target="_blank" > - + - + diff --git a/apps/nextjs/src/app/[locale]/manage/apps/page.tsx b/apps/nextjs/src/app/[locale]/manage/apps/page.tsx index 25fa5ac9e..1093524e7 100644 --- a/apps/nextjs/src/app/[locale]/manage/apps/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/apps/page.tsx @@ -75,7 +75,7 @@ const AppCard = async ({ app }: AppCardProps) => { const session = await auth(); return ( - + { const VisibilityIcon = board.isPublic ? IconWorld : IconLock; return ( - + - - {board.name} - + {board.name} @@ -127,6 +125,7 @@ const BoardCard = async ({ board }: BoardCardProps) => { style={{ borderTop: "none", borderBottom: "none", borderRight: "none", borderRadius: 0 }} variant="default" size="lg" + aria-label={t("action.settings.label")} > diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-card.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-card.tsx index cc6a0a752..0bfe34ed0 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-card.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-card.tsx @@ -33,7 +33,7 @@ export const SecretCard = ({ secret, children, onCancel }: SecretCardProps) => { const KindIcon = integrationSecretIcons[secret.kind]; return ( - + @@ -58,7 +58,12 @@ export const SecretCard = ({ secret, children, onCancel }: SecretCardProps) => { )} {isPublic ? ( - + ) : null} diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/_components/test-connection/integration-test-connection-error.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/_components/test-connection/integration-test-connection-error.tsx index cdaa70d93..a50625106 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/_components/test-connection/integration-test-connection-error.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/_components/test-connection/integration-test-connection-error.tsx @@ -18,7 +18,7 @@ export const IntegrationTestConnectionError = ({ error, url }: IntegrationTestCo const causeArray = useMemo(() => toCauseArray(error.cause), [error.cause]); return ( - + diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/_components/test-connection/test-connection-certificate.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/_components/test-connection/test-connection-certificate.tsx index 9f7b00530..6ebbdbb6d 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/_components/test-connection/test-connection-certificate.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/_components/test-connection/test-connection-certificate.tsx @@ -216,7 +216,7 @@ export const CertificateDetailsCard = ({ certificate }: CertificateDetailsProps) const tCertificateField = useScopedI18n("certificate.field"); return ( - + {tDetails("title")} diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/page.module.css b/apps/nextjs/src/app/[locale]/manage/integrations/page.module.css index 34001e53b..551deb5ab 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/page.module.css +++ b/apps/nextjs/src/app/[locale]/manage/integrations/page.module.css @@ -8,7 +8,7 @@ border: 1px solid transparent; position: relative; z-index: 0; - transition: transform 150ms ease; + transition: background-color 150ms ease; overflow: hidden; &[data-first="true"] { @@ -20,11 +20,9 @@ } &[data-active] { - transform: scale(1.01); z-index: 1; background-color: var(--mantine-color-body); border-color: light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-4)); - box-shadow: var(--mantine-shadow-md); border-radius: var(--mantine-radius-lg); } } diff --git a/apps/nextjs/src/app/[locale]/manage/not-found.tsx b/apps/nextjs/src/app/[locale]/manage/not-found.tsx index 8579e45c4..f6931af9f 100644 --- a/apps/nextjs/src/app/[locale]/manage/not-found.tsx +++ b/apps/nextjs/src/app/[locale]/manage/not-found.tsx @@ -7,9 +7,7 @@ export default async function NotFound() { return (
- - {t("title")} - + {t("title")} {t("text")}
diff --git a/apps/nextjs/src/app/[locale]/manage/page.tsx b/apps/nextjs/src/app/[locale]/manage/page.tsx index 256eaddb5..c7a3a1813 100644 --- a/apps/nextjs/src/app/[locale]/manage/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/page.tsx @@ -29,20 +29,20 @@ export default async function ManagementPage() { {statistics.map((statistic) => ( - + - + {statistic.count} - + {t(`statisticLabel.${statistic.subtitleKey}`)} - {t(`statistic.${statistic.titleKey}`)} + {t(`statistic.${statistic.titleKey}`)} - + ))} diff --git a/apps/nextjs/src/app/[locale]/manage/search-engines/page.tsx b/apps/nextjs/src/app/[locale]/manage/search-engines/page.tsx index 00ca08055..fd4066d64 100644 --- a/apps/nextjs/src/app/[locale]/manage/search-engines/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/search-engines/page.tsx @@ -74,7 +74,7 @@ const SearchEngineCard = async ({ searchEngine }: SearchEngineCardProps) => { const session = await auth(); return ( - + { <> {t("title")} - - + + diff --git a/apps/nextjs/src/app/[locale]/manage/settings/_components/crawling-and-indexing.settings.tsx b/apps/nextjs/src/app/[locale]/manage/settings/_components/crawling-and-indexing.settings.tsx index b99f298ee..29206a473 100644 --- a/apps/nextjs/src/app/[locale]/manage/settings/_components/crawling-and-indexing.settings.tsx +++ b/apps/nextjs/src/app/[locale]/manage/settings/_components/crawling-and-indexing.settings.tsx @@ -41,11 +41,11 @@ export const CrawlingAndIndexingSettings = ({ initialData }: CrawlingAndIndexing <> {t("title")} - + {t("warning")} - + diff --git a/apps/nextjs/src/app/[locale]/manage/tools/certificates/page.tsx b/apps/nextjs/src/app/[locale]/manage/tools/certificates/page.tsx index cf1730736..422b9f858 100644 --- a/apps/nextjs/src/app/[locale]/manage/tools/certificates/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/tools/certificates/page.tsx @@ -79,7 +79,7 @@ export default async function CertificatesPage({ params }: CertificatesPageProps {x509Certificates.map((cert) => ( - + {cert.isError ? ( - @@ -253,7 +253,6 @@ const ContainerActionBarButton = (props: ContainerActionBarButtonProps) => { onClick={handleClickAsync} loading={isPending} variant="light" - radius="md" > {t(`${props.action}.label`)} diff --git a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/cluster-dashboard/header-card/header-card.module.css b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/cluster-dashboard/header-card/header-card.module.css index b439e7f4b..dbc035932 100644 --- a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/cluster-dashboard/header-card/header-card.module.css +++ b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/cluster-dashboard/header-card/header-card.module.css @@ -4,28 +4,16 @@ overflow: hidden; padding: var(--mantine-spacing-xs); padding-left: calc(var(--mantine-spacing-xs) * 2); - - @mixin hover { - box-shadow: var(--mantine-shadow-md); - } - - &::before { - content: ""; - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 6px; - background-image: linear-gradient(0, var(--mantine-color-blue-4), var(--mantine-color-blue-9)); - } + border-left: 1px solid var(--mantine-color-blue-6); + background-color: light-dark( + var(--mantine-color-blue-0), + color-mix(in oklch, var(--mantine-color-blue-9), transparent 85%) + ); @mixin rtl { padding-left: var(--mantine-spacing-xs); padding-right: calc(var(--mantine-spacing-xs) * 2); - - &::before { - left: unset; - right: 0; - } + border-left: none; + border-right: 1px solid var(--mantine-color-blue-6); } } diff --git a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/cluster-dashboard/header-card/header-card.tsx b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/cluster-dashboard/header-card/header-card.tsx index a8704e1b5..37ed66fe2 100644 --- a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/cluster-dashboard/header-card/header-card.tsx +++ b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/cluster-dashboard/header-card/header-card.tsx @@ -23,7 +23,6 @@ export function HeaderCard(props: HeaderCardProps) { - + + diff --git a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/cluster-dashboard/resource-tile/resource-tile.tsx b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/cluster-dashboard/resource-tile/resource-tile.tsx index d2405fcf7..17c922c90 100644 --- a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/cluster-dashboard/resource-tile/resource-tile.tsx +++ b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/cluster-dashboard/resource-tile/resource-tile.tsx @@ -17,12 +17,7 @@ interface ResourceTileProps { export function ResourceTile(props: ResourceTileProps) { const t = useI18n(); return ( - + {props.label} diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_profile-avatar-form.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_profile-avatar-form.tsx index e4ee64583..2137add34 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_profile-avatar-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_profile-avatar-form.tsx @@ -95,7 +95,7 @@ export const UserProfileAvatarForm = ({ user }: UserProfileAvatarForm) => { return ( - + diff --git a/apps/nextjs/src/app/[locale]/manage/users/create/_components/create-user-stepper.tsx b/apps/nextjs/src/app/[locale]/manage/users/create/_components/create-user-stepper.tsx index fbaae76c7..f443ae585 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/create/_components/create-user-stepper.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/create/_components/create-user-stepper.tsx @@ -149,7 +149,7 @@ export const UserCreateStepperComponent = ({ initialGroups }: UserCreateStepperC color={!generalForm.isValid() ? "red" : undefined} > - + - + - + @@ -198,20 +198,20 @@ export const UserCreateStepperComponent = ({ initialGroups }: UserCreateStepperC - + - + {generalForm.values.username} - + {t("step.completed.title")} diff --git a/apps/nextjs/src/app/[locale]/manage/users/create/_components/stepper-navigation.tsx b/apps/nextjs/src/app/[locale]/manage/users/create/_components/stepper-navigation.tsx index 24d003a84..675f3f435 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/create/_components/stepper-navigation.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/create/_components/stepper-navigation.tsx @@ -25,7 +25,7 @@ export const StepperNavigationComponent = ({ }: StepperNavigationComponentProps) => { const t = useI18n(); return ( - + {!isComplete ? ( @@ -170,7 +170,7 @@ const SupportedIntegrations = ({ integrations, mt }: SupportedIntegrationsProps) return (
- + {integrations.slice(0, countToShow).map((integration) => ( diff --git a/apps/nextjs/src/components/board/sections/category-section.tsx b/apps/nextjs/src/components/board/sections/category-section.tsx index feedcb964..4c3958859 100644 --- a/apps/nextjs/src/components/board/sections/category-section.tsx +++ b/apps/nextjs/src/components/board/sections/category-section.tsx @@ -45,13 +45,7 @@ export const BoardCategorySection = ({ section }: Props) => { }); return ( - + diff --git a/apps/nextjs/src/components/board/sections/category/category-menu.tsx b/apps/nextjs/src/components/board/sections/category/category-menu.tsx index 894db8949..9e3928198 100644 --- a/apps/nextjs/src/components/board/sections/category/category-menu.tsx +++ b/apps/nextjs/src/components/board/sections/category/category-menu.tsx @@ -30,9 +30,9 @@ export const CategoryMenu = ({ category }: Props) => { const t = useScopedI18n("section.category"); return ( - + - + diff --git a/apps/nextjs/src/components/board/sections/dynamic-section.tsx b/apps/nextjs/src/components/board/sections/dynamic-section.tsx index 39818c5de..8bb0a52c3 100644 --- a/apps/nextjs/src/components/board/sections/dynamic-section.tsx +++ b/apps/nextjs/src/components/board/sections/dynamic-section.tsx @@ -28,7 +28,6 @@ export const BoardDynamicSection = ({ section }: Props) => { className={combineClasses(classes.itemCard, section.options.customCssClasses.join(" "))} w="100%" h="100%" - withBorder styles={{ root: { overflow: "visible", diff --git a/apps/nextjs/src/components/board/sections/dynamic/dynamic-menu.tsx b/apps/nextjs/src/components/board/sections/dynamic/dynamic-menu.tsx index f73328024..cffc3446f 100644 --- a/apps/nextjs/src/components/board/sections/dynamic/dynamic-menu.tsx +++ b/apps/nextjs/src/components/board/sections/dynamic/dynamic-menu.tsx @@ -43,9 +43,17 @@ export const BoardDynamicSectionMenu = ({ section }: { section: DynamicSectionIt }; return ( - + - + diff --git a/apps/nextjs/src/components/layout/navigation-link.tsx b/apps/nextjs/src/components/layout/navigation-link.tsx index dd6949682..2d98d42ec 100644 --- a/apps/nextjs/src/components/layout/navigation-link.tsx +++ b/apps/nextjs/src/components/layout/navigation-link.tsx @@ -12,16 +12,7 @@ export const CommonNavLink = (props: ClientNavigationLink) => const NavLinkHref = (props: NavigationLinkHref) => { const pathname = usePathname(); return props.external ? ( - + ) : ( { leftSection={props.icon} href={props.href} active={pathname === props.href} - style={{ - borderRadius: 5, - }} /> ); }; @@ -40,14 +28,7 @@ const NavLinkWithItems = (props: NavigationLinkWithItems) => { const pathname = usePathname(); const isActive = props.items.some((item) => item.href === pathname); return ( - + {props.items.map((item) => ( ))} diff --git a/apps/nextjs/src/components/manage/danger-zone.tsx b/apps/nextjs/src/components/manage/danger-zone.tsx index 30bfb3e37..38f63185b 100644 --- a/apps/nextjs/src/components/manage/danger-zone.tsx +++ b/apps/nextjs/src/components/manage/danger-zone.tsx @@ -15,7 +15,7 @@ export const DangerZoneRoot = async ({ children }: DangerZoneRootProps) => { {t("common.dangerZone")} - + {Array.isArray(children) ? children.map((child, index) => ( diff --git a/apps/nextjs/src/components/no-results.tsx b/apps/nextjs/src/components/no-results.tsx index ecc794e46..9506bafa4 100644 --- a/apps/nextjs/src/components/no-results.tsx +++ b/apps/nextjs/src/components/no-results.tsx @@ -14,7 +14,7 @@ interface NoResultsProps { export const NoResults = ({ icon: Icon, title, action }: NoResultsProps) => { return ( - + diff --git a/apps/nextjs/src/components/user-avatar-menu.tsx b/apps/nextjs/src/components/user-avatar-menu.tsx index 454ecca78..8faa8f6fa 100644 --- a/apps/nextjs/src/components/user-avatar-menu.tsx +++ b/apps/nextjs/src/components/user-avatar-menu.tsx @@ -52,7 +52,7 @@ export const UserAvatarMenu = ({ children, availableUpdatesPromise }: UserAvatar return ( // We use keepMounted so we can add event listeners to prevent navigating away without saving the board - + }> diff --git a/packages/forms-collection/src/icon-picker/icon-picker.tsx b/packages/forms-collection/src/icon-picker/icon-picker.tsx index 0ad036f81..f407196a6 100644 --- a/packages/forms-collection/src/icon-picker/icon-picker.tsx +++ b/packages/forms-collection/src/icon-picker/icon-picker.tsx @@ -108,10 +108,9 @@ export const IconPicker = ({ cursor: "pointer", }} className={classes.iconCard} - withBorder > - + diff --git a/packages/modals-collection/src/apps/app-select-modal.tsx b/packages/modals-collection/src/apps/app-select-modal.tsx index e488eb3a6..e5530d341 100644 --- a/packages/modals-collection/src/apps/app-select-modal.tsx +++ b/packages/modals-collection/src/apps/app-select-modal.tsx @@ -77,7 +77,7 @@ export const AppSelectModal = createModal(({ actions, inner {t("app.action.create.description")} - @@ -100,7 +100,7 @@ export const AppSelectModal = createModal(({ actions, inner {app.description ?? ""} - diff --git a/packages/modals-collection/src/docker/add-docker-app-to-homarr.tsx b/packages/modals-collection/src/docker/add-docker-app-to-homarr.tsx index f94bf8f24..d83b16fdd 100644 --- a/packages/modals-collection/src/docker/add-docker-app-to-homarr.tsx +++ b/packages/modals-collection/src/docker/add-docker-app-to-homarr.tsx @@ -58,7 +58,7 @@ export const AddDockerAppToHomarrModal = createModal( }; return ( - + {innerProps.selectedContainers.map((container, index) => ( diff --git a/packages/modals-collection/src/search-engines/request-media-modal.tsx b/packages/modals-collection/src/search-engines/request-media-modal.tsx index efb92cf7a..89306f3af 100644 --- a/packages/modals-collection/src/search-engines/request-media-modal.tsx +++ b/packages/modals-collection/src/search-engines/request-media-modal.tsx @@ -83,15 +83,10 @@ export const RequestMediaModal = createModal(({ actions, return ( - + {data && ( - poster + poster {data.overview} diff --git a/packages/old-import/src/components/initial/board-selection-card.tsx b/packages/old-import/src/components/initial/board-selection-card.tsx index 294e68885..4665ec2cd 100644 --- a/packages/old-import/src/components/initial/board-selection-card.tsx +++ b/packages/old-import/src/components/initial/board-selection-card.tsx @@ -38,7 +38,7 @@ export const BoardSelectionCard = ({ selections, updateSelections }: BoardSelect } return ( - + @@ -57,7 +57,7 @@ export const BoardSelectionCard = ({ selections, updateSelections }: BoardSelect {[...selections.entries()].map(([name, selected]) => ( - + { const tImportSettings = useScopedI18n("init.step.import.importSettings"); return ( - + {tImportSettings("title")} diff --git a/packages/old-import/src/components/initial/import-summary-card.tsx b/packages/old-import/src/components/initial/import-summary-card.tsx index 876d1f43c..9993b3ac2 100644 --- a/packages/old-import/src/components/initial/import-summary-card.tsx +++ b/packages/old-import/src/components/initial/import-summary-card.tsx @@ -13,7 +13,7 @@ interface ImportSummaryCardProps { export const ImportSummaryCard = ({ counts, onSubmit, loading }: ImportSummaryCardProps) => { const tSummary = useScopedI18n("init.step.import.summary"); return ( - + {tSummary("title")} @@ -24,7 +24,7 @@ export const ImportSummaryCard = ({ counts, onSubmit, loading }: ImportSummaryCa {objectEntries(counts).map(([key, count]) => ( - + {tSummary(`entities.${key}`)} diff --git a/packages/spotlight/src/components/spotlight.tsx b/packages/spotlight/src/components/spotlight.tsx index c90542f45..4ca086f3b 100644 --- a/packages/spotlight/src/components/spotlight.tsx +++ b/packages/spotlight/src/components/spotlight.tsx @@ -110,6 +110,7 @@ const SpotlightWithActiveMode = ({ modeState, queryState, activeMode }: Spotligh inputRef.current?.focus(); }} variant="subtle" + aria-label={t("common.action.close")} > diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json index d7b690137..a62728845 100644 --- a/packages/translation/src/lang/en.json +++ b/packages/translation/src/lang/en.json @@ -1087,7 +1087,9 @@ "checkoutDocs": "Check out the documentation", "checkLogs": "Check logs for more details", "tryAgain": "Try again", - "loading": "Loading" + "loading": "Loading", + "show": "Show", + "hide": "Hide" }, "here": "here", "iconPicker": { @@ -1252,7 +1254,8 @@ "menu": { "label": { "create": "New category", - "changePosition": "Change position" + "changePosition": "Change position", + "settings": "Settings" } }, "openAllInNewTabs": { diff --git a/packages/ui/src/components/user-avatar-group.tsx b/packages/ui/src/components/user-avatar-group.tsx index 1aa2fbf6b..f014987e1 100644 --- a/packages/ui/src/components/user-avatar-group.tsx +++ b/packages/ui/src/components/user-avatar-group.tsx @@ -12,7 +12,7 @@ interface UserAvatarGroupProps { export const UserAvatarGroup = ({ size, limit, users }: UserAvatarGroupProps) => { return ( - + {users.slice(0, limit).map((user) => ( diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index 2a4bb91a1..364f7a394 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -2,6 +2,7 @@ import type { MantineProviderProps } from "@mantine/core"; import { theme } from "./theme"; +export { theme } from "./theme"; export * from "./components"; export const uiConfiguration = { diff --git a/packages/ui/src/theme.ts b/packages/ui/src/theme.ts index 7439ae440..9aea93dbf 100644 --- a/packages/ui/src/theme.ts +++ b/packages/ui/src/theme.ts @@ -1,13 +1,103 @@ -import { createTheme } from "@mantine/core"; - -import { primaryColor } from "./theme/colors/primary"; -import { secondaryColor } from "./theme/colors/secondary"; +import { createTheme, rem } from "@mantine/core"; export const theme = createTheme({ - colors: { - primaryColor, - secondaryColor, + primaryColor: "red", + autoContrast: true, + respectReducedMotion: true, + cursorType: "pointer", + + fontFamily: "Inter, system-ui, -apple-system, sans-serif", + fontFamilyMonospace: "ui-monospace, 'Cascadia Code', 'Fira Code', monospace", + + headings: { + fontFamily: "Inter, system-ui, -apple-system, sans-serif", + fontWeight: "600", + sizes: { + h1: { fontSize: rem(36), lineHeight: "1.1", fontWeight: "700" }, + h2: { fontSize: rem(24), lineHeight: "1.2", fontWeight: "700" }, + h3: { fontSize: rem(20), lineHeight: "1.3", fontWeight: "600" }, + h4: { fontSize: rem(16), lineHeight: "1.4", fontWeight: "600" }, + h5: { fontSize: rem(14), lineHeight: "1.5", fontWeight: "600" }, + h6: { fontSize: rem(12), lineHeight: "1.5", fontWeight: "600" }, + }, + }, + + fontSizes: { + xs: rem(12), + sm: rem(14), + md: rem(16), + lg: rem(18), + xl: rem(20), + }, + + spacing: { + xs: rem(10), + sm: rem(12), + md: rem(16), + lg: rem(20), + xl: rem(32), + }, + + radius: { + xs: rem(4), + sm: rem(4), + md: rem(8), + lg: rem(12), + xl: rem(16), + }, + defaultRadius: "md", + + shadows: { + xs: "0 1px 2px rgba(0, 0, 0, 0.04)", + sm: "0 1px 3px rgba(0, 0, 0, 0.06)", + md: "0 2px 8px rgba(0, 0, 0, 0.08)", + lg: "0 4px 12px rgba(0, 0, 0, 0.10)", + xl: "0 8px 24px rgba(0, 0, 0, 0.12)", + }, + + components: { + Card: { + defaultProps: { + withBorder: true, + radius: "lg", + }, + }, + Paper: { + defaultProps: { + withBorder: true, + radius: "md", + }, + }, + Button: { + defaultProps: { + radius: "md", + }, + }, + ActionIcon: { + defaultProps: { + radius: "md", + }, + }, + Tooltip: { + defaultProps: { + openDelay: 300, + }, + }, + Menu: { + defaultProps: { + withArrow: true, + }, + }, + NavLink: { + defaultProps: { + style: { borderRadius: 5 }, + }, + }, + LoadingOverlay: { + defaultProps: { + zIndex: 1000, + overlayProps: { radius: "sm", blur: 2 }, + }, + }, }, - primaryColor: "primaryColor", - defaultRadius: "sm", }); diff --git a/packages/ui/src/theme/colors/primary.ts b/packages/ui/src/theme/colors/primary.ts deleted file mode 100644 index 3bb5ef987..000000000 --- a/packages/ui/src/theme/colors/primary.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { MantineColorsTuple } from "@mantine/core"; - -export const primaryColor: MantineColorsTuple = [ - "#eafbf0", - "#ddefe3", - "#bedcc7", - "#9bc8aa", - "#7eb892", - "#6bad81", - "#60a878", - "#509265", - "#438359", - "#35724a", -]; diff --git a/packages/ui/src/theme/colors/secondary.ts b/packages/ui/src/theme/colors/secondary.ts deleted file mode 100644 index c3a10a691..000000000 --- a/packages/ui/src/theme/colors/secondary.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { MantineColorsTuple } from "@mantine/core"; - -export const secondaryColor: MantineColorsTuple = [ - "#e6f7ff", - "#d9e8f6", - "#b6cde6", - "#90b2d4", - "#6f9ac5", - "#5a8bbd", - "#4d84ba", - "#3d71a4", - "#326595", - "#205885", -]; diff --git a/packages/widgets/src/_inputs/widget-sortable-item-list-input.tsx b/packages/widgets/src/_inputs/widget-sortable-item-list-input.tsx index d765c1d73..f4f73fd72 100644 --- a/packages/widgets/src/_inputs/widget-sortable-item-list-input.tsx +++ b/packages/widgets/src/_inputs/widget-sortable-item-list-input.tsx @@ -194,8 +194,6 @@ const Item = ({ return ( + - + Coolify - + oolify @@ -75,7 +75,11 @@ export function SingleInstanceLayout({ instance, options, isTiny, widgetKey }: S )} - + Coolify diff --git a/packages/widgets/src/coolify/types.ts b/packages/widgets/src/coolify/types.ts index a5982b695..3316c503a 100644 --- a/packages/widgets/src/coolify/types.ts +++ b/packages/widgets/src/coolify/types.ts @@ -3,6 +3,7 @@ import type { CoolifyInstanceInfo } from "@homarr/integrations/types"; import type { WidgetComponentProps } from "../definition"; export const COOLIFY_ICON_URL = "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/coolify.svg"; +export const COOLIFY_BRAND_COLOR = "#8B5CF6"; export interface InstanceData { integrationId: string; diff --git a/packages/widgets/src/docker/component.tsx b/packages/widgets/src/docker/component.tsx index c135484a8..e47c77f33 100644 --- a/packages/widgets/src/docker/component.tsx +++ b/packages/widgets/src/docker/component.tsx @@ -62,7 +62,7 @@ const createColumns = ( Cell({ renderedCellValue, row }) { return ( - + {renderedCellValue} diff --git a/packages/widgets/src/downloads/component.tsx b/packages/widgets/src/downloads/component.tsx index 2a96dc7cf..96e63a106 100644 --- a/packages/widgets/src/downloads/component.tsx +++ b/packages/widgets/src/downloads/component.tsx @@ -864,7 +864,7 @@ const ClientsControl = ({ clients, filters, setFilters, availableStatuses }: Cli - + {client.status ? ( diff --git a/packages/widgets/src/health-monitoring/cluster/resource-table.tsx b/packages/widgets/src/health-monitoring/cluster/resource-table.tsx index 1b0d4fe6f..13e75bc90 100644 --- a/packages/widgets/src/health-monitoring/cluster/resource-table.tsx +++ b/packages/widgets/src/health-monitoring/cluster/resource-table.tsx @@ -1,4 +1,4 @@ -import { Group, Indicator, Popover, Table, TableTbody, TableThead, TableTr, Text } from "@mantine/core"; +import { Group, Indicator, Popover, Table, TableTbody, TableTh, TableThead, TableTr, Text } from "@mantine/core"; import type { Resource } from "@homarr/integrations/types"; import { useI18n } from "@homarr/translation/client"; @@ -17,23 +17,23 @@ export const ResourceTable = ({ type, data, isTiny }: ResourceTableProps) => { - + {t("widget.healthMonitoring.cluster.table.header.name")} - + {type !== "storage" ? ( - + {t("widget.healthMonitoring.cluster.table.header.cpu")} - + ) : null} {type !== "storage" ? ( - + {t("widget.healthMonitoring.cluster.table.header.memory")} - + ) : null} {type === "storage" ? ( - + {t("widget.healthMonitoring.cluster.table.header.node")} - + ) : null} diff --git a/packages/widgets/src/media-requests/list/component.tsx b/packages/widgets/src/media-requests/list/component.tsx index 3015451bc..5d86c40a1 100644 --- a/packages/widgets/src/media-requests/list/component.tsx +++ b/packages/widgets/src/media-requests/list/component.tsx @@ -95,7 +95,6 @@ const MediaRequestCard = ({ request, isTiny, options }: MediaRequestCardProps) = className={`mediaRequests-list-item-wrapper mediaRequests-list-item-${request.type} mediaRequests-list-item-${request.status}`} radius={board.itemRadius} p="xs" - withBorder > variant="light" color="green" size="xs" - radius="md" onClick={() => { handleDecision("approve"); }} @@ -228,7 +226,6 @@ const DecisionButtons = ({ requestId, integrationId }: DecisionButtonsProps) => variant="light" color="red" size="xs" - radius="md" onClick={() => { handleDecision("decline"); }} diff --git a/packages/widgets/src/media-requests/stats/component.tsx b/packages/widgets/src/media-requests/stats/component.tsx index e3696ef47..4a1b6ed09 100644 --- a/packages/widgets/src/media-requests/stats/component.tsx +++ b/packages/widgets/src/media-requests/stats/component.tsx @@ -23,6 +23,9 @@ import type { WidgetComponentProps } from "../../definition"; import { NoIntegrationDataError } from "../../errors/no-data-integration"; import classes from "./component.module.css"; +const OVERSEERR_COLOR = "#ECB000"; +const JELLYSEERR_COLOR = "#6677CC"; + export default function MediaServerWidget({ integrationIds, isEditMode, @@ -151,7 +154,7 @@ export default function MediaServerWidget({ className="mediaRequests-stats-users-user-avatar" size={20} src={user.avatar} - bd={`2px solid ${user.integration.kind === "overseerr" ? "#ECB000" : "#6677CC"}`} + bd={`2px solid ${user.integration.kind === "overseerr" ? OVERSEERR_COLOR : JELLYSEERR_COLOR}`} /> diff --git a/packages/widgets/src/media-transcoding/health-check-status.tsx b/packages/widgets/src/media-transcoding/health-check-status.tsx index d1b3f7df9..24a8100d3 100644 --- a/packages/widgets/src/media-transcoding/health-check-status.tsx +++ b/packages/widgets/src/media-transcoding/health-check-status.tsx @@ -27,7 +27,11 @@ export function HealthCheckStatus(props: HealthCheckStatusProps) { - + diff --git a/packages/widgets/src/media-transcoding/panels/queue.panel.tsx b/packages/widgets/src/media-transcoding/panels/queue.panel.tsx index 45cc7581f..99e8e9e2a 100644 --- a/packages/widgets/src/media-transcoding/panels/queue.panel.tsx +++ b/packages/widgets/src/media-transcoding/panels/queue.panel.tsx @@ -1,4 +1,17 @@ -import { Center, Group, ScrollArea, Table, TableTd, TableTh, TableTr, Text, Title, Tooltip } from "@mantine/core"; +import { + Center, + Group, + ScrollArea, + Table, + TableTbody, + TableTd, + TableTh, + TableThead, + TableTr, + Text, + Title, + Tooltip, +} from "@mantine/core"; import { IconHeartbeat, IconTransform } from "@tabler/icons-react"; import { humanFileSize } from "@homarr/common"; @@ -25,7 +38,7 @@ export function QueuePanel(props: QueuePanelProps) { return (
- + @@ -38,8 +51,8 @@ export function QueuePanel(props: QueuePanelProps) { - - + + {queue.array.map((item) => ( @@ -63,7 +76,7 @@ export function QueuePanel(props: QueuePanelProps) { ))} - +
); diff --git a/packages/widgets/src/media-transcoding/panels/statistics.panel.tsx b/packages/widgets/src/media-transcoding/panels/statistics.panel.tsx index b80dab0dd..af7c4b15b 100644 --- a/packages/widgets/src/media-transcoding/panels/statistics.panel.tsx +++ b/packages/widgets/src/media-transcoding/panels/statistics.panel.tsx @@ -91,7 +91,7 @@ function StatisticItem(props: StatisticItemProps) { const board = useRequiredBoard(); return ( - + {props.value} diff --git a/packages/widgets/src/media-transcoding/panels/workers.panel.tsx b/packages/widgets/src/media-transcoding/panels/workers.panel.tsx index d1602c248..3dbf968b7 100644 --- a/packages/widgets/src/media-transcoding/panels/workers.panel.tsx +++ b/packages/widgets/src/media-transcoding/panels/workers.panel.tsx @@ -4,8 +4,10 @@ import { Progress, ScrollArea, Table, + TableTbody, TableTd, TableTh, + TableThead, TableTr, Text, Title, @@ -35,7 +37,7 @@ export function WorkersPanel(props: WorkersPanelProps) { return ( - + @@ -53,8 +55,8 @@ export function WorkersPanel(props: WorkersPanelProps) { - - + + {props.workers.map((worker) => { const fileName = worker.filePath.split("\\").pop()?.split("/").pop() ?? worker.filePath; return ( @@ -101,7 +103,7 @@ export function WorkersPanel(props: WorkersPanelProps) { ); })} - +
); diff --git a/packages/widgets/src/notebook/notebook.tsx b/packages/widgets/src/notebook/notebook.tsx index e7377b4b9..97721daf7 100644 --- a/packages/widgets/src/notebook/notebook.tsx +++ b/packages/widgets/src/notebook/notebook.tsx @@ -421,7 +421,6 @@ export function Notebook({ options, setOptions, isEditMode, boardId, itemId }: W color={primaryColor} variant="light" size={30} - radius={"md"} onClick={handleEditToggle} > {isEditing ? : } @@ -438,7 +437,6 @@ export function Notebook({ options, setOptions, isEditMode, boardId, itemId }: W color={primaryColor} variant="light" size={30} - radius={"md"} onClick={handleEditCancel} > diff --git a/packages/widgets/src/notifications/component.tsx b/packages/widgets/src/notifications/component.tsx index 1fc4d6910..72a662956 100644 --- a/packages/widgets/src/notifications/component.tsx +++ b/packages/widgets/src/notifications/component.tsx @@ -67,7 +67,7 @@ export default function NotificationsWidget({ options, integrationIds }: WidgetC {sortedNotifications.length > 0 ? ( sortedNotifications.map((notification) => ( - + {notification.title && ( diff --git a/packages/widgets/src/releases/component.module.scss b/packages/widgets/src/releases/component.module.scss index 1fbdf7434..9d41454cb 100644 --- a/packages/widgets/src/releases/component.module.scss +++ b/packages/widgets/src/releases/component.module.scss @@ -1,10 +1,8 @@ .releasesRepository { - border-left: 2px solid transparent; - &:has(.releasesRepositoryHeader:hover), &:has(.releasesRepositoryHeader.active), &:has(.releasesRepositoryDetails:hover) { - border-left-color: var(--mantine-color-secondaryColor-text); + background-color: var(--mantine-color-secondaryColor-light); } } diff --git a/packages/widgets/src/rssFeed/component.tsx b/packages/widgets/src/rssFeed/component.tsx index f219cd2e4..843168b88 100644 --- a/packages/widgets/src/rssFeed/component.tsx +++ b/packages/widgets/src/rssFeed/component.tsx @@ -57,7 +57,6 @@ export default function RssFeed({ options, width }: WidgetComponentProps<"rssFee {feedEntries.map((feedEntry) => ( )} - +
diff --git a/packages/widgets/src/system-resources/chart/combined-network-traffic.tsx b/packages/widgets/src/system-resources/chart/combined-network-traffic.tsx index 6cfee0eaa..20b01bb58 100644 --- a/packages/widgets/src/system-resources/chart/combined-network-traffic.tsx +++ b/packages/widgets/src/system-resources/chart/combined-network-traffic.tsx @@ -38,7 +38,7 @@ export const CombinedNetworkTrafficChart = ({ tooltipProps={{ content: ({ payload }) => { return ( - + {payload.map((payloadData) => ( diff --git a/packages/widgets/src/system-resources/chart/cpu-chart.tsx b/packages/widgets/src/system-resources/chart/cpu-chart.tsx index 7006728d5..a799978ae 100644 --- a/packages/widgets/src/system-resources/chart/cpu-chart.tsx +++ b/packages/widgets/src/system-resources/chart/cpu-chart.tsx @@ -36,7 +36,7 @@ export const SystemResourceCPUChart = ({ content: ({ payload }) => { const value = payload[0] ? Number(payload[0].value) : 0; return ( - + {value.toFixed(0)}% diff --git a/packages/widgets/src/system-resources/chart/gpu-chart.tsx b/packages/widgets/src/system-resources/chart/gpu-chart.tsx index bf2d34b40..4efdb0bab 100644 --- a/packages/widgets/src/system-resources/chart/gpu-chart.tsx +++ b/packages/widgets/src/system-resources/chart/gpu-chart.tsx @@ -36,7 +36,7 @@ export const SystemResourceGPUChart = ({ content: ({ payload }) => { const value = payload[0] ? Number(payload[0].value) : 0; return ( - + {value.toFixed(0)}% diff --git a/packages/widgets/src/system-resources/chart/memory-chart.tsx b/packages/widgets/src/system-resources/chart/memory-chart.tsx index 54c2e347c..9de519199 100644 --- a/packages/widgets/src/system-resources/chart/memory-chart.tsx +++ b/packages/widgets/src/system-resources/chart/memory-chart.tsx @@ -42,7 +42,7 @@ export const SystemResourceMemoryChart = ({ content: ({ payload }) => { const value = payload[0] ? Number(payload[0].value) : 0; return ( - + {humanFileSize(Math.round(value))} / {humanFileSize(totalCapacityInBytes)} ( {Math.round((value / totalCapacityInBytes) * 100)}%) diff --git a/packages/widgets/src/system-resources/chart/network-traffic.tsx b/packages/widgets/src/system-resources/chart/network-traffic.tsx index 02747b86d..9dd0b6d04 100644 --- a/packages/widgets/src/system-resources/chart/network-traffic.tsx +++ b/packages/widgets/src/system-resources/chart/network-traffic.tsx @@ -39,7 +39,7 @@ export const NetworkTrafficChart = ({ content: ({ payload }) => { const value = payload[0] ? Number(payload[0].value) : 0; return ( - + {humanFileSize(Math.round(value))}/s diff --git a/packages/widgets/src/tracearr/recent-activity-section.tsx b/packages/widgets/src/tracearr/recent-activity-section.tsx index 84fe35c3b..e078fd6f2 100644 --- a/packages/widgets/src/tracearr/recent-activity-section.tsx +++ b/packages/widgets/src/tracearr/recent-activity-section.tsx @@ -24,7 +24,7 @@ export function RecentActivityList({ sessions }: { sessions: TracearrHistorySess : session.mediaTitle; return ( - + diff --git a/packages/widgets/src/tracearr/stats-section.tsx b/packages/widgets/src/tracearr/stats-section.tsx index efa2d8b32..60b4ef125 100644 --- a/packages/widgets/src/tracearr/stats-section.tsx +++ b/packages/widgets/src/tracearr/stats-section.tsx @@ -32,7 +32,7 @@ export function StatsBar({ function StatCard({ icon, label, value }: { icon: React.ReactNode; label: string; value: string | number }) { return ( - + {icon} diff --git a/packages/widgets/src/tracearr/streams-section.tsx b/packages/widgets/src/tracearr/streams-section.tsx index e7908b7ba..0b9d0a3bc 100644 --- a/packages/widgets/src/tracearr/streams-section.tsx +++ b/packages/widgets/src/tracearr/streams-section.tsx @@ -45,7 +45,7 @@ function StreamCard({ stream, compact }: { stream: TracearrStream; compact: bool : null; return ( - + {stream.posterUrl && ( - + {mediaLabel} diff --git a/packages/widgets/src/tracearr/violations-section.tsx b/packages/widgets/src/tracearr/violations-section.tsx index a35c5a933..2ce675ed8 100644 --- a/packages/widgets/src/tracearr/violations-section.tsx +++ b/packages/widgets/src/tracearr/violations-section.tsx @@ -19,7 +19,7 @@ export function ViolationsList({ violations }: { violations: TracearrViolation[] ) : ( {violations.map((violation) => ( - +