Compare commits

..

3 Commits

9 changed files with 159 additions and 99 deletions

View File

@@ -14,7 +14,10 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
const pathname = usePathname(); const pathname = usePathname();
const getPageTitle = (path: string) => { const getPageTitle = (path: string) => {
if (path === "/") return "Overview"; const pathSegments = path.split("/").filter(Boolean);
if (pathSegments.length <= 1) return "Overview";
const purePath = `/${pathSegments.slice(1).join("/")}`;
const titles: Record<string, string> = { const titles: Record<string, string> = {
"/users": "Users", "/users": "Users",
@@ -24,7 +27,8 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
"/events": "Worship & Events", "/events": "Worship & Events",
}; };
return titles[path] || "Dashboard"; return titles[purePath] || "Dashboard";
}; };
return ( return (

View File

@@ -13,11 +13,11 @@ export interface BibleVerse {
export const bibleVerses: BibleVerse[] = [ export const bibleVerses: BibleVerse[] = [
{ {
reference: "Epheser 2:19", reference: "Epheser 2:19-22",
content: { content: {
en: "So then you are no longer strangers and aliens...", en: "So then you are no longer strangers and aliens, but you are fellow citizens with the saints and members of the household of God, built on the foundation of the apostles and prophets, Christ Jesus himself being the cornerstone, in whom the whole structure, being joined together, grows into a holy temple in the Lord. In him you also are being built together into a dwelling place for God by the Spirit.",
de: "So seid ihr nun nicht mehr Gäste und Fremdlinge...", de: "So seid ihr nun nicht mehr Gäste und Fremdlinge, sondern Mitbürger der Heiligen und Gottes Hausgenossen, erbaut auf den Grund der Apostel und Propheten, da Jesus Christus der Eckstein ist, auf welchem der ganze Bau ineinandergefügt wächst zu einem heiligen Tempel in dem Herrn. Durch ihn werdet auch ihr mit erbaut zu einer Wohnung Gottes im Geist.",
ru: "Итак вы уже не чужие и не пришельцы..." ru: "Итак, вы уже не чужие и не пришельцы, но сограждане святым и свои Богу, быв утверждены на основании Апостолов и пророков, имея Самого Иисуса Христа краеугольным камнем, на котором всё здание, слагаясь стройно, возрастает в святой храм в Господе, на котором и вы устрояетесь в жилище Божие Духом."
} }
}, },
{ {

View File

@@ -26,6 +26,8 @@ import { useParams } from "next/navigation";
import Link from "next/link"; import Link from "next/link";
import React from "react"; import React from "react";
import { bibleVerses, localizedContent } from "./lib/dailyVerseData"; import { bibleVerses, localizedContent } from "./lib/dailyVerseData";
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
import Image from "next/image";
const Dashboard: React.FC = () => { const Dashboard: React.FC = () => {
// 1. Get a unique number for the current day // 1. Get a unique number for the current day
@@ -39,7 +41,6 @@ const Dashboard: React.FC = () => {
const todayVerse = bibleVerses[verseIndex]; const todayVerse = bibleVerses[verseIndex];
const params = useParams(); const params = useParams();
const lng = params.locale as keyof localizedContent || "en"; // Default to English if no locale is provided const lng = params.locale as keyof localizedContent || "en"; // Default to English if no locale is provided
const t = useTranslations("dashboard"); const t = useTranslations("dashboard");
const categories: ModuleCategory[] = [ const categories: ModuleCategory[] = [
@@ -184,24 +185,23 @@ const Dashboard: React.FC = () => {
return ( return (
<div className="mx-auto max-w-7xl space-y-8"> <div className="mx-auto max-w-7xl space-y-8">
{/* Welcome Section */} {/* Welcome Section */}
<div className="flex flex-col justify-between gap-4 md:flex-row md:items-center"> <div data-cmp="ModuleCard" className="group bg-card border border-border rounded-xl p-6 h-full overflow-hidden">
<div> <div className="animate-in items-baseline fade-in slide-in-from-bottom-4 duration-700 flex flex-col sm:flex-row grow pr-6 gap-2">
<h1 className="text-foreground text-3xl font-bold tracking-tight"> <span className="text-2xl md:text-3xl text-nowrap font-semibold leading-none">{t("greeting_name", { user: "Alexander" })}</span>
{t("title")} <span className="text-xl font-semibold text-nowrap leading-none"> {t("greeting")}</span>
</h1>
<p className="text-muted-foreground mt-1">{t("greeting", { user: "David", church: "Rastatt" })}</p>
<p className="text-muted-foreground mt-1">{t("verse_intro")}</p>
<p className="text-muted-foreground mt-1">
{todayVerse.content[lng]}"
</p>
<span className="text-sm text-muted-foreground">({todayVerse.reference})</span>
</div> </div>
<div className="flex space-x-3"> <div className="flex-col mt-4">
<Badge variant="secondary" className="px-2.5 py-0.5 text-sm"> <p>
v2.4.0 Live <span className="font-semibold">{t("verse_intro")}</span> <br />
<i className="italic text-foreground">"{todayVerse.content[lng]}"</i>
</p>
<div className="flex justify-end mt-3">
<Badge variant="outline" className="rounded-sm self-start">
{todayVerse.reference}
</Badge> </Badge>
</div> </div>
</div> </div>
</div>
{/* Quick Stats */} {/* Quick Stats */}
<div className="grid grid-cols-1 gap-6 md:grid-cols-3"> <div className="grid grid-cols-1 gap-6 md:grid-cols-3">

View File

@@ -44,72 +44,114 @@
} }
:root { :root {
--radius: 0.625rem; --radius: 0.125rem;
--background: oklch(1 0 0); /* ---------- Base background (warm light) ---------- */
--foreground: oklch(0.129 0.042 264.695); --background: oklch(0.97 0.01 95);
--card: oklch(1 0 0); --foreground: oklch(0.22 0.02 30);
--card-foreground: oklch(0.129 0.042 264.695);
--popover: oklch(1 0 0); /* ---------- Surfaces ---------- */
--popover-foreground: oklch(0.129 0.042 264.695); --card: oklch(0.99 0.005 95);
--primary: oklch(0.208 0.042 265.755); --card-foreground: oklch(0.22 0.02 30);
--primary-foreground: oklch(0.984 0.003 247.858);
--secondary: oklch(0.968 0.007 247.896); --popover: oklch(1 0.004 95);
--secondary-foreground: oklch(0.208 0.042 265.755); --popover-foreground: oklch(0.22 0.02 30);
--muted: oklch(0.968 0.007 247.896);
--muted-foreground: oklch(0.554 0.046 257.417); /* ---------- Ubuntu orange primary ---------- */
--accent: oklch(0.968 0.007 247.896); --primary: oklch(0.62 0.2 45);
--accent-foreground: oklch(0.208 0.042 265.755); --primary-foreground: oklch(0.99 0.005 95);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.929 0.013 255.508); /* ---------- Secondary / muted warm grays ---------- */
--input: oklch(0.929 0.013 255.508); --secondary: oklch(0.92 0.01 90);
--ring: oklch(0.704 0.04 256.788); --secondary-foreground: oklch(0.3 0.02 35);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704); --muted: oklch(0.94 0.008 90);
--chart-3: oklch(0.398 0.07 227.392); --muted-foreground: oklch(0.45 0.015 35);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08); --accent: oklch(0.9 0.015 85);
--sidebar: oklch(0.984 0.003 247.858); --accent-foreground: oklch(0.3 0.02 35);
--sidebar-foreground: oklch(0.129 0.042 264.695);
--sidebar-primary: oklch(0.208 0.042 265.755); /* ---------- Destructive ---------- */
--sidebar-primary-foreground: oklch(0.984 0.003 247.858); --destructive: oklch(0.58 0.23 25);
--sidebar-accent: oklch(0.968 0.007 247.896);
--sidebar-accent-foreground: oklch(0.208 0.042 265.755); /* ---------- Borders / inputs ---------- */
--sidebar-border: oklch(0.929 0.013 255.508); --border: oklch(0.85 0.01 90);
--sidebar-ring: oklch(0.704 0.04 256.788); --input: oklch(0.88 0.01 90);
--ring: oklch(0.62 0.2 45 / 0.5);
/* ---------- Charts ---------- */
--chart-1: oklch(0.62 0.2 45); /* orange */
--chart-2: oklch(0.55 0.16 150); /* green */
--chart-3: oklch(0.7 0.17 85); /* yellow */
--chart-4: oklch(0.6 0.18 300); /* purple */
--chart-5: oklch(0.6 0.2 20); /* red */
/* ---------- Sidebar ---------- */
--sidebar: oklch(0.95 0.01 90);
--sidebar-foreground: oklch(0.28 0.02 30);
--sidebar-primary: oklch(0.62 0.2 45);
--sidebar-primary-foreground: oklch(0.99 0.005 95);
--sidebar-accent: oklch(0.9 0.015 85);
--sidebar-accent-foreground: oklch(0.3 0.02 35);
--sidebar-border: oklch(0.85 0.01 90);
--sidebar-ring: oklch(0.62 0.2 45 / 0.5);
} }
.dark { .dark {
--background: oklch(0.129 0.042 264.695); /* ---------- Base background (warm charcoal) ---------- */
--foreground: oklch(0.984 0.003 247.858); --background: oklch(0.11 0.015 30);
--card: oklch(0.208 0.042 265.755); --foreground: oklch(0.97 0.01 95);
--card-foreground: oklch(0.984 0.003 247.858);
--popover: oklch(0.208 0.042 265.755); /* ---------- Surfaces ---------- */
--popover-foreground: oklch(0.984 0.003 247.858); --card: oklch(0.16 0.018 32);
--primary: oklch(0.929 0.013 255.508); --card-foreground: oklch(0.97 0.01 95);
--primary-foreground: oklch(0.208 0.042 265.755);
--secondary: oklch(0.279 0.041 260.031); --popover: oklch(0.18 0.02 32);
--secondary-foreground: oklch(0.984 0.003 247.858); --popover-foreground: oklch(0.97 0.01 95);
--muted: oklch(0.279 0.041 260.031);
--muted-foreground: oklch(0.704 0.04 256.788); /* ---------- Ubuntu orange primary ---------- */
--accent: oklch(0.279 0.041 260.031); --primary: oklch(0.68 0.19 45);
--accent-foreground: oklch(0.984 0.003 247.858); --primary-foreground: oklch(0.98 0.01 95);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%); /* ---------- Secondary / muted warm grays ---------- */
--input: oklch(1 0 0 / 15%); --secondary: oklch(0.22 0.02 30);
--ring: oklch(0.551 0.027 264.364); --secondary-foreground: oklch(0.92 0.015 95);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48); --muted: oklch(0.22 0.02 30);
--chart-3: oklch(0.769 0.188 70.08); --muted-foreground: oklch(0.68 0.02 90);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439); --accent: oklch(0.26 0.025 35);
--sidebar: oklch(0.208 0.042 265.755); --accent-foreground: oklch(0.95 0.01 95);
--sidebar-foreground: oklch(0.984 0.003 247.858);
--sidebar-primary: oklch(0.488 0.243 264.376); /* ---------- Destructive (Ubuntu red tone) ---------- */
--sidebar-primary-foreground: oklch(0.984 0.003 247.858); --destructive: oklch(0.62 0.22 25);
--sidebar-accent: oklch(0.279 0.041 260.031);
--sidebar-accent-foreground: oklch(0.984 0.003 247.858); /* ---------- Borders / inputs ---------- */
--sidebar-border: oklch(1 0 0 / 10%); --border: oklch(0.3 0.015 35 / 0.6);
--sidebar-ring: oklch(0.551 0.027 264.364); --input: oklch(0.3 0.015 35 / 0.8);
--ring: oklch(0.68 0.19 45 / 0.6);
/* ---------- Charts ---------- */
--chart-1: oklch(0.68 0.19 45); /* orange */
--chart-2: oklch(0.7 0.15 150); /* green */
--chart-3: oklch(0.78 0.16 85); /* yellow */
--chart-4: oklch(0.66 0.18 300); /* purple */
--chart-5: oklch(0.7 0.18 20); /* red */
/* ---------- Sidebar (slightly darker & warmer) ---------- */
--sidebar: oklch(0.14 0.018 30);
--sidebar-foreground: oklch(0.95 0.01 95);
--sidebar-primary: oklch(0.68 0.19 45);
--sidebar-primary-foreground: oklch(0.98 0.01 95);
--sidebar-accent: oklch(0.24 0.02 32);
--sidebar-accent-foreground: oklch(0.95 0.01 95);
--sidebar-border: oklch(0.3 0.015 35 / 0.5);
--sidebar-ring: oklch(0.68 0.19 45 / 0.6);
} }
/* === CUSTOM COLOR THEME === */ /* === CUSTOM COLOR THEME === */

View File

@@ -7,6 +7,7 @@ interface HeaderProps {
} }
const Header: React.FC<HeaderProps> = ({ onMenuClick, pageTitle }) => { const Header: React.FC<HeaderProps> = ({ onMenuClick, pageTitle }) => {
const [hasError, setHasError] = React.useState(false);
return ( return (
<header <header
data-cmp="Header" data-cmp="Header"
@@ -55,9 +56,19 @@ const Header: React.FC<HeaderProps> = ({ onMenuClick, pageTitle }) => {
<p className="text-foreground text-sm font-medium">Community Admin</p> <p className="text-foreground text-sm font-medium">Community Admin</p>
<p className="text-muted-foreground text-xs">Super Administrator</p> <p className="text-muted-foreground text-xs">Super Administrator</p>
</div> </div>
<div className="bg-primary/10 border-primary/20 flex h-9 w-9 shrink-0 items-center justify-center rounded-full border"> {hasError ? (
<User className="text-primary h-5 w-5" /> <div className="w-10 h-10 rounded-full border border-border bg-muted flex items-center justify-center">
<User className="w-6 h-6 text-muted-foreground" />
</div> </div>
) : (
<img
src="/images/IMG_84271.jpg"
alt="Profile"
className="w-10 h-10 rounded-full object-cover border border-border"
/* If image fails to load, set hasError to true */
onError={() => setHasError(true)}
/>
)}
</div> </div>
</div> </div>
</header> </header>

View File

@@ -11,8 +11,9 @@
"dashboard": { "dashboard": {
"title": "Community-Dashboard", "title": "Community-Dashboard",
"welcome": "Willkommen im Admin-Bereich. Verwalten Sie Ihre Community-Ressourcen sicher.", "welcome": "Willkommen im Admin-Bereich. Verwalten Sie Ihre Community-Ressourcen sicher.",
"greeting": "Lieber {user}, deine örtliche Gemeinde {church} begrüßt dich!", "greeting_name": "Lieber Bruder {user},",
"verse_intro": "Lass dich durch den folgenden Vers ermutigen:" "greeting": "Friede sei mit Dir!",
"verse_intro": "Zur Ermutigung:"
}, },
"users": { "users": {
"title": "Benutzer", "title": "Benutzer",

View File

@@ -11,8 +11,9 @@
"dashboard": { "dashboard": {
"title": "Community Dashboard", "title": "Community Dashboard",
"welcome": "Welcome to the admin area. Manage your community resources safely.", "welcome": "Welcome to the admin area. Manage your community resources safely.",
"greeting": "Dear {user}, your local community {church} welcomes you!", "greeting_name": "Dear brother {user},",
"verse_intro": "Let the following verse encourage you:" "greeting": "peace be with you!",
"verse_intro": "For encouragement:"
}, },
"users": { "users": {
"title": "Users", "title": "Users",

View File

@@ -11,8 +11,9 @@
"dashboard": { "dashboard": {
"title": "Community Dashboard", "title": "Community Dashboard",
"welcome": "Добро пожаловать в административный раздел. Безопасно управляйте ресурсами вашего сообщества.", "welcome": "Добро пожаловать в административный раздел. Безопасно управляйте ресурсами вашего сообщества.",
"greeting": "Дорогой {user}, твоя местная община {church} приветствует тебя!", "greeting_name": "Дорогой брат {user},",
"verse_intro": "Пусть этот стих подбодрит тебя:" "greeting": "мир Тебе!",
"verse_intro": "Для ободрения:"
}, },
"users": { "users": {
"title": "Пользователи", "title": "Пользователи",

BIN
public/images/IMG_84271.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB