feat: replace initial-data with full *.lafabriquedesgenies.be HTTPS services & direct URL editor
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
91a57285b9
commit
205337f5c8
8 files changed
+844
-296
No files matched your search
+401
-2
@@ -1,4 +1,403 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"note": "Fichier de persistance locale pour le portail Home. Synchronisé avec src/data/initial-data.ts."
|
||||
"version": "3.0.0",
|
||||
"dockTileIds": [
|
||||
"nextcloud",
|
||||
"dockge",
|
||||
"gitea",
|
||||
"jellyfin",
|
||||
"open-webui",
|
||||
"vaultwarden"
|
||||
],
|
||||
"quickNote": "Bienvenue sur Home OS (*.lafabriquedesgenies.be). Cliquez sur « Éditer » pour ajuster n'importe quelle URL ou sous-domaine à la volée.",
|
||||
"categories": [
|
||||
{
|
||||
"id": "infrastructure",
|
||||
"name": "Infrastructure & Serveur",
|
||||
"subtitle": "Administration système, conteneurs Docker, sauvegardes & réseau",
|
||||
"icon": "Server",
|
||||
"tabs": [
|
||||
{
|
||||
"id": "infra-main",
|
||||
"label": "Services Serveur",
|
||||
"tiles": [
|
||||
{
|
||||
"id": "dockge",
|
||||
"title": "Dockge",
|
||||
"description": "Gestionnaire Docker Compose",
|
||||
"url": "https://dockge.lafabriquedesgenies.be",
|
||||
"icon": "Terminal",
|
||||
"size": "2x1",
|
||||
"badge": "Docker",
|
||||
"accentColor": "emerald",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "nginx-proxy-manager",
|
||||
"title": "Nginx Proxy Manager",
|
||||
"description": "Reverse Proxy & Certificats SSL",
|
||||
"url": "https://proxy.lafabriquedesgenies.be",
|
||||
"icon": "Shield",
|
||||
"size": "1x1",
|
||||
"badge": "Proxy SSL",
|
||||
"accentColor": "blue",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "duplicati",
|
||||
"title": "Duplicati",
|
||||
"description": "Sauvegardes du serveur",
|
||||
"url": "https://backup.lafabriquedesgenies.be",
|
||||
"icon": "Archive",
|
||||
"size": "1x1",
|
||||
"badge": "Backup",
|
||||
"accentColor": "sky",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "speedtest",
|
||||
"title": "Speedtest",
|
||||
"description": "Surveillance débit réseau",
|
||||
"url": "https://speedtest.lafabriquedesgenies.be",
|
||||
"icon": "Activity",
|
||||
"size": "1x1",
|
||||
"badge": "Réseau",
|
||||
"accentColor": "cyan",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "adminer",
|
||||
"title": "Adminer",
|
||||
"description": "Gestionnaire bases SQL",
|
||||
"url": "https://db.lafabriquedesgenies.be",
|
||||
"icon": "Database",
|
||||
"size": "1x1",
|
||||
"badge": "SQL",
|
||||
"accentColor": "amber",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "adguard-home",
|
||||
"title": "AdGuard Home",
|
||||
"description": "Filtrage DNS & Antipub",
|
||||
"url": "https://adguard.lafabriquedesgenies.be",
|
||||
"icon": "ShieldCheck",
|
||||
"size": "1x1",
|
||||
"badge": "DNS",
|
||||
"accentColor": "teal",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "watchtower",
|
||||
"title": "Watchtower",
|
||||
"description": "Mises à jour automatiques",
|
||||
"url": "https://dockge.lafabriquedesgenies.be",
|
||||
"icon": "RefreshCw",
|
||||
"size": "1x1",
|
||||
"badge": "Daemon Auto",
|
||||
"accentColor": "violet",
|
||||
"openBehavior": "external"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "private-security",
|
||||
"name": "Privé & Sécurité",
|
||||
"subtitle": "Cloud personnel, mots de passe, documents, notes & domotique",
|
||||
"icon": "ShieldCheck",
|
||||
"tabs": [
|
||||
{
|
||||
"id": "private-main",
|
||||
"label": "Espace Privé",
|
||||
"tiles": [
|
||||
{
|
||||
"id": "nextcloud",
|
||||
"title": "Nextcloud",
|
||||
"description": "Fichiers & Drive Cloud",
|
||||
"url": "https://nc.lafabriquedesgenies.be",
|
||||
"icon": "Cloud",
|
||||
"size": "2x1",
|
||||
"badge": "Cloud",
|
||||
"accentColor": "sky",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "vaultwarden",
|
||||
"title": "Vaultwarden",
|
||||
"description": "Gestionnaire de mots de passe",
|
||||
"url": "https://vault.lafabriquedesgenies.be",
|
||||
"icon": "Key",
|
||||
"size": "1x1",
|
||||
"badge": "Coffre-fort",
|
||||
"accentColor": "amber",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "paperless-ngx",
|
||||
"title": "Paperless-ngx",
|
||||
"description": "GED & Archivage intelligent",
|
||||
"url": "https://paperless.lafabriquedesgenies.be",
|
||||
"icon": "FileText",
|
||||
"size": "1x1",
|
||||
"badge": "GED",
|
||||
"accentColor": "emerald",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "wikijs",
|
||||
"title": "Wiki.js",
|
||||
"description": "Base de connaissances & notes",
|
||||
"url": "https://wiki.lafabriquedesgenies.be",
|
||||
"icon": "BookOpen",
|
||||
"size": "1x1",
|
||||
"badge": "Wiki",
|
||||
"accentColor": "indigo",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "stirling-pdf",
|
||||
"title": "Stirling PDF",
|
||||
"description": "Boîte à outils PDF complète",
|
||||
"url": "https://pdf.lafabriquedesgenies.be",
|
||||
"icon": "FileCode",
|
||||
"size": "1x1",
|
||||
"badge": "PDF",
|
||||
"accentColor": "rose",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "home-assistant",
|
||||
"title": "Home Assistant",
|
||||
"description": "Domotique de la maison",
|
||||
"url": "https://hass.lafabriquedesgenies.be",
|
||||
"icon": "Home",
|
||||
"size": "2x1",
|
||||
"badge": "Domotique",
|
||||
"accentColor": "cyan",
|
||||
"openBehavior": "external"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "multimedia",
|
||||
"name": "Multimédia & Médias",
|
||||
"subtitle": "Streaming vidéo, livres audio, musique & téléchargements",
|
||||
"icon": "Film",
|
||||
"tabs": [
|
||||
{
|
||||
"id": "media-main",
|
||||
"label": "Streaming & Téléchargements",
|
||||
"tiles": [
|
||||
{
|
||||
"id": "jellyfin",
|
||||
"title": "Jellyfin",
|
||||
"description": "Streaming Films & Séries",
|
||||
"url": "https://jellyfin.lafabriquedesgenies.be",
|
||||
"icon": "Film",
|
||||
"size": "2x1",
|
||||
"badge": "Streaming",
|
||||
"accentColor": "purple",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "audiobookshelf",
|
||||
"title": "Audiobookshelf",
|
||||
"description": "Livres audio & Podcasts",
|
||||
"url": "https://audiobookshelf.lafabriquedesgenies.be",
|
||||
"icon": "Headphones",
|
||||
"size": "1x1",
|
||||
"badge": "Audio",
|
||||
"accentColor": "amber",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "sonarr",
|
||||
"title": "Sonarr",
|
||||
"description": "Suivi & gestion des séries",
|
||||
"url": "https://sonarr.lafabriquedesgenies.be",
|
||||
"icon": "Tv",
|
||||
"size": "1x1",
|
||||
"badge": "Séries",
|
||||
"accentColor": "sky",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "radarr",
|
||||
"title": "Radarr",
|
||||
"description": "Suivi & gestion des films",
|
||||
"url": "https://radarr.lafabriquedesgenies.be",
|
||||
"icon": "Video",
|
||||
"size": "1x1",
|
||||
"badge": "Films",
|
||||
"accentColor": "amber",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "qbittorrent",
|
||||
"title": "qBittorrent",
|
||||
"description": "Téléchargements VPN (Gluetun)",
|
||||
"url": "https://torrent.lafabriquedesgenies.be",
|
||||
"icon": "DownloadCloud",
|
||||
"size": "1x1",
|
||||
"badge": "VPN Gluetun",
|
||||
"accentColor": "blue",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "deemix",
|
||||
"title": "Deemix",
|
||||
"description": "Téléchargement Musique",
|
||||
"url": "https://deemix.lafabriquedesgenies.be",
|
||||
"icon": "Music",
|
||||
"size": "1x1",
|
||||
"badge": "Musique",
|
||||
"accentColor": "pink",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "sabnzbd",
|
||||
"title": "SABnzbd",
|
||||
"description": "Client Usenet",
|
||||
"url": "https://sabnzbd.lafabriquedesgenies.be",
|
||||
"icon": "HardDriveDownload",
|
||||
"size": "1x1",
|
||||
"badge": "Usenet",
|
||||
"accentColor": "emerald",
|
||||
"openBehavior": "external"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "projects-work",
|
||||
"name": "Projets & Travail",
|
||||
"subtitle": "Forge Git, applications La Fabrique des Génies & outils métiers",
|
||||
"icon": "Briefcase",
|
||||
"tabs": [
|
||||
{
|
||||
"id": "work-main",
|
||||
"label": "Applications & Projets",
|
||||
"tiles": [
|
||||
{
|
||||
"id": "gitea",
|
||||
"title": "Gitea",
|
||||
"description": "Dépôts de code Git",
|
||||
"url": "https://git.lafabriquedesgenies.be",
|
||||
"icon": "GitBranch",
|
||||
"size": "2x1",
|
||||
"badge": "Git",
|
||||
"accentColor": "emerald",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "wordpress-lafabrique",
|
||||
"title": "WordPress La Fabrique",
|
||||
"description": "Site officiel La Fabrique",
|
||||
"url": "https://lafabriquedesgenies.be",
|
||||
"icon": "Globe",
|
||||
"size": "1x1",
|
||||
"badge": "Site Web",
|
||||
"accentColor": "blue",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "teacher-app",
|
||||
"title": "Teacher App",
|
||||
"description": "Plateforme pédagogique",
|
||||
"url": "https://teacher.lafabriquedesgenies.be",
|
||||
"icon": "GraduationCap",
|
||||
"size": "1x1",
|
||||
"badge": "Pédagogie",
|
||||
"accentColor": "indigo",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "creaprof",
|
||||
"title": "CreaProf",
|
||||
"description": "Outil création enseignant",
|
||||
"url": "https://creaprof.lafabriquedesgenies.be",
|
||||
"icon": "PenTool",
|
||||
"size": "1x1",
|
||||
"badge": "Création",
|
||||
"accentColor": "violet",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "ubicraft",
|
||||
"title": "Ubicraft",
|
||||
"description": "Application métier",
|
||||
"url": "https://ubicraft.lafabriquedesgenies.be",
|
||||
"icon": "LayoutGrid",
|
||||
"size": "1x1",
|
||||
"badge": "Métier",
|
||||
"accentColor": "cyan",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "lma-v2",
|
||||
"title": "LMA V2",
|
||||
"description": "Plateforme Last Minute Activities",
|
||||
"url": "https://lma.lafabriquedesgenies.be",
|
||||
"icon": "Briefcase",
|
||||
"size": "1x1",
|
||||
"badge": "LMA",
|
||||
"accentColor": "amber",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "coo-app",
|
||||
"title": "Coo App",
|
||||
"description": "Application de gestion",
|
||||
"url": "https://coo.lafabriquedesgenies.be",
|
||||
"icon": "Layers",
|
||||
"size": "1x1",
|
||||
"badge": "Gestion",
|
||||
"accentColor": "teal",
|
||||
"openBehavior": "external"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ai",
|
||||
"name": "Intelligence Artificielle",
|
||||
"subtitle": "Modèles LLM auto-hébergés & Assistant Google Gemini intégré",
|
||||
"icon": "Sparkles",
|
||||
"tabs": [
|
||||
{
|
||||
"id": "ai-main",
|
||||
"label": "Assistants IA",
|
||||
"tiles": [
|
||||
{
|
||||
"id": "open-webui",
|
||||
"title": "Open WebUI",
|
||||
"description": "Interface modèles LLM",
|
||||
"url": "https://ai.lafabriquedesgenies.be",
|
||||
"icon": "Bot",
|
||||
"size": "2x1",
|
||||
"badge": "LLM",
|
||||
"accentColor": "emerald",
|
||||
"openBehavior": "external"
|
||||
},
|
||||
{
|
||||
"id": "google-gemini",
|
||||
"title": "Google Gemini",
|
||||
"description": "Assistant IA intégré",
|
||||
"url": "#gemini",
|
||||
"icon": "Sparkles",
|
||||
"size": "2x1",
|
||||
"badge": "Omnibox IA",
|
||||
"accentColor": "blue",
|
||||
"openBehavior": "external"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -12,7 +12,11 @@ async function readOrInitData(): Promise<DashboardData> {
|
||||
await fs.mkdir(DATA_DIR, { recursive: true });
|
||||
const raw = await fs.readFile(DATA_FILE, "utf-8");
|
||||
const parsed = JSON.parse(raw);
|
||||
if (parsed && Array.isArray(parsed.categories)) {
|
||||
if (
|
||||
parsed &&
|
||||
Array.isArray(parsed.categories) &&
|
||||
parsed.version === initialDashboardData.version
|
||||
) {
|
||||
return parsed as DashboardData;
|
||||
}
|
||||
await fs.writeFile(
|
||||
@@ -46,9 +50,13 @@ export async function POST(request: Request) {
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
const payload: DashboardData = {
|
||||
...body,
|
||||
version: initialDashboardData.version,
|
||||
};
|
||||
await fs.mkdir(DATA_DIR, { recursive: true });
|
||||
await fs.writeFile(DATA_FILE, JSON.stringify(body, null, 2), "utf-8");
|
||||
return NextResponse.json({ ok: true, data: body });
|
||||
await fs.writeFile(DATA_FILE, JSON.stringify(payload, null, 2), "utf-8");
|
||||
return NextResponse.json({ ok: true, data: payload });
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{ error: "Impossible de sauvegarder data.json", details: String(error) },
|
||||
|
||||
@@ -12,12 +12,16 @@ import {
|
||||
Layers,
|
||||
ArrowLeft,
|
||||
ArrowRight,
|
||||
Sparkles,
|
||||
} from "lucide-react";
|
||||
|
||||
interface BentoGridProps {
|
||||
tiles: ShortcutTile[];
|
||||
isEditMode: boolean;
|
||||
onLaunchTile: (tile: ShortcutTile, forceMode?: "workspace" | "popup" | "external") => void;
|
||||
onLaunchTile: (
|
||||
tile: ShortcutTile,
|
||||
forceMode?: "workspace" | "popup" | "external"
|
||||
) => void;
|
||||
onAddTile: () => void;
|
||||
onEditTile: (tile: ShortcutTile) => void;
|
||||
onDeleteTile: (tileId: string) => void;
|
||||
@@ -91,6 +95,7 @@ const accentStyles: Record<
|
||||
};
|
||||
|
||||
function formatHostname(url: string) {
|
||||
if (!url || url === "#gemini") return "Assistant intégré";
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
return parsed.host;
|
||||
@@ -120,19 +125,22 @@ export function BentoGrid({
|
||||
|
||||
const style =
|
||||
accentStyles[tile.accentColor || "indigo"] || accentStyles.indigo;
|
||||
const behavior = tile.openBehavior || "workspace";
|
||||
const behavior = tile.openBehavior || "external";
|
||||
const isGeminiWidget = tile.url === "#gemini";
|
||||
|
||||
return (
|
||||
<div
|
||||
key={tile.id}
|
||||
onClick={() => {
|
||||
if (!isEditMode) {
|
||||
if (isEditMode) {
|
||||
onEditTile(tile);
|
||||
} else {
|
||||
onLaunchTile(tile);
|
||||
}
|
||||
}}
|
||||
className={`group relative flex flex-col justify-between overflow-hidden rounded-2xl border border-white/10 bg-zinc-900/60 p-4 sm:p-5 backdrop-blur-md transition-all duration-200 select-none ${spanClass} ${
|
||||
isEditMode
|
||||
? "border-dashed border-amber-500/40 bg-zinc-900/80"
|
||||
? "cursor-pointer border-dashed border-amber-500/40 bg-zinc-900/80 hover:border-amber-400"
|
||||
: `cursor-pointer ${style.borderHover} hover:-translate-y-0.5 hover:bg-zinc-900/90 hover:shadow-xl hover:shadow-black/40`
|
||||
}`}
|
||||
>
|
||||
@@ -175,10 +183,11 @@ export function BentoGrid({
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onEditTile(tile)}
|
||||
title="Modifier la tuile"
|
||||
className="rounded p-1 text-amber-300 hover:bg-amber-500/20"
|
||||
title="Modifier l'URL ou les détails"
|
||||
className="flex items-center gap-1 rounded bg-amber-500/15 px-1.5 py-1 text-[10px] font-medium text-amber-300 hover:bg-amber-500/25"
|
||||
>
|
||||
<Pencil className="size-3.5" />
|
||||
<Pencil className="size-3" />
|
||||
<span>URL</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -203,8 +212,26 @@ export function BentoGrid({
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
{/* Quick override buttons on hover */}
|
||||
{isGeminiWidget ? (
|
||||
<span className="flex items-center gap-1 rounded-lg border border-blue-500/30 bg-blue-500/15 px-2 py-1 text-[10px] font-medium text-blue-300">
|
||||
<Sparkles className="size-3" />
|
||||
<span>Ouvrir IA</span>
|
||||
</span>
|
||||
) : (
|
||||
/* Quick override buttons on hover */
|
||||
<div className="flex items-center gap-0.5 rounded-lg border border-white/8 bg-zinc-950/70 p-0.5 opacity-80 sm:opacity-0 transition-opacity group-hover:opacity-100">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onLaunchTile(tile, "external")}
|
||||
title="Ouvrir dans un nouvel onglet"
|
||||
className={`rounded p-1 transition-colors ${
|
||||
behavior === "external"
|
||||
? "text-emerald-400 bg-emerald-500/15"
|
||||
: "text-zinc-400 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
<ExternalLink className="size-3" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onLaunchTile(tile, "workspace")}
|
||||
@@ -220,7 +247,7 @@ export function BentoGrid({
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onLaunchTile(tile, "popup")}
|
||||
title="Ouvrir en fenêtre App Chromium (idéal Google Docs/Drive)"
|
||||
title="Ouvrir en fenêtre App dédiée"
|
||||
className={`rounded p-1 transition-colors ${
|
||||
behavior === "popup"
|
||||
? "text-cyan-400 bg-cyan-500/15"
|
||||
@@ -229,15 +256,8 @@ export function BentoGrid({
|
||||
>
|
||||
<AppWindow className="size-3" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onLaunchTile(tile, "external")}
|
||||
title="Ouvrir dans un nouvel onglet navigateur"
|
||||
className="rounded p-1 text-zinc-400 hover:text-white"
|
||||
>
|
||||
<ExternalLink className="size-3" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -248,7 +268,7 @@ export function BentoGrid({
|
||||
<h3 className="text-base font-semibold tracking-tight text-zinc-100 group-hover:text-white truncate">
|
||||
{tile.title}
|
||||
</h3>
|
||||
<span className="font-mono text-[10px] text-zinc-500 truncate max-w-[130px] shrink-0">
|
||||
<span className="font-mono text-[10px] text-zinc-500 truncate max-w-[175px] shrink-0">
|
||||
{formatHostname(tile.url)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -32,6 +32,7 @@ export function DashboardShell({ initialData }: DashboardShellProps) {
|
||||
>({});
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [isEditMode, setIsEditMode] = useState(false);
|
||||
const [geminiTriggerCount, setGeminiTriggerCount] = useState(0);
|
||||
|
||||
// OS Window Manager state ("bento" or window.id)
|
||||
const [openWindows, setOpenWindows] = useState<OpenWindowTab[]>([]);
|
||||
@@ -122,7 +123,13 @@ export function DashboardShell({ initialData }: DashboardShellProps) {
|
||||
tile: ShortcutTile,
|
||||
forceMode?: "workspace" | "popup" | "external"
|
||||
) => {
|
||||
const mode = forceMode || tile.openBehavior || "workspace";
|
||||
if (tile.url === "#gemini") {
|
||||
setActiveViewId("bento");
|
||||
setGeminiTriggerCount((c) => c + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
const mode = forceMode || tile.openBehavior || "external";
|
||||
|
||||
if (mode === "external") {
|
||||
window.open(tile.url, "_blank", "noopener,noreferrer");
|
||||
@@ -134,7 +141,7 @@ export function DashboardShell({ initialData }: DashboardShellProps) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Default: "workspace" -> Open or focus an in-OS tab
|
||||
// "workspace" -> Open or focus an in-OS tab
|
||||
const existing = openWindows.find((w) => w.tileId === tile.id);
|
||||
if (existing) {
|
||||
setActiveViewId(existing.id);
|
||||
@@ -398,6 +405,7 @@ export function DashboardShell({ initialData }: DashboardShellProps) {
|
||||
searchQuery={searchQuery}
|
||||
onSearchChange={setSearchQuery}
|
||||
onOpenCustomUrl={handleOpenCustomUrl}
|
||||
geminiTriggerCount={geminiTriggerCount}
|
||||
/>
|
||||
|
||||
<main className="flex-1 overflow-y-auto px-4 py-5 pb-24 sm:px-6 md:pb-8">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
@@ -18,6 +18,7 @@ interface HeaderOmniboxProps {
|
||||
searchQuery: string;
|
||||
onSearchChange: (q: string) => void;
|
||||
onOpenCustomUrl: (url: string, title?: string) => void;
|
||||
geminiTriggerCount?: number;
|
||||
}
|
||||
|
||||
export function HeaderOmnibox({
|
||||
@@ -26,12 +27,23 @@ export function HeaderOmnibox({
|
||||
searchQuery,
|
||||
onSearchChange,
|
||||
onOpenCustomUrl,
|
||||
geminiTriggerCount = 0,
|
||||
}: HeaderOmniboxProps) {
|
||||
const [mode, setMode] = useState<"search" | "gemini" | "url">("search");
|
||||
const [geminiPrompt, setGeminiPrompt] = useState("");
|
||||
const [geminiLoading, setGeminiLoading] = useState(false);
|
||||
const [geminiAnswer, setGeminiAnswer] = useState<string | null>(null);
|
||||
const [customUrlInput, setCustomUrlInput] = useState("");
|
||||
const geminiInputRef = useRef<HTMLInputElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (geminiTriggerCount > 0) {
|
||||
setMode("gemini");
|
||||
setTimeout(() => {
|
||||
geminiInputRef.current?.focus();
|
||||
}, 50);
|
||||
}
|
||||
}, [geminiTriggerCount]);
|
||||
|
||||
const handleGeminiSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
@@ -65,7 +77,6 @@ export function HeaderOmnibox({
|
||||
if (raw.includes(".") && !raw.includes(" ")) {
|
||||
finalUrl = `https://${raw}`;
|
||||
} else {
|
||||
// DuckDuckGo / Wikipedia embed-friendly search or direct URL
|
||||
finalUrl = `https://fr.wikipedia.org/w/index.php?search=${encodeURIComponent(raw)}`;
|
||||
}
|
||||
}
|
||||
@@ -122,7 +133,10 @@ export function HeaderOmnibox({
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setMode("gemini")}
|
||||
onClick={() => {
|
||||
setMode("gemini");
|
||||
setTimeout(() => geminiInputRef.current?.focus(), 50);
|
||||
}}
|
||||
className={`flex items-center gap-1 rounded-lg px-2.5 py-1.5 text-xs font-medium transition-all ${
|
||||
mode === "gemini"
|
||||
? "bg-gradient-to-r from-indigo-500 to-blue-500 text-white shadow-xs"
|
||||
@@ -138,7 +152,7 @@ export function HeaderOmnibox({
|
||||
<Input
|
||||
value={searchQuery}
|
||||
onChange={(e) => onSearchChange(e.target.value)}
|
||||
placeholder="Rechercher Nextcloud, Docs, Drive, Gitea..."
|
||||
placeholder="Rechercher un service (*.lafabriquedesgenies.be)..."
|
||||
className="h-8 border-0 bg-transparent text-sm text-zinc-100 placeholder:text-zinc-500 focus-visible:ring-0 dark:bg-transparent"
|
||||
/>
|
||||
)}
|
||||
@@ -151,7 +165,7 @@ export function HeaderOmnibox({
|
||||
<Input
|
||||
value={customUrlInput}
|
||||
onChange={(e) => setCustomUrlInput(e.target.value)}
|
||||
placeholder="Entrer une URL (ex: cloud.lafabriquedesgenies.be) à ouvrir en onglet..."
|
||||
placeholder="Entrer une URL (ex: nc.lafabriquedesgenies.be) à ouvrir..."
|
||||
className="h-8 border-0 bg-transparent text-sm text-zinc-100 placeholder:text-zinc-500 focus-visible:ring-0 dark:bg-transparent"
|
||||
/>
|
||||
<Button
|
||||
@@ -170,9 +184,10 @@ export function HeaderOmnibox({
|
||||
className="flex flex-1 items-center"
|
||||
>
|
||||
<Input
|
||||
ref={geminiInputRef}
|
||||
value={geminiPrompt}
|
||||
onChange={(e) => setGeminiPrompt(e.target.value)}
|
||||
placeholder="Demander à Gemini (résumer un cours, traduire, formule Excel)..."
|
||||
placeholder="Poser une question à Google Gemini, traduire, générer une idée..."
|
||||
className="h-8 border-0 bg-transparent text-sm text-zinc-100 placeholder:text-zinc-500 focus-visible:ring-0 dark:bg-transparent"
|
||||
/>
|
||||
<Button
|
||||
|
||||
@@ -5,12 +5,21 @@ import {
|
||||
Wrench,
|
||||
Sparkles,
|
||||
Container,
|
||||
Shield,
|
||||
ShieldCheck,
|
||||
Archive,
|
||||
Activity,
|
||||
Cloud,
|
||||
Key,
|
||||
KeyRound,
|
||||
Radar,
|
||||
Film,
|
||||
Headphones,
|
||||
Tv,
|
||||
Video,
|
||||
DownloadCloud,
|
||||
Music,
|
||||
HardDriveDownload,
|
||||
Image,
|
||||
RefreshCw,
|
||||
Network,
|
||||
@@ -20,6 +29,8 @@ import {
|
||||
Bookmark,
|
||||
Wallet,
|
||||
FileText,
|
||||
FileCode,
|
||||
Home,
|
||||
GitBranch,
|
||||
Code2,
|
||||
BookOpen,
|
||||
@@ -36,11 +47,13 @@ import {
|
||||
Folder,
|
||||
Database,
|
||||
Layers,
|
||||
LayoutGrid,
|
||||
ExternalLink,
|
||||
HardDrive,
|
||||
Calendar,
|
||||
GraduationCap,
|
||||
AppWindow,
|
||||
Lock,
|
||||
type LucideIcon,
|
||||
} from "lucide-react";
|
||||
|
||||
@@ -51,12 +64,21 @@ export const iconRegistry: Record<string, LucideIcon> = {
|
||||
Wrench,
|
||||
Sparkles,
|
||||
Container,
|
||||
Shield,
|
||||
ShieldCheck,
|
||||
Archive,
|
||||
Activity,
|
||||
Cloud,
|
||||
Key,
|
||||
KeyRound,
|
||||
Radar,
|
||||
Film,
|
||||
Headphones,
|
||||
Tv,
|
||||
Video,
|
||||
DownloadCloud,
|
||||
Music,
|
||||
HardDriveDownload,
|
||||
Image,
|
||||
RefreshCw,
|
||||
Network,
|
||||
@@ -66,6 +88,8 @@ export const iconRegistry: Record<string, LucideIcon> = {
|
||||
Bookmark,
|
||||
Wallet,
|
||||
FileText,
|
||||
FileCode,
|
||||
Home,
|
||||
GitBranch,
|
||||
Code2,
|
||||
BookOpen,
|
||||
@@ -82,11 +106,13 @@ export const iconRegistry: Record<string, LucideIcon> = {
|
||||
Folder,
|
||||
Database,
|
||||
Layers,
|
||||
LayoutGrid,
|
||||
ExternalLink,
|
||||
HardDrive,
|
||||
Calendar,
|
||||
GraduationCap,
|
||||
AppWindow,
|
||||
Lock,
|
||||
};
|
||||
|
||||
export const availableIconNames = Object.keys(iconRegistry);
|
||||
|
||||
@@ -53,7 +53,7 @@ export function TileEditorModal({
|
||||
initialTile?.accentColor || "indigo"
|
||||
);
|
||||
const [openBehavior, setOpenBehavior] = useState<OpenBehavior>(
|
||||
initialTile?.openBehavior || "workspace"
|
||||
initialTile?.openBehavior || "external"
|
||||
);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
@@ -116,15 +116,16 @@ export function TileEditorModal({
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs font-medium text-zinc-300">
|
||||
Adresse URL complète
|
||||
<label className="text-xs font-semibold text-amber-300">
|
||||
Adresse URL complète (Sous-domaine HTTPS)
|
||||
</label>
|
||||
<Input
|
||||
value={url}
|
||||
onChange={(e) => setUrl(e.target.value)}
|
||||
placeholder="https://cloud.lafabriquedesgenies.be"
|
||||
placeholder="https://service.lafabriquedesgenies.be"
|
||||
required
|
||||
className="border-white/10 bg-zinc-900 font-mono text-xs text-zinc-100"
|
||||
autoFocus={Boolean(initialTile)}
|
||||
className="border-amber-500/40 bg-zinc-900 font-mono text-xs text-zinc-100 focus-visible:ring-amber-500/30"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
+331
-260
@@ -1,295 +1,366 @@
|
||||
import { DashboardData } from "@/types/dashboard";
|
||||
|
||||
export const initialDashboardData: DashboardData = {
|
||||
version: "2.0.0",
|
||||
version: "3.0.0",
|
||||
dockTileIds: [
|
||||
"nextcloud-files",
|
||||
"nextcloud-office",
|
||||
"google-docs",
|
||||
"google-drive",
|
||||
"gitea-server",
|
||||
"nextcloud",
|
||||
"dockge",
|
||||
"gitea",
|
||||
"jellyfin",
|
||||
"open-webui",
|
||||
"vaultwarden",
|
||||
],
|
||||
quickNote:
|
||||
"Bienvenue sur Home OS. Utilisez F11 sur CachyOS (Chromium) ou ajoutez l'application à l'écran d'accueil sur votre Galaxy S20 FE.",
|
||||
"Bienvenue sur Home OS (*.lafabriquedesgenies.be). Cliquez sur « Éditer » pour ajuster n'importe quelle URL ou sous-domaine à la volée.",
|
||||
categories: [
|
||||
{
|
||||
id: "work",
|
||||
name: "Bureautique & École",
|
||||
subtitle: "Nextcloud Office, Google Docs, Drive & Cours",
|
||||
icon: "Briefcase",
|
||||
tabs: [
|
||||
{
|
||||
id: "cloud-office",
|
||||
label: "Documents & Suites",
|
||||
tiles: [
|
||||
{
|
||||
id: "nextcloud-files",
|
||||
title: "Nextcloud Hub",
|
||||
description: "Tous mes fichiers, dossiers personnels et synchronisation",
|
||||
url: "https://cloud.lafabriquedesgenies.be",
|
||||
icon: "Cloud",
|
||||
size: "2x1",
|
||||
badge: "Fichiers",
|
||||
accentColor: "sky",
|
||||
openBehavior: "workspace",
|
||||
},
|
||||
{
|
||||
id: "nextcloud-office",
|
||||
title: "Nextcloud Office",
|
||||
description: "Traitement de texte (Word), Tableur (Excel) & Présentations",
|
||||
url: "https://cloud.lafabriquedesgenies.be/apps/richdocuments",
|
||||
icon: "FileSpreadsheet",
|
||||
size: "2x1",
|
||||
badge: "Word / Excel",
|
||||
accentColor: "emerald",
|
||||
openBehavior: "workspace",
|
||||
},
|
||||
{
|
||||
id: "google-docs",
|
||||
title: "Google Docs",
|
||||
description: "Travaux d'école, rapports et rédaction collaborative",
|
||||
url: "https://docs.google.com",
|
||||
icon: "FileText",
|
||||
size: "2x1",
|
||||
badge: "École • Docs",
|
||||
accentColor: "blue",
|
||||
openBehavior: "popup",
|
||||
},
|
||||
{
|
||||
id: "google-drive",
|
||||
title: "Google Drive",
|
||||
description: "Stockage scolaire, cours partagés et Google Sheets",
|
||||
url: "https://drive.google.com",
|
||||
icon: "HardDrive",
|
||||
size: "1x1",
|
||||
badge: "École • Drive",
|
||||
accentColor: "amber",
|
||||
openBehavior: "popup",
|
||||
},
|
||||
{
|
||||
id: "nextcloud-notes",
|
||||
title: "Notes & Aide-mémoire",
|
||||
description: "Prise de notes rapide en Markdown sur Nextcloud",
|
||||
url: "https://cloud.lafabriquedesgenies.be/apps/notes",
|
||||
icon: "NotebookPen",
|
||||
size: "1x1",
|
||||
badge: "Markdown",
|
||||
accentColor: "violet",
|
||||
openBehavior: "workspace",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "dev-git",
|
||||
label: "Code & Projets",
|
||||
tiles: [
|
||||
{
|
||||
id: "gitea-server",
|
||||
title: "Gitea — La Fabrique",
|
||||
description: "Dépôts Git personnels (klemens/home) et CI",
|
||||
url: "https://git.lafabriquedesgenies.be/klemens/home",
|
||||
icon: "GitBranch",
|
||||
size: "2x1",
|
||||
badge: "Git Serveur",
|
||||
accentColor: "emerald",
|
||||
openBehavior: "workspace",
|
||||
},
|
||||
{
|
||||
id: "github",
|
||||
title: "GitHub",
|
||||
description: "Projets open-source et dépôts externes",
|
||||
url: "https://github.com",
|
||||
icon: "Code2",
|
||||
size: "1x1",
|
||||
badge: "Externe",
|
||||
accentColor: "slate",
|
||||
openBehavior: "popup",
|
||||
},
|
||||
{
|
||||
id: "excalidraw",
|
||||
title: "Excalidraw",
|
||||
description: "Schémas d'architecture, croquis et diagrammes de cours",
|
||||
url: "https://excalidraw.com",
|
||||
icon: "PenTool",
|
||||
size: "1x1",
|
||||
badge: "Tableau blanc",
|
||||
accentColor: "indigo",
|
||||
openBehavior: "workspace",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "server",
|
||||
name: "Mon Serveur",
|
||||
subtitle: "Infrastructure Docker (Core i3 / 8 Go RAM) & Réseau",
|
||||
id: "infrastructure",
|
||||
name: "Infrastructure & Serveur",
|
||||
subtitle: "Administration système, conteneurs Docker, sauvegardes & réseau",
|
||||
icon: "Server",
|
||||
tabs: [
|
||||
{
|
||||
id: "containers",
|
||||
label: "Conteneurs & Infra",
|
||||
id: "infra-main",
|
||||
label: "Services Serveur",
|
||||
tiles: [
|
||||
{
|
||||
id: "dockge",
|
||||
title: "Dockge",
|
||||
description: "Gestionnaire de stacks Docker Compose ultra-léger",
|
||||
url: "http://localhost:5001",
|
||||
icon: "Container",
|
||||
description: "Gestionnaire Docker Compose",
|
||||
url: "https://dockge.lafabriquedesgenies.be",
|
||||
icon: "Terminal",
|
||||
size: "2x1",
|
||||
badge: "Docker",
|
||||
accentColor: "emerald",
|
||||
openBehavior: "workspace",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "nginx-proxy",
|
||||
title: "Nginx Reverse Proxy",
|
||||
description: "Gestion des domaines *.lafabriquedesgenies.be et SSL",
|
||||
url: "http://localhost:81",
|
||||
icon: "ShieldCheck",
|
||||
id: "nginx-proxy-manager",
|
||||
title: "Nginx Proxy Manager",
|
||||
description: "Reverse Proxy & Certificats SSL",
|
||||
url: "https://proxy.lafabriquedesgenies.be",
|
||||
icon: "Shield",
|
||||
size: "1x1",
|
||||
badge: "Proxy SSL",
|
||||
accentColor: "blue",
|
||||
openBehavior: "workspace",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "beszel",
|
||||
title: "Monitoring i3",
|
||||
description: "Charge CPU, mémoire 8 Go et stockage disque",
|
||||
url: "http://localhost:8090",
|
||||
id: "duplicati",
|
||||
title: "Duplicati",
|
||||
description: "Sauvegardes du serveur",
|
||||
url: "https://backup.lafabriquedesgenies.be",
|
||||
icon: "Archive",
|
||||
size: "1x1",
|
||||
badge: "Backup",
|
||||
accentColor: "sky",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "speedtest",
|
||||
title: "Speedtest",
|
||||
description: "Surveillance débit réseau",
|
||||
url: "https://speedtest.lafabriquedesgenies.be",
|
||||
icon: "Activity",
|
||||
size: "1x1",
|
||||
badge: "Système",
|
||||
badge: "Réseau",
|
||||
accentColor: "cyan",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "adminer",
|
||||
title: "Adminer",
|
||||
description: "Gestionnaire bases SQL",
|
||||
url: "https://db.lafabriquedesgenies.be",
|
||||
icon: "Database",
|
||||
size: "1x1",
|
||||
badge: "SQL",
|
||||
accentColor: "amber",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "adguard-home",
|
||||
title: "AdGuard Home",
|
||||
description: "Filtrage DNS & Antipub",
|
||||
url: "https://adguard.lafabriquedesgenies.be",
|
||||
icon: "ShieldCheck",
|
||||
size: "1x1",
|
||||
badge: "DNS",
|
||||
accentColor: "teal",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "watchtower",
|
||||
title: "Watchtower",
|
||||
description: "Mises à jour automatiques",
|
||||
url: "https://dockge.lafabriquedesgenies.be",
|
||||
icon: "RefreshCw",
|
||||
size: "1x1",
|
||||
badge: "Daemon Auto",
|
||||
accentColor: "violet",
|
||||
openBehavior: "workspace",
|
||||
openBehavior: "external",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "private-security",
|
||||
name: "Privé & Sécurité",
|
||||
subtitle: "Cloud personnel, mots de passe, documents, notes & domotique",
|
||||
icon: "ShieldCheck",
|
||||
tabs: [
|
||||
{
|
||||
id: "private-main",
|
||||
label: "Espace Privé",
|
||||
tiles: [
|
||||
{
|
||||
id: "nextcloud",
|
||||
title: "Nextcloud",
|
||||
description: "Fichiers & Drive Cloud",
|
||||
url: "https://nc.lafabriquedesgenies.be",
|
||||
icon: "Cloud",
|
||||
size: "2x1",
|
||||
badge: "Cloud",
|
||||
accentColor: "sky",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "vaultwarden",
|
||||
title: "Vaultwarden",
|
||||
description: "Gestionnaire de mots de passe auto-hébergé",
|
||||
url: "http://localhost:8222",
|
||||
icon: "KeyRound",
|
||||
description: "Gestionnaire de mots de passe",
|
||||
url: "https://vault.lafabriquedesgenies.be",
|
||||
icon: "Key",
|
||||
size: "1x1",
|
||||
badge: "Sécurité",
|
||||
badge: "Coffre-fort",
|
||||
accentColor: "amber",
|
||||
openBehavior: "workspace",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "adguard",
|
||||
title: "AdGuard DNS",
|
||||
description: "Filtrage publicitaire et résolution DNS locale",
|
||||
url: "http://localhost:3000",
|
||||
icon: "Radar",
|
||||
id: "paperless-ngx",
|
||||
title: "Paperless-ngx",
|
||||
description: "GED & Archivage intelligent",
|
||||
url: "https://paperless.lafabriquedesgenies.be",
|
||||
icon: "FileText",
|
||||
size: "1x1",
|
||||
badge: "DNS",
|
||||
accentColor: "teal",
|
||||
openBehavior: "workspace",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
badge: "GED",
|
||||
accentColor: "emerald",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "private",
|
||||
name: "Privé",
|
||||
subtitle: "Quotidien, Mails, Agenda & Médias",
|
||||
icon: "User",
|
||||
tabs: [
|
||||
{
|
||||
id: "daily",
|
||||
label: "Quotidien",
|
||||
tiles: [
|
||||
{
|
||||
id: "nextcloud-calendar",
|
||||
title: "Agenda & Tâches",
|
||||
description: "Planning des cours, échéances et rendez-vous",
|
||||
url: "https://cloud.lafabriquedesgenies.be/apps/calendar",
|
||||
icon: "Calendar",
|
||||
size: "2x1",
|
||||
badge: "Planning",
|
||||
accentColor: "sky",
|
||||
openBehavior: "workspace",
|
||||
},
|
||||
{
|
||||
id: "webmail",
|
||||
title: "Messagerie",
|
||||
description: "Boîte mail personnelle et scolaire",
|
||||
url: "https://mail.proton.me",
|
||||
icon: "Mail",
|
||||
id: "wikijs",
|
||||
title: "Wiki.js",
|
||||
description: "Base de connaissances & notes",
|
||||
url: "https://wiki.lafabriquedesgenies.be",
|
||||
icon: "BookOpen",
|
||||
size: "1x1",
|
||||
badge: "Emails",
|
||||
accentColor: "violet",
|
||||
openBehavior: "popup",
|
||||
},
|
||||
{
|
||||
id: "freshrss",
|
||||
title: "Lecteur RSS",
|
||||
description: "Veille technologique et actualités sans pub",
|
||||
url: "http://localhost:8085",
|
||||
icon: "Rss",
|
||||
size: "1x1",
|
||||
badge: "Flux",
|
||||
accentColor: "amber",
|
||||
openBehavior: "workspace",
|
||||
},
|
||||
{
|
||||
id: "jellyfin",
|
||||
title: "Médiathèque",
|
||||
description: "Films, séries et musique en streaming local",
|
||||
url: "http://localhost:8096",
|
||||
icon: "Film",
|
||||
size: "2x1",
|
||||
badge: "Média",
|
||||
accentColor: "purple",
|
||||
openBehavior: "workspace",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "tools",
|
||||
name: "Outils",
|
||||
subtitle: "Utilitaires rapides PDF, Réseau & Partage S20 FE <-> CachyOS",
|
||||
icon: "Wrench",
|
||||
tabs: [
|
||||
{
|
||||
id: "utilities",
|
||||
label: "Boîte à outils",
|
||||
tiles: [
|
||||
{
|
||||
id: "pairdrop",
|
||||
title: "PairDrop (CachyOS ↔ S20 FE)",
|
||||
description: "Transfert instantané de fichiers entre le PC et le Galaxy S20 FE",
|
||||
url: "https://pairdrop.net",
|
||||
icon: "Share2",
|
||||
size: "2x1",
|
||||
badge: "AirDrop Local",
|
||||
accentColor: "cyan",
|
||||
openBehavior: "workspace",
|
||||
badge: "Wiki",
|
||||
accentColor: "indigo",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "stirling-pdf",
|
||||
title: "Stirling PDF",
|
||||
description: "Convertir, fusionner et signer des PDF pour l'école",
|
||||
url: "http://localhost:8083",
|
||||
icon: "FileText",
|
||||
description: "Boîte à outils PDF complète",
|
||||
url: "https://pdf.lafabriquedesgenies.be",
|
||||
icon: "FileCode",
|
||||
size: "1x1",
|
||||
badge: "PDF",
|
||||
accentColor: "rose",
|
||||
openBehavior: "workspace",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "it-tools",
|
||||
title: "IT-Tools",
|
||||
description: "Convertisseurs, générateurs de tokens, JSON et réseau",
|
||||
url: "https://it-tools.tech",
|
||||
icon: "Cpu",
|
||||
id: "home-assistant",
|
||||
title: "Home Assistant",
|
||||
description: "Domotique de la maison",
|
||||
url: "https://hass.lafabriquedesgenies.be",
|
||||
icon: "Home",
|
||||
size: "2x1",
|
||||
badge: "Domotique",
|
||||
accentColor: "cyan",
|
||||
openBehavior: "external",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "multimedia",
|
||||
name: "Multimédia & Médias",
|
||||
subtitle: "Streaming vidéo, livres audio, musique & téléchargements",
|
||||
icon: "Film",
|
||||
tabs: [
|
||||
{
|
||||
id: "media-main",
|
||||
label: "Streaming & Téléchargements",
|
||||
tiles: [
|
||||
{
|
||||
id: "jellyfin",
|
||||
title: "Jellyfin",
|
||||
description: "Streaming Films & Séries",
|
||||
url: "https://jellyfin.lafabriquedesgenies.be",
|
||||
icon: "Film",
|
||||
size: "2x1",
|
||||
badge: "Streaming",
|
||||
accentColor: "purple",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "audiobookshelf",
|
||||
title: "Audiobookshelf",
|
||||
description: "Livres audio & Podcasts",
|
||||
url: "https://audiobookshelf.lafabriquedesgenies.be",
|
||||
icon: "Headphones",
|
||||
size: "1x1",
|
||||
badge: "DevTools",
|
||||
badge: "Audio",
|
||||
accentColor: "amber",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "sonarr",
|
||||
title: "Sonarr",
|
||||
description: "Suivi & gestion des séries",
|
||||
url: "https://sonarr.lafabriquedesgenies.be",
|
||||
icon: "Tv",
|
||||
size: "1x1",
|
||||
badge: "Séries",
|
||||
accentColor: "sky",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "radarr",
|
||||
title: "Radarr",
|
||||
description: "Suivi & gestion des films",
|
||||
url: "https://radarr.lafabriquedesgenies.be",
|
||||
icon: "Video",
|
||||
size: "1x1",
|
||||
badge: "Films",
|
||||
accentColor: "amber",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "qbittorrent",
|
||||
title: "qBittorrent",
|
||||
description: "Téléchargements VPN (Gluetun)",
|
||||
url: "https://torrent.lafabriquedesgenies.be",
|
||||
icon: "DownloadCloud",
|
||||
size: "1x1",
|
||||
badge: "VPN Gluetun",
|
||||
accentColor: "blue",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "deemix",
|
||||
title: "Deemix",
|
||||
description: "Téléchargement Musique",
|
||||
url: "https://deemix.lafabriquedesgenies.be",
|
||||
icon: "Music",
|
||||
size: "1x1",
|
||||
badge: "Musique",
|
||||
accentColor: "pink",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "sabnzbd",
|
||||
title: "SABnzbd",
|
||||
description: "Client Usenet",
|
||||
url: "https://sabnzbd.lafabriquedesgenies.be",
|
||||
icon: "HardDriveDownload",
|
||||
size: "1x1",
|
||||
badge: "Usenet",
|
||||
accentColor: "emerald",
|
||||
openBehavior: "external",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "projects-work",
|
||||
name: "Projets & Travail",
|
||||
subtitle: "Forge Git, applications La Fabrique des Génies & outils métiers",
|
||||
icon: "Briefcase",
|
||||
tabs: [
|
||||
{
|
||||
id: "work-main",
|
||||
label: "Applications & Projets",
|
||||
tiles: [
|
||||
{
|
||||
id: "gitea",
|
||||
title: "Gitea",
|
||||
description: "Dépôts de code Git",
|
||||
url: "https://git.lafabriquedesgenies.be",
|
||||
icon: "GitBranch",
|
||||
size: "2x1",
|
||||
badge: "Git",
|
||||
accentColor: "emerald",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "wordpress-lafabrique",
|
||||
title: "WordPress La Fabrique",
|
||||
description: "Site officiel La Fabrique",
|
||||
url: "https://lafabriquedesgenies.be",
|
||||
icon: "Globe",
|
||||
size: "1x1",
|
||||
badge: "Site Web",
|
||||
accentColor: "blue",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "teacher-app",
|
||||
title: "Teacher App",
|
||||
description: "Plateforme pédagogique",
|
||||
url: "https://teacher.lafabriquedesgenies.be",
|
||||
icon: "GraduationCap",
|
||||
size: "1x1",
|
||||
badge: "Pédagogie",
|
||||
accentColor: "indigo",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "creaprof",
|
||||
title: "CreaProf",
|
||||
description: "Outil création enseignant",
|
||||
url: "https://creaprof.lafabriquedesgenies.be",
|
||||
icon: "PenTool",
|
||||
size: "1x1",
|
||||
badge: "Création",
|
||||
accentColor: "violet",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "ubicraft",
|
||||
title: "Ubicraft",
|
||||
description: "Application métier",
|
||||
url: "https://ubicraft.lafabriquedesgenies.be",
|
||||
icon: "LayoutGrid",
|
||||
size: "1x1",
|
||||
badge: "Métier",
|
||||
accentColor: "cyan",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "lma-v2",
|
||||
title: "LMA V2",
|
||||
description: "Plateforme Last Minute Activities",
|
||||
url: "https://lma.lafabriquedesgenies.be",
|
||||
icon: "Briefcase",
|
||||
size: "1x1",
|
||||
badge: "LMA",
|
||||
accentColor: "amber",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "coo-app",
|
||||
title: "Coo App",
|
||||
description: "Application de gestion",
|
||||
url: "https://coo.lafabriquedesgenies.be",
|
||||
icon: "Layers",
|
||||
size: "1x1",
|
||||
badge: "Gestion",
|
||||
accentColor: "teal",
|
||||
openBehavior: "workspace",
|
||||
openBehavior: "external",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -297,35 +368,35 @@ export const initialDashboardData: DashboardData = {
|
||||
},
|
||||
{
|
||||
id: "ai",
|
||||
name: "IA",
|
||||
subtitle: "Assistant Gemini intégré & Outils de recherche",
|
||||
name: "Intelligence Artificielle",
|
||||
subtitle: "Modèles LLM auto-hébergés & Assistant Google Gemini intégré",
|
||||
icon: "Sparkles",
|
||||
tabs: [
|
||||
{
|
||||
id: "assistants",
|
||||
label: "Studios IA",
|
||||
id: "ai-main",
|
||||
label: "Assistants IA",
|
||||
tiles: [
|
||||
{
|
||||
id: "aistudio",
|
||||
title: "Google AI Studio",
|
||||
description: "Tests avancés Gemini et gestion de la clé API",
|
||||
url: "https://aistudio.google.com",
|
||||
icon: "Sparkles",
|
||||
id: "open-webui",
|
||||
title: "Open WebUI",
|
||||
description: "Interface modèles LLM",
|
||||
url: "https://ai.lafabriquedesgenies.be",
|
||||
icon: "Bot",
|
||||
size: "2x1",
|
||||
badge: "Gemini",
|
||||
accentColor: "blue",
|
||||
openBehavior: "popup",
|
||||
badge: "LLM",
|
||||
accentColor: "emerald",
|
||||
openBehavior: "external",
|
||||
},
|
||||
{
|
||||
id: "wikipedia",
|
||||
title: "Wikipédia FR",
|
||||
description: "Encyclopédie libre consultable directement dans un onglet Home",
|
||||
url: "https://fr.wikipedia.org",
|
||||
icon: "BookOpen",
|
||||
id: "google-gemini",
|
||||
title: "Google Gemini",
|
||||
description: "Assistant IA intégré",
|
||||
url: "#gemini",
|
||||
icon: "Sparkles",
|
||||
size: "2x1",
|
||||
badge: "Encyclopédie",
|
||||
accentColor: "slate",
|
||||
openBehavior: "workspace",
|
||||
badge: "Omnibox IA",
|
||||
accentColor: "blue",
|
||||
openBehavior: "external",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user