Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,25 @@ import { StyledTable } from '@/app/_components/StyledTable';
import { ARTICLES } from '@/lib/articles';
import { Alert, Link, Stack } from '@mui/joy';
import { ExternalLink } from 'lucide-react';
import { Metadata } from 'next';
import { isLocale } from '@/lib/i18n/config';
import { getDictionary } from '@/lib/i18n/dictionaries';
import { pageMetadata } from '@/lib/i18n/metadata';

export default function Articles() {
export async function generateMetadata(props: { params: Promise<{ lang: string }> }): Promise<Metadata> {
const { lang } = await props.params;
const locale = isLocale(lang) ? lang : 'en';
const dict = getDictionary(locale);
return pageMetadata(locale, '/about/articles', { title: dict.pages.articles.title });
}

export default async function Articles(props: { params: Promise<{ lang: string }> }) {
const { lang } = await props.params;
const locale = isLocale(lang) ? lang : 'en';
const dict = getDictionary(locale);
return (
<PageLayout
title="Articles"
title={dict.pages.articles.title}
subtitle={
<>
This page collects articles about the W3C Web of Things. See our{' '}
Expand Down
18 changes: 18 additions & 0 deletions website/app/[lang]/about/contact/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Metadata } from 'next';
import { isLocale } from '@/lib/i18n/config';
import { getDictionary } from '@/lib/i18n/dictionaries';
import { pageMetadata } from '@/lib/i18n/metadata';

export async function generateMetadata(props: { params: Promise<{ lang: string }> }): Promise<Metadata> {
const { lang } = await props.params;
const locale = isLocale(lang) ? lang : 'en';
const dict = getDictionary(locale);
return pageMetadata(locale, '/about/contact', {
title: dict.pages.contact.title,
description: dict.pages.contact.subtitle,
});
}

export default function ContactLayout({ children }: { children: React.ReactNode }) {
return children;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { PageLayout } from '@/app/_components/PageLayout';
import { CONTACTS } from '@/lib/contacts';
import { Box } from '@mui/joy';
import { MastodonFeed } from '@/app/_components/home-page-sections/MastodonFeed';
import { useDictionary } from '@/app/_components/i18n/LocaleProvider';

export default function Contact() {
const dict = useDictionary();
return (
<PageLayout title="Contact" subtitle="Get in touch with us for any questions or inquiries">
<PageLayout title={dict.pages.contact.title} subtitle={dict.pages.contact.subtitle}>
<Box
sx={{
display: 'grid',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
import { PageLayout } from '@/app/_components/PageLayout';
import { Alert, Box, Stack, Typography, Card } from '@mui/joy';
import { history } from '@/lib/history';
import { Metadata } from 'next';
import { isLocale } from '@/lib/i18n/config';
import { getDictionary } from '@/lib/i18n/dictionaries';
import { pageMetadata } from '@/lib/i18n/metadata';

export default function History() {
export async function generateMetadata(props: { params: Promise<{ lang: string }> }): Promise<Metadata> {
const { lang } = await props.params;
const locale = isLocale(lang) ? lang : 'en';
const dict = getDictionary(locale);
return pageMetadata(locale, '/about/history', {
title: dict.pages.history.title,
description: dict.pages.history.subtitle,
});
}

export default async function History(props: { params: Promise<{ lang: string }> }) {
const { lang } = await props.params;
const locale = isLocale(lang) ? lang : 'en';
const dict = getDictionary(locale);
return (
<PageLayout
title="History"
subtitle="Web of Things has reached its place at W3C after many years of discussions and work by different parties "
>
<PageLayout title={dict.pages.history.title} subtitle={dict.pages.history.subtitle}>
<Alert variant="outlined">
The journey of the Web of Things at the W3C began with initial discussions to bridge the gap between the Web and
the physical world. Since then, it has evolved through various community efforts, workshops, and working groups
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,27 @@ import { Box, Card, Divider, Link, Stack, Table, Typography } from '@mui/joy';
import { LinkButton } from '@/app/_components/LinkButton';
import { DELIVERABLES } from '@/lib/deliverables';
import { StyledTable } from '@/app/_components/StyledTable';
import { Metadata } from 'next';
import { isLocale } from '@/lib/i18n/config';
import { getDictionary } from '@/lib/i18n/dictionaries';
import { pageMetadata } from '@/lib/i18n/metadata';

export default function DocumentationPage() {
export async function generateMetadata(props: { params: Promise<{ lang: string }> }): Promise<Metadata> {
const { lang } = await props.params;
const locale = isLocale(lang) ? lang : 'en';
const dict = getDictionary(locale);
return pageMetadata(locale, '/developers/documentation', {
title: dict.pages.documentation.title,
description: dict.pages.documentation.subtitle,
});
}

export default async function DocumentationPage(props: { params: Promise<{ lang: string }> }) {
const { lang } = await props.params;
const locale = isLocale(lang) ? lang : 'en';
const dict = getDictionary(locale);
return (
<PageLayout
title="Documentation"
subtitle="Explore the Web of Things (WoT) specifications, tutorials, and resources"
>
<PageLayout title={dict.pages.documentation.title} subtitle={dict.pages.documentation.subtitle}>
<PageSection title="Foundations">
<Stack gap={3}>
<Typography>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Box } from '@mui/joy';
import { Filter } from './Filter';
import toolsJSON from '@/lib/generated/devToolsOutput.json';
import { DevToolsOutput, ToolOutput } from '../../../../../scripts/dev-tools/types';
import { DevToolsOutput, ToolOutput } from '../../../../../../scripts/dev-tools/types';
import { useMemo } from 'react';

export function ToolFilters({
Expand Down Expand Up @@ -50,14 +50,8 @@ export function ToolFilters({
);

const allCategoriesOptions = useMemo(() => ['All', ...allCategories], [allCategories]);
const allPlatformsOptions = useMemo(
() => ['All', ...Array.from(allPlatformsSet).sort()],
[allPlatformsSet]
);
const allLanguagesOptions = useMemo(
() => ['All', ...Array.from(allLanguagesSet).sort()],
[allLanguagesSet]
);
const allPlatformsOptions = useMemo(() => ['All', ...Array.from(allPlatformsSet).sort()], [allPlatformsSet]);
const allLanguagesOptions = useMemo(() => ['All', ...Array.from(allLanguagesSet).sort()], [allLanguagesSet]);

const disabledCategories = useMemo(
() => allCategoriesOptions.filter((opt) => getMatchCount(opt, platform, language, showObsolete) === 0),
Expand Down
18 changes: 18 additions & 0 deletions website/app/[lang]/developers/tools/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Metadata } from 'next';
import { isLocale } from '@/lib/i18n/config';
import { getDictionary } from '@/lib/i18n/dictionaries';
import { pageMetadata } from '@/lib/i18n/metadata';

export async function generateMetadata(props: { params: Promise<{ lang: string }> }): Promise<Metadata> {
const { lang } = await props.params;
const locale = isLocale(lang) ? lang : 'en';
const dict = getDictionary(locale);
return pageMetadata(locale, '/developers/tools', {
title: dict.pages.tools.title,
description: dict.pages.tools.subtitle,
});
}

export default function ToolsLayout({ children }: { children: React.ReactNode }) {
return children;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@ import { PageLayout } from '@/app/_components/PageLayout';
import { ReactNode, useMemo, useState } from 'react';
import { ToolFilters } from './_components/ToolFilters';
import toolsJSON from '@/lib/generated/devToolsOutput.json';
import { DevToolsOutput, ToolOutput } from '../../../../scripts/dev-tools/types';
import { DevToolsOutput, ToolOutput } from '../../../../../scripts/dev-tools/types';
import { Alert, Link, Modal, ModalClose, ModalDialog, Stack, Table, Typography } from '@mui/joy';
import GitHubLogo from '@/public/github.png';
import GitLabLogo from '@/public/gitlab.png';
import Image, { StaticImageData } from 'next/image';
import { Building, Clock, House, Monitor, Scale } from 'lucide-react';
import { StyledTable } from '@/app/_components/StyledTable';
import { useDictionary } from '@/app/_components/i18n/LocaleProvider';

export default function ToolsPage() {
const dict = useDictionary();
const [categoryFilter, setCategoryFilter] = useState('All');
const [platformFilter, setPlatformFilter] = useState('All');
const [languageFilter, setLanguageFilter] = useState('All');
Expand Down Expand Up @@ -82,10 +84,7 @@ export default function ToolsPage() {
}, [categoryFilter, languageFilter, platformFilter, showObsoleteFilter, tools]);

return (
<PageLayout
title="WoT Tools"
subtitle="Various resources for building Web of Things applications, including libraries, ready-to-use software, services, and SDKs tailored for different development stages, are grouped below "
>
<PageLayout title={dict.pages.tools.title} subtitle={dict.pages.tools.subtitle}>
{selectedTool && (
<Modal
open={true}
Expand Down
28 changes: 28 additions & 0 deletions website/app/[lang]/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use client';

import { PageLayout } from '../_components/PageLayout';
import { LocaleLink } from '../_components/LocaleLink';
import { Button, ButtonGroup } from '@mui/joy';
import { Home, RotateCw } from 'lucide-react';
import { usePathname } from 'next/navigation';
import { useDictionary } from '../_components/i18n/LocaleProvider';
import { stripLocale } from '@/lib/i18n/config';

export default function Error() {
const path = stripLocale(usePathname());
const dict = useDictionary();
return (
<PageLayout title={dict.error.title} subtitle={dict.error.subtitle}>
<ButtonGroup variant="soft" color="neutral" spacing={2}>
<Button startDecorator={<RotateCw size={18} />} onClick={() => window.location.reload()}>
{dict.error.cta}
</Button>
{path !== '/' && (
<LocaleLink href="/">
<Button startDecorator={<Home size={18} />}>{dict.notFound.cta}</Button>
</LocaleLink>
)}
</ButtonGroup>
</PageLayout>
);
}
87 changes: 87 additions & 0 deletions website/app/[lang]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import '../globals.css';
import ThemeRegistry from '../_theme/ThemeRegistry';
import { Metadata, Route } from 'next';
import { redirect } from 'next/navigation';
import { Navbar } from '../_components/navbar/Navbar';
import { Footer } from '../_components/Footer';
import { Alert, Box, Link, Stack } from '@mui/joy';
import { Redirects } from '../_components/Redirects';
import { LocaleProvider } from '../_components/i18n/LocaleProvider';
import { LOCALES, LOCALE_HREFLANG, isLocale, type Locale } from '@/lib/i18n/config';
import { getDictionary } from '@/lib/i18n/dictionaries';
import { getAlternates, SITE_URL } from '@/lib/i18n/metadata';
import { StyledLink } from '../_components/StyledLink';

export const dynamicParams = false;

export function generateStaticParams() {
return LOCALES.map((lang) => ({ lang }));
}

export async function generateMetadata(props: { params: Promise<{ lang: string }> }): Promise<Metadata> {
const { lang } = await props.params;
const locale: Locale = isLocale(lang) ? lang : 'en';
const dict = getDictionary(locale);

return {
metadataBase: new URL(SITE_URL),
title: {
default: 'W3C Web of Things',
template: '%s | Web of Things',
},
description: dict.metadata.description,
alternates: getAlternates(locale, '/'),
openGraph: {
siteName: 'Web of Things',
title: 'W3C Web of Things',
description: dict.metadata.description,
locale: LOCALE_HREFLANG[locale],
type: 'website',
},
};
}

export default async function RootLayout(props: { children: React.ReactNode; params: Promise<{ lang: string }> }) {
const { lang } = await props.params;

if (!isLocale(lang)) {
redirect('/en' as Route);
}

const dict = getDictionary(lang);

return (
<html lang={LOCALE_HREFLANG[lang]}>
<head>
{/* Mastodon integration */}
<link rel="me" href="https://w3c.social/@wot" />
</head>
<body>
<LocaleProvider lang={lang} dict={dict}>
<Redirects />
<ThemeRegistry>
<Stack minHeight="100vh">
<Navbar />
<Box component="main" flex={1}>
{lang !== 'en' && (
<Alert variant="soft" sx={{ borderRadius: 0, display: 'block', textAlign: 'center' }}>
{dict.alertBanner.translationNotice}{' '}
<StyledLink
fontSize={14}
external_url="https://github.com/w3c/wot-marketing/issues"
sx={{ display: 'inline' }}
>
GitHub
</StyledLink>
</Alert>
)}
{props.children}
</Box>
<Footer />
</Stack>
</ThemeRegistry>
</LocaleProvider>
</body>
</html>
);
}
17 changes: 17 additions & 0 deletions website/app/[lang]/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use client';

import { Button } from '@mui/joy';
import { PageLayout } from '../_components/PageLayout';
import { LocaleLink } from '../_components/LocaleLink';
import { useDictionary } from '../_components/i18n/LocaleProvider';

export default function NotFound() {
const dict = useDictionary();
return (
<PageLayout title={dict.notFound.title} subtitle={dict.notFound.subtitle}>
<LocaleLink href="/">
<Button variant="soft">{dict.notFound.cta}</Button>
</LocaleLink>
</PageLayout>
);
}
41 changes: 41 additions & 0 deletions website/app/[lang]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Metadata } from 'next';
import { PageLayout } from '../_components/PageLayout';
import { WoTInANutshell } from '../_components/home-page-sections/WoTInANutshell';
import { Members } from '../_components/home-page-sections/Members';
import { Liaisons } from '../_components/home-page-sections/Liaisons';
import { WhyJoin } from '../_components/home-page-sections/WhyJoin';
import { RecentActivities } from '../_components/home-page-sections/RecentActivities';
import { UseCases } from '../_components/home-page-sections/UseCases';
import { MastodonFeed } from '../_components/home-page-sections/MastodonFeed';
import { isLocale } from '@/lib/i18n/config';
import { getDictionary } from '@/lib/i18n/dictionaries';
import { getAlternates } from '@/lib/i18n/metadata';

export async function generateMetadata(props: { params: Promise<{ lang: string }> }): Promise<Metadata> {
const { lang } = await props.params;
const locale = isLocale(lang) ? lang : 'en';
const dict = getDictionary(locale);
return {
title: 'W3C Web of Things',
description: dict.home.hero.subtitle,
alternates: getAlternates(locale, '/'),
};
}

export default async function HomePage(props: { params: Promise<{ lang: string }> }) {
const { lang } = await props.params;
const locale = isLocale(lang) ? lang : 'en';
const dict = getDictionary(locale);

return (
<PageLayout title={dict.home.hero.title} subtitle={dict.home.hero.subtitle}>
<WoTInANutshell />
<UseCases />
<Members />
<Liaisons />
<WhyJoin />
<RecentActivities />
<MastodonFeed />
</PageLayout>
);
}
Loading