feat: enhance onboarding

This commit is contained in:
Thomas Camlong authored and ajnart committed 2026-08-14 11:32:12 +02:00
1 parent ece6757979
commit 775ae0147c
23 files changed
+415 -170

No files matched your search

+1
View File
@@ -18,6 +18,7 @@ export { LanguageIcon } from "./language-icon";
export { LanguageCombobox } from "./language-combobox";
export { ColorSchemeCombobox } from "./color-scheme-combobox";
export { BoardColorInput } from "./board-color-input";
export { IntegrationMarquee } from "./integration-marquee";
export { Link } from "./link";
export {
SelectGridLayout,
@@ -0,0 +1,41 @@
.root {
--integration-marquee-accent: var(--mantine-primary-color-filled);
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: var(--mantine-spacing-xl);
height: 100%;
overflow: hidden;
transform: rotate(10deg);
}
.track {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--mantine-spacing-xl);
animation: integrationMarquee var(--marquee-duration) linear infinite;
}
.iconFrame {
display: grid;
flex: 0 0 4.5rem;
width: 4.5rem;
height: 4.5rem;
place-items: center;
border: 1px solid color-mix(in srgb, var(--integration-marquee-accent) 24%, transparent);
border-radius: var(--mantine-radius-lg);
background: color-mix(in srgb, var(--integration-marquee-accent) 8%, var(--mantine-color-body));
box-shadow: var(--mantine-shadow-sm);
}
@keyframes integrationMarquee {
to {
transform: translateY(-50%);
}
}
@media (prefers-reduced-motion: reduce) {
.track {
animation: none;
}
}
@@ -0,0 +1,2 @@
declare const classes: Record<string, string>;
export default classes;
@@ -0,0 +1,33 @@
import type { CSSProperties } from "react";
import { Image } from "@mantine/core";
import { splitToNChunks } from "@homarr/common";
import { integrationDefs } from "@homarr/definitions";
import classes from "./integration-marquee.module.css";
const iconGroups = splitToNChunks(
Object.values(integrationDefs)
.filter((integration) => integration.name !== "Mock")
.map((integration) => integration.iconUrl),
3,
);
const animationDuration = iconGroups.flat().length * 2;
export const IntegrationMarquee = ({ className }: { className?: string }) => (
<div className={[classes.root, className].filter(Boolean).join(" ")} aria-hidden>
{iconGroups.map((icons, columnIndex) => (
<div
key={columnIndex}
className={classes.track}
style={{ "--marquee-duration": `${animationDuration - columnIndex * 3}s` } as CSSProperties}
>
{[...icons, ...icons].map((icon, iconIndex) => (
<div key={`${icon}-${iconIndex}`} className={classes.iconFrame}>
<Image src={icon} alt="" fit="contain" w={52} h={52} />
</div>
))}
</div>
))}
</div>
);