diff --git a/app/components/content-mdx-provider.tsx b/app/components/content-mdx-provider.tsx
index 3e8997dd1..80ec1977a 100644
--- a/app/components/content-mdx-provider.tsx
+++ b/app/components/content-mdx-provider.tsx
@@ -3,7 +3,16 @@ import { Box } from "@mui/material";
import { ReactNode } from "react";
import { ContentLayout, StaticContentLayout } from "@/components/layout";
-import { Contribute, Examples, Intro, Tutorial } from "@/homepage";
+import {
+ BugReport,
+ Contribute,
+ Examples,
+ Intro,
+ Newsletter,
+ Tutorial,
+} from "@/homepage";
+import { FeatureRequest } from "@/homepage/feature-request";
+import { Section } from "@/homepage/section";
const castContentId = (contentId: unknown) => {
if (typeof contentId === "string") {
@@ -35,6 +44,10 @@ const defaultMDXComponents = {
Tutorial,
Examples,
Contribute,
+ Newsletter,
+ BugReport,
+ Section,
+ FeatureRequest,
};
export const ContentMDXProvider = ({ children }: { children: ReactNode }) => {
diff --git a/app/docs/homepage.docs.mdx b/app/docs/homepage.docs.mdx
index 65a5fc793..4f054848d 100644
--- a/app/docs/homepage.docs.mdx
+++ b/app/docs/homepage.docs.mdx
@@ -1,25 +1,38 @@
import { Box } from "@mui/material";
import { ReactSpecimen } from "./catalog";
-import { Contribute, Examples, Intro, Tutorial } from "@/homepage";
-import { Canvas, Meta } from '@storybook/blocks';
-import * as HomepageStories from './homepage.stories';
+import {
+ BugReport,
+ Contribute,
+ Examples,
+ Intro,
+ Newsletter,
+ Tutorial,
+} from "@/homepage";
+import { bugReportTemplates } from "@/templates/email/bug-report";
+import { OWNER_ORGANIZATION_EMAIL } from "@/templates/email/config";
+import { featureRequestTemplates } from "@/templates/email/feature-request";
+import { Canvas, Meta } from "@storybook/blocks";
+import { createMailtoLink } from "../../app/templates/email";
+import * as HomepageStories from "./homepage.stories";
> The Homepage is the main page you see when you enter the Visualize app.
-It consists of 4 different components: Intro, Tutorial, Examples and Contribute. In order to compose a complete Homepage, you have to use them all in the correct order.
+It consists of 7 different components: Intro, Tutorial, Examples, Newsletter,
+Bug Reporting, Feature Requesting and Contribute. In order to compose a complete
+Homepage, you have to use them all in the correct order.
-You can either import them directly to JSX files or create a separate MDX file and use a MDXProvider to render the page (see ContentMDXProvider component).
+You can either import them directly to JSX files or create a separate MDX file
+and use a MDXProvider to render the page (see ContentMDXProvider component).
-
## How to use
```jsx
-import { Contribute, Examples, Intro, Tutorial } from "../homepage";
+import { Contribute, Examples, Intro, Tutorial, Newsletter, BugReport, FeatureRequest } from "../homepage";
+
+
+
-```
\ No newline at end of file
+```
diff --git a/app/docs/homepage.stories.tsx b/app/docs/homepage.stories.tsx
index ad3cb8480..ccd8ec845 100644
--- a/app/docs/homepage.stories.tsx
+++ b/app/docs/homepage.stories.tsx
@@ -1,7 +1,21 @@
import { Box } from "@mui/material";
import { Meta } from "@storybook/react";
-import { Contribute, Examples, Intro, Tutorial } from "@/homepage";
+import {
+ BugReport,
+ Contribute,
+ Examples,
+ Intro,
+ Newsletter,
+ Tutorial,
+} from "@/homepage";
+import { FeatureRequest } from "@/homepage/feature-request";
+import { Section } from "@/homepage/section";
+import { bugReportTemplates } from "@/templates/email/bug-report";
+import { OWNER_ORGANIZATION_EMAIL } from "@/templates/email/config";
+import { featureRequestTemplates } from "@/templates/email/feature-request";
+
+import { createMailtoLink } from "../../app/templates/email";
import { ReactSpecimen } from "./catalog";
@@ -33,12 +47,55 @@ const HomepageStory = {
example2Headline="Use powerful customizations"
example2Description="With the help of custom filters and data segmentation, even complex issues can be visualized."
/>
-
+
+
+
+
+
+
+
+
+
+
+
),
diff --git a/app/homepage/bug-report.tsx b/app/homepage/bug-report.tsx
new file mode 100644
index 000000000..2c5ab05a5
--- /dev/null
+++ b/app/homepage/bug-report.tsx
@@ -0,0 +1,70 @@
+import { Button, Link, Typography } from "@mui/material";
+
+import Flex from "@/components/flex";
+
+export const BugReport = ({
+ headline,
+ description,
+ buttonLabel,
+ buttonUrl,
+}: {
+ headline: string;
+ description: string;
+ buttonLabel: string;
+ buttonUrl: string;
+}) => {
+ return (
+
+
+
+ {headline}
+
+
+ {description}
+
+
+
+
+
+
+ );
+};
diff --git a/app/homepage/contribute.tsx b/app/homepage/contribute.tsx
index 696344da7..fa797f4e3 100644
--- a/app/homepage/contribute.tsx
+++ b/app/homepage/contribute.tsx
@@ -1,5 +1,4 @@
-import { Box, Button, Link, Typography } from "@mui/material";
-import * as React from "react";
+import { Button, Link, Typography } from "@mui/material";
import Flex from "@/components/flex";
@@ -15,50 +14,57 @@ export const Contribute = ({
buttonUrl: string;
}) => {
return (
-
-
-
-
-
- {headline}
-
-
- {description}
-
-
-
-
-
-
-
-
+
+
+
+ {headline}
+
+
+ {description}
+
+
+
+
+
+
);
};
diff --git a/app/homepage/feature-request.tsx b/app/homepage/feature-request.tsx
new file mode 100644
index 000000000..d06c5d058
--- /dev/null
+++ b/app/homepage/feature-request.tsx
@@ -0,0 +1,69 @@
+import { Button, Link, Typography } from "@mui/material";
+
+import Flex from "@/components/flex";
+
+export const FeatureRequest = ({
+ headline,
+ description,
+ buttonLabel,
+ buttonUrl,
+}: {
+ headline: string;
+ description: string;
+ buttonLabel: string;
+ buttonUrl: string;
+}) => {
+ return (
+
+
+
+ {headline}
+
+
+ {description}
+
+
+
+
+
+
+ );
+};
diff --git a/app/homepage/index.ts b/app/homepage/index.ts
index b227d2c40..7ad20a2e9 100644
--- a/app/homepage/index.ts
+++ b/app/homepage/index.ts
@@ -1,4 +1,6 @@
+export * from "./bug-report";
+export * from "./contribute";
+export * from "./examples";
export * from "./intro";
+export * from "./newsletter";
export * from "./tutorial";
-export * from "./examples";
-export * from "./contribute";
diff --git a/app/homepage/newsletter.tsx b/app/homepage/newsletter.tsx
new file mode 100644
index 000000000..51f6daba8
--- /dev/null
+++ b/app/homepage/newsletter.tsx
@@ -0,0 +1,69 @@
+import { Button, Link, Typography } from "@mui/material";
+
+import Flex from "@/components/flex";
+
+export const Newsletter = ({
+ headline,
+ description,
+ buttonLabel,
+ buttonUrl,
+}: {
+ headline: string;
+ description: string;
+ buttonLabel: string;
+ buttonUrl: string;
+}) => {
+ return (
+
+
+
+ {headline}
+
+
+ {description}
+
+
+
+
+
+
+ );
+};
diff --git a/app/homepage/section.tsx b/app/homepage/section.tsx
new file mode 100644
index 000000000..6563eb761
--- /dev/null
+++ b/app/homepage/section.tsx
@@ -0,0 +1,30 @@
+import { Box, SxProps } from "@mui/material";
+import { Theme } from "@mui/material/styles";
+
+import Flex from "@/components/flex";
+
+export const Section = ({
+ children,
+ sx = { backgroundColor: "primary.main", color: "grey.100", width: "100%" },
+}: {
+ children: React.ReactNode;
+ sx?: SxProps;
+}) => {
+ return (
+
+
+
+ {children}
+
+
+
+ );
+};
diff --git a/app/static-pages/de/index.mdx b/app/static-pages/de/index.mdx
index 475dc5664..0fd448f5b 100644
--- a/app/static-pages/de/index.mdx
+++ b/app/static-pages/de/index.mdx
@@ -1,3 +1,12 @@
+import { bugReportTemplates } from "@/templates/email/bug-report";
+import { featureRequestTemplates } from "@/templates/email/feature-request";
+import { Divider } from "@mui/material";
+import { createMailtoLink } from "../../../app/templates/email";
+import {
+ OWNER_ORGANIZATION_EMAIL,
+ SUPPORT_EMAIL,
+} from "../../../app/templates/email/config";
+
export const contentId = "home";
-
+
+
+
+
+
+
+
+
+
+
diff --git a/app/static-pages/en/index.mdx b/app/static-pages/en/index.mdx
index 380ab047b..c3600380b 100644
--- a/app/static-pages/en/index.mdx
+++ b/app/static-pages/en/index.mdx
@@ -1,3 +1,12 @@
+import { bugReportTemplates } from "@/templates/email/bug-report";
+import { featureRequestTemplates } from "@/templates/email/feature-request";
+import { Divider } from "@mui/material";
+import { createMailtoLink } from "../../../app/templates/email";
+import {
+ OWNER_ORGANIZATION_EMAIL,
+ SUPPORT_EMAIL,
+} from "../../../app/templates/email/config";
+
export const contentId = "home";
-
+
+
+
+
+
+
+
+
+
+
diff --git a/app/static-pages/fr/index.mdx b/app/static-pages/fr/index.mdx
index 35e80c5d9..8f66dbaf4 100644
--- a/app/static-pages/fr/index.mdx
+++ b/app/static-pages/fr/index.mdx
@@ -1,3 +1,12 @@
+import { bugReportTemplates } from "@/templates/email/bug-report";
+import { featureRequestTemplates } from "@/templates/email/feature-request";
+import { Divider } from "@mui/material";
+import { createMailtoLink } from "../../../app/templates/email";
+import {
+ OWNER_ORGANIZATION_EMAIL,
+ SUPPORT_EMAIL,
+} from "../../../app/templates/email/config";
+
export const contentId = "home";
-
+
+
+
+
+
+
+
+
+
+
diff --git a/app/static-pages/it/index.mdx b/app/static-pages/it/index.mdx
index 347b4fa35..fae06cbdf 100644
--- a/app/static-pages/it/index.mdx
+++ b/app/static-pages/it/index.mdx
@@ -1,3 +1,13 @@
+import { bugReportTemplates } from "@/templates/email/bug-report";
+import { featureRequestTemplates } from "@/templates/email/feature-request";
+import { Divider } from "@mui/material";
+
+import { createMailtoLink } from "../../../app/templates/email";
+import {
+ OWNER_ORGANIZATION_EMAIL,
+ SUPPORT_EMAIL,
+} from "../../../app/templates/email/config";
+
export const contentId = "home";
-
+
+
+
+
+
+
+
+
+
+
diff --git a/app/templates/email/bug-report.ts b/app/templates/email/bug-report.ts
new file mode 100644
index 000000000..695f198dd
--- /dev/null
+++ b/app/templates/email/bug-report.ts
@@ -0,0 +1,146 @@
+export const bugReportTemplates = {
+ en: `
+Bug Report
+
+Describe the bug
+A clear and concise description of what the bug is. If it seems connected to some data problem (missing values, wrong parsing), please first check the cube in Cube Validator (https://cube-validator.lindas.admin.ch/select) to see if everything is fine there.
+Please describe...
+
+----------------------------------------------
+To Reproduce
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '...'
+3. Scroll down to '...'
+4. See error
+
+----------------------------------------------
+Expected behavior
+A clear and concise description of what you expected to happen.
+Please describe...
+
+----------------------------------------------
+Screenshots or video
+If applicable, add screenshots or a short video to help put your problem into a context.
+
+----------------------------------------------
+Environment
+Please complete the following information.
+- Visualize environment and version: [e.g., INT v4.9.4]
+- Browser and version [e.g., Chrome 107]
+
+----------------------------------------------
+Additional context
+Add any other context about the problem here.
+Please describe...
+`,
+
+ de: `
+Fehlermeldung
+
+----------------------------------------------
+Beschreiben Sie den Fehler
+Eine klare und präzise Beschreibung des Fehlers. Wenn es mit einem Datenproblem zusammenhängt (fehlende Werte, falsche Analyse), überprüfen Sie bitte zuerst den Cube im Cube Validator (https://cube-validator.lindas.admin.ch/select), um sicherzustellen, dass dort alles in Ordnung ist.
+Bitte beschreiben Sie...
+
+----------------------------------------------
+Zum Reproduzieren
+Schritte zum Reproduzieren des Verhaltens:
+1. Gehen Sie zu '...'
+2. Klicken Sie auf '...'
+3. Scrollen Sie nach unten zu '...'
+4. Fehlermeldung erscheint
+
+----------------------------------------------
+Erwartetes Verhalten
+Eine klare und präzise Beschreibung dessen, was Sie erwartet haben.
+Bitte beschreiben Sie...
+
+----------------------------------------------
+Screenshots oder Video
+Falls zutreffend, fügen Sie Screenshots oder ein kurzes Video hinzu, um Ihr Problem in einen Kontext zu setzen.
+
+----------------------------------------------
+Umgebung
+Bitte vervollständigen Sie die folgenden Informationen.
+- Visualize-Umgebung und Version: [z.B., INT v4.9.4]
+- Browser und Version [z.B., Chrome 107]
+
+----------------------------------------------
+Zusätzlicher Kontext
+Fügen Sie hier weitere Kontextinformationen zum Problem hinzu.
+Bitte beschreiben Sie...
+`,
+
+ fr: `
+Rapport de bug
+
+Description du bug
+Une description claire et concise du bug. S'il semble lié à un problème de données (valeurs manquantes, analyse incorrecte), veuillez d'abord vérifier le cube dans le Cube Validator (https://cube-validator.lindas.admin.ch/select) pour vous assurer que tout y est correct.
+Veuillez décrire...
+
+----------------------------------------------
+Pour reproduire
+Étapes pour reproduire le comportement :
+1. Aller à '...'
+2. Cliquer sur '...'
+3. Faire défiler jusqu'à '...'
+4. Voir l'erreur
+
+----------------------------------------------
+Comportement attendu
+Une description claire et concise de ce que vous attendiez.
+Veuillez décrire...
+
+----------------------------------------------
+Captures d'écran ou vidéo
+Le cas échéant, ajoutez des captures d'écran ou une courte vidéo pour mettre votre problème en contexte.
+
+----------------------------------------------
+Environnement
+Veuillez compléter les informations suivantes.
+- Environnement et version Visualize : [ex. INT v4.9.4]
+- Navigateur et version [ex. Chrome 107]
+
+----------------------------------------------
+Contexte supplémentaire
+Ajoutez ici tout autre contexte concernant le problème.
+Veuillez décrire...
+`,
+
+ it: `
+Segnalazione di bug
+
+Descrizione del bug
+Una descrizione chiara e concisa del bug. Se sembra collegato a un problema di dati (valori mancanti, analisi errata), controllare prima il cubo nel Cube Validator (https://cube-validator.lindas.admin.ch/select) per assicurarsi che tutto sia a posto.
+Si prega di descrivere...
+
+----------------------------------------------
+Per riprodurre
+Passaggi per riprodurre il comportamento:
+1. Andare a '...'
+2. Cliccare su '...'
+3. Scorrere fino a '...'
+4. Vedere l'errore
+
+----------------------------------------------
+Comportamento previsto
+Una descrizione chiara e concisa di ciò che ci si aspettava.
+Si prega di descrivere...
+
+----------------------------------------------
+Screenshot o video
+Se applicabile, aggiungere screenshot o un breve video per contestualizzare il problema.
+
+----------------------------------------------
+Ambiente
+Si prega di completare le seguenti informazioni.
+- Ambiente e versione Visualize: [es. INT v4.9.4]
+- Browser e versione [es. Chrome 107]
+
+----------------------------------------------
+Contesto aggiuntivo
+Aggiungere qui qualsiasi altro contesto sul problema.
+Si prega di descrivere...
+`,
+};
diff --git a/app/templates/email/config.ts b/app/templates/email/config.ts
new file mode 100644
index 000000000..9e6151b9d
--- /dev/null
+++ b/app/templates/email/config.ts
@@ -0,0 +1,2 @@
+export const OWNER_ORGANIZATION_EMAIL = "visualize@bafu.admin.ch";
+export const SUPPORT_EMAIL = "support@interactivethings.com";
diff --git a/app/templates/email/feature-request.ts b/app/templates/email/feature-request.ts
new file mode 100644
index 000000000..285256df4
--- /dev/null
+++ b/app/templates/email/feature-request.ts
@@ -0,0 +1,113 @@
+export const featureRequestTemplates = {
+ en: `
+New Feature
+
+Is your feature request related to a problem?
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+Please describe...
+
+----------------------------------------------
+Describe the solution you'd like
+A clear and concise description of what you want to happen.
+Please describe...
+
+----------------------------------------------
+Describe alternatives you've considered
+A clear and concise description of any alternative solutions or features you've considered.
+Please describe...
+
+----------------------------------------------
+Use cases and impact
+Examples of how the feature would be beneficial and an estimation of how much impact it would have.
+Please describe...
+
+----------------------------------------------
+Additional context
+Add any other context or screenshots about the feature request here.
+Please describe...
+`,
+
+ de: `
+Neue Funktion
+
+Bezieht sich Ihre Feature-Anfrage auf ein Problem?
+Eine klare und präzise Beschreibung des Problems. Z.B. Es frustriert mich immer, wenn [...]
+Bitte beschreiben Sie...
+
+----------------------------------------------
+Beschreiben Sie die gewünschte Lösung
+Eine klare und präzise Beschreibung dessen, was passieren soll.
+Bitte beschreiben Sie...
+
+----------------------------------------------
+Beschreiben Sie Alternativen, die Sie in Betracht gezogen haben
+Eine klare und präzise Beschreibung aller alternativen Lösungen oder Funktionen, die Sie in Betracht gezogen haben.
+Bitte beschreiben Sie...
+
+----------------------------------------------
+Anwendungsfälle und Auswirkungen
+Beispiele dafür, wie die Funktion nützlich wäre und eine Einschätzung der Auswirkungen.
+Bitte beschreiben Sie...
+
+----------------------------------------------
+Zusätzlicher Kontext
+Fügen Sie hier weitere Kontextinformationen oder Screenshots zur Feature-Anfrage hinzu.
+Bitte beschreiben Sie...
+`,
+
+ fr: `
+Nouvelle fonctionnalité
+
+Votre demande de fonctionnalité est-elle liée à un problème ?
+Une description claire et concise du problème. Ex. Je suis toujours frustré quand [...]
+Veuillez décrire...
+
+----------------------------------------------
+Décrivez la solution que vous souhaitez
+Une description claire et concise de ce que vous voulez qu'il se passe.
+Veuillez décrire...
+
+----------------------------------------------
+Décrivez les alternatives que vous avez envisagées
+Une description claire et concise des solutions ou fonctionnalités alternatives que vous avez envisagées.
+Veuillez décrire...
+
+----------------------------------------------
+Cas d'utilisation et impact
+Exemples de l'utilité de la fonctionnalité et estimation de son impact.
+Veuillez décrire...
+
+----------------------------------------------
+Contexte supplémentaire
+Ajoutez ici tout autre contexte ou captures d'écran concernant la demande de fonctionnalité.
+Veuillez décrire...
+`,
+
+ it: `
+Nuova funzionalità
+
+La sua richiesta di funzionalità è legata a un problema?
+Una descrizione chiara e concisa del problema. Es. Sono sempre frustrato quando [...]
+Si prega di descrivere...
+
+----------------------------------
+Descriva la soluzione che vorrebbe
+Una descrizione chiara e concisa di ciò che vuole che accada.
+Si prega di descrivere...
+
+----------------------------------------------
+Descriva le alternative considerate
+Una descrizione chiara e concisa di eventuali soluzioni o funzionalità alternative che ha considerato.
+Si prega di descrivere...
+
+----------------------------------------------
+Casi d'uso e impatto
+Esempi di come la funzionalità sarebbe utile e una stima del suo impatto.
+Si prega di descrivere...
+
+----------------------------------------------
+Contesto aggiuntivo
+Aggiunga qui qualsiasi altro contesto o screenshot sulla richiesta di funzionalità.
+Si prega di descrivere...
+`,
+};
diff --git a/app/templates/email/index.ts b/app/templates/email/index.ts
new file mode 100644
index 000000000..a1726e278
--- /dev/null
+++ b/app/templates/email/index.ts
@@ -0,0 +1,22 @@
+import { bugReportTemplates } from "./bug-report";
+
+type EmailRecipients = {
+ to: string;
+ cc: string;
+};
+
+export const createMailtoLink = (
+ lang: keyof typeof bugReportTemplates,
+ options: {
+ recipients: EmailRecipients;
+ template: typeof bugReportTemplates;
+ subject: string;
+ }
+) => {
+ const template = options.template[lang];
+ return `mailto:${options.recipients.to}?cc=${
+ options.recipients.cc
+ }&subject=${encodeURIComponent(options.subject)}&body=${encodeURIComponent(
+ template
+ )}`;
+};