diff --git a/bun.lockb b/bun.lockb
index 1ed5e7e..7635343 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/messages/en.json b/messages/en.json
index f9b2767..0977576 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -39,6 +39,7 @@
"storage": "Storage",
"about": "About",
"shiftSchedule": "Shift Schedule",
+ "rules": "Rules",
"changeLocale": "Change language",
"toggleTheme": "Toggle theme",
"light": "Light",
@@ -156,5 +157,10 @@
}
}
}
+ },
+ "rules": {
+ "title": "Rules",
+ "forEveryone": "For everyone",
+ "internal": "Internal rules"
}
}
diff --git a/messages/no.json b/messages/no.json
index 8062933..92607f5 100644
--- a/messages/no.json
+++ b/messages/no.json
@@ -39,6 +39,7 @@
"storage": "Lager",
"about": "Om oss",
"shiftSchedule": "Vaktliste",
+ "rules": "Rules",
"changeLocale": "Bytt språk",
"toggleTheme": "Bytt tema",
"light": "Lys",
@@ -156,5 +157,10 @@
}
}
}
+ },
+ "rules": {
+ "title": "Regler",
+ "forEveryone": "For alle",
+ "internal": "Interne regler"
}
}
diff --git a/src/app/[locale]/(default)/rules/(main)/layout.tsx b/src/app/[locale]/(default)/rules/(main)/layout.tsx
new file mode 100644
index 0000000..a691282
--- /dev/null
+++ b/src/app/[locale]/(default)/rules/(main)/layout.tsx
@@ -0,0 +1,21 @@
+import { getTranslations, setRequestLocale } from 'next-intl/server';
+
+type RulesLayoutProps = {
+ children: React.ReactNode;
+ params: Promise<{ locale: string }>;
+};
+
+export default async function RulesLayout({
+ children,
+ params,
+}: RulesLayoutProps) {
+ const { locale } = await params;
+ setRequestLocale(locale);
+ const t = await getTranslations('rules');
+ return (
+ <>
+
{t('title')}
+ {children}
+ >
+ );
+}
diff --git a/src/app/[locale]/(default)/rules/(main)/loading.tsx b/src/app/[locale]/(default)/rules/(main)/loading.tsx
new file mode 100644
index 0000000..be3cce2
--- /dev/null
+++ b/src/app/[locale]/(default)/rules/(main)/loading.tsx
@@ -0,0 +1,5 @@
+import { RuleCardListSkeleton } from '@/components/rules/RuleCardListSkeleton';
+
+export default function RulesSkeleton() {
+ return ;
+}
diff --git a/src/app/[locale]/(default)/rules/(main)/page.tsx b/src/app/[locale]/(default)/rules/(main)/page.tsx
new file mode 100644
index 0000000..32cbcfe
--- /dev/null
+++ b/src/app/[locale]/(default)/rules/(main)/page.tsx
@@ -0,0 +1,29 @@
+import { RuleCardList } from '@/components/rules/RuleCardList';
+import { rulesMockdata } from '@/mock-data/rules';
+import { getTranslations, setRequestLocale } from 'next-intl/server';
+
+export async function generateMetadata({
+ params,
+}: {
+ params: Promise<{ locale: string }>;
+}) {
+ const { locale } = await params;
+
+ const t = await getTranslations({ locale, namespace: 'layout' });
+
+ return {
+ title: t('rules'),
+ };
+}
+
+export default async function RulesPage({
+ params,
+}: {
+ params: Promise<{ locale: string }>;
+}) {
+ const { locale } = await params;
+
+ setRequestLocale(locale);
+
+ return ;
+}
diff --git a/src/app/[locale]/(default)/rules/[subset]/page.tsx b/src/app/[locale]/(default)/rules/[subset]/page.tsx
new file mode 100644
index 0000000..b739e7d
--- /dev/null
+++ b/src/app/[locale]/(default)/rules/[subset]/page.tsx
@@ -0,0 +1,17 @@
+import { rulesMockdata } from '@/mock-data/rules';
+import { setRequestLocale } from 'next-intl/server';
+import { notFound } from 'next/navigation';
+
+export default async function RuleSubSetPage({
+ params,
+}: {
+ params: Promise<{ locale: string }>;
+}) {
+ const { locale } = await params;
+ setRequestLocale(locale);
+ const page = rulesMockdata.find(
+ (rule) => rule.id === Number.parseInt(locale),
+ );
+ if (!page) return notFound();
+ return {page.title}
;
+}
diff --git a/src/components/rules/RuleCard.tsx b/src/components/rules/RuleCard.tsx
new file mode 100644
index 0000000..7898aac
--- /dev/null
+++ b/src/components/rules/RuleCard.tsx
@@ -0,0 +1,57 @@
+import { Badge } from '@/components/ui/Badge';
+import { Button } from '@/components/ui/Button';
+import { Card, CardTitle } from '@/components/ui/Card';
+import { Link } from '@/lib/locale/navigation';
+import { cx } from '@/lib/utils';
+import { useTranslations } from 'next-intl';
+import Image from 'next/image';
+
+type RuleCardProps = {
+ className?: string;
+ id: number;
+ internal: boolean;
+ title: string;
+ photoUrl: string;
+};
+
+function RuleCard({ className, id, internal, title, photoUrl }: RuleCardProps) {
+ const t = useTranslations('rules');
+
+ return (
+
+ );
+}
+
+export { RuleCard };
diff --git a/src/components/rules/RuleCardList.tsx b/src/components/rules/RuleCardList.tsx
new file mode 100644
index 0000000..21d42c8
--- /dev/null
+++ b/src/components/rules/RuleCardList.tsx
@@ -0,0 +1,55 @@
+import { RuleCard } from '@/components/rules/RuleCard';
+import { cx } from '@/lib/utils';
+import { useTranslations } from 'next-intl';
+
+type RuleCardListProps = {
+ className?: string;
+ rules: Array<{
+ id: number;
+ internal: boolean;
+ title: string;
+ photoUrl: string;
+ }>;
+};
+
+function RuleCardList({ rules }: RuleCardListProps) {
+ const internal = rules.filter((rule) => rule.internal);
+ const notInternal = rules.filter((rule) => !rule.internal);
+ const t = useTranslations('rules');
+ const isMember = true;
+
+ return (
+
+
+
+ {t('forEveryone')}
+
+ {notInternal.map((rule) => (
+
+ ))}
+
+
+
{t('internal')}
+ {internal.map((rule) => (
+
+ ))}
+
+
+ );
+}
+
+export { RuleCardList };
diff --git a/src/components/rules/RuleCardListSkeleton.tsx b/src/components/rules/RuleCardListSkeleton.tsx
new file mode 100644
index 0000000..61e90da
--- /dev/null
+++ b/src/components/rules/RuleCardListSkeleton.tsx
@@ -0,0 +1,14 @@
+import { RuleCardSkeleton } from '@/components/rules/RuleCardSkeleton';
+import { useId } from 'react';
+
+function RuleCardListSkeleton() {
+ return (
+
+ {Array.from({ length: 5 }).map(() => (
+
+ ))}
+
+ );
+}
+
+export { RuleCardListSkeleton };
diff --git a/src/components/rules/RuleCardSkeleton.tsx b/src/components/rules/RuleCardSkeleton.tsx
new file mode 100644
index 0000000..1091637
--- /dev/null
+++ b/src/components/rules/RuleCardSkeleton.tsx
@@ -0,0 +1,24 @@
+import { Button } from '@/components/ui/Button';
+import { Card, CardTitle } from '@/components/ui/Card';
+import { Skeleton } from '@/components/ui/Skeleton';
+import { cx } from '@/lib/utils';
+
+function RuleCardSkeleton() {
+ return (
+
+ );
+}
+
+export { RuleCardSkeleton };
diff --git a/src/lib/locale/index.ts b/src/lib/locale/index.ts
index 0166353..d57d8a2 100644
--- a/src/lib/locale/index.ts
+++ b/src/lib/locale/index.ts
@@ -43,6 +43,14 @@ const routing = defineRouting({
en: '/storage/shopping-cart',
no: '/lager/handlekurv',
},
+ '/rules': {
+ en: '/rules',
+ no: '/regler',
+ },
+ '/rules/[subset]': {
+ en: '/rules/[subset]',
+ no: '/regler/[subset]',
+ },
'/shift-schedule': {
en: '/shift-schedule',
no: '/vaktliste',
diff --git a/src/mock-data/rules.ts b/src/mock-data/rules.ts
new file mode 100644
index 0000000..d34d125
--- /dev/null
+++ b/src/mock-data/rules.ts
@@ -0,0 +1,90 @@
+const rulesMockdata = [
+ {
+ id: 1,
+ internal: true,
+ title: 'Regler for regler',
+ photoUrl: 'mock.jpg',
+ content:
+ 'Reglene eksisterer av en grunn, overhold dem! • For din egen sikkerhet, andre sin sikkerhet og for at utstyr skal vare. • Regler håndheves av LabOps, Styret og Ledelsen • Si ifra hvis du ser regelbrudd. Ta ansvar. • Hvis du ikke vil si ifra selv, kan du gå via tillitsvalgt, som har taushetsplikt • Hvis reglene ikke følges, kan det føre til at man ikke får bruke utstyret, eller at man blir utestengt. • Regler kan foreslås endret og/eller fremlegges av hvem som helst, men godkjennes av styret.',
+ },
+ {
+ id: 2,
+ internal: true,
+ title: 'Etiske retningslinjer',
+ photoUrl: 'mock.jpg',
+ },
+ {
+ id: 3,
+ internal: false,
+ title: 'Regler for verkstedet',
+ photoUrl: 'mock.jpg',
+ },
+ {
+ id: 4,
+ internal: true,
+ title: 'Regler for vakt',
+ photoUrl: 'mock.jpg',
+ },
+ {
+ id: 5,
+ internal: false,
+ title: 'Regler for bruk av 3D-printer',
+ photoUrl: 'mock.jpg',
+ },
+ {
+ id: 6,
+ internal: true,
+ title: 'Regler for kaffemaskin',
+ photoUrl: 'mock.jpg',
+ },
+ {
+ id: 7,
+ internal: true,
+ title: 'Regler for utlån',
+ photoUrl: 'mock.jpg',
+ },
+ {
+ id: 8,
+ internal: true,
+ title: 'Regler for kurs',
+ photoUrl: 'mock.jpg',
+ },
+ {
+ id: 9,
+ internal: true,
+ title: 'Regler for arrangement',
+ photoUrl: 'mock.jpg',
+ },
+ {
+ id: 10,
+ internal: false,
+ title: 'Regler for VR briller',
+ photoUrl: 'mock.jpg',
+ },
+ {
+ id: 11,
+ internal: false,
+ title: 'Regler for verksted-PC',
+ photoUrl: 'mock.jpg',
+ },
+ {
+ id: 12,
+ internal: true,
+ title: 'Regler for kjøkkenet',
+ photoUrl: 'mock.jpg',
+ },
+ {
+ id: 13,
+ internal: false,
+ title: 'Regler for loddestasjon',
+ photoUrl: 'mock.jpg',
+ },
+ {
+ id: 14,
+ internal: true,
+ title: 'Regler for Drive',
+ photoUrl: 'mock.jpg',
+ },
+];
+
+export { rulesMockdata };