[OPTIONAL] - Newssite - updates to support different languages / html direction in the future (#248)

This commit is contained in:
Thorsten Kober 2023-06-29 07:11:39 -07:00 committed by GitHub
parent ad36a2c483
commit 9025eb1fdc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 123 additions and 39 deletions

View file

@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="./_next/static/css/5c49298423df7aa9.css" as="style"/><link rel="stylesheet" href="./_next/static/css/5c49298423df7aa9.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="./_next/static/chunks/webpack-e50e9853db18b759.js" defer=""></script><script src="./_next/static/chunks/framework-2c79e2a64abdb08b.js" defer=""></script><script src="./_next/static/chunks/main-2ba37e62325cc71b.js" defer=""></script><script src="./_next/static/chunks/pages/_app-77983e68be50f72a.js" defer=""></script><script src="./_next/static/chunks/pages/_error-54de1933a164a1ff.js" defer=""></script><script src="./_next/static/F195PZl4yn18BfMZaSMUr/_buildManifest.js" defer=""></script><script src="./_next/static/F195PZl4yn18BfMZaSMUr/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><div id="settings-container"></div><div id="notifications-container"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"F195PZl4yn18BfMZaSMUr","assetPrefix":".","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="./_next/static/css/5c49298423df7aa9.css" as="style"/><link rel="stylesheet" href="./_next/static/css/5c49298423df7aa9.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="./_next/static/chunks/webpack-e50e9853db18b759.js" defer=""></script><script src="./_next/static/chunks/framework-2c79e2a64abdb08b.js" defer=""></script><script src="./_next/static/chunks/main-2ba37e62325cc71b.js" defer=""></script><script src="./_next/static/chunks/pages/_app-77983e68be50f72a.js" defer=""></script><script src="./_next/static/chunks/pages/_error-54de1933a164a1ff.js" defer=""></script><script src="./_next/static/t9NOr8PuVZjocZMRyrerF/_buildManifest.js" defer=""></script><script src="./_next/static/t9NOr8PuVZjocZMRyrerF/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><div id="settings-container"></div><div id="notifications-container"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"t9NOr8PuVZjocZMRyrerF","assetPrefix":".","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
self.__BUILD_MANIFEST={__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":["static/chunks/743-fd706aeabb7828e3.js","static/css/8b914e4a9001ee1d.css","static/chunks/pages/index-85192d51d3aa6df8.js"],"/_error":["static/chunks/pages/_error-54de1933a164a1ff.js"],sortedPages:["/","/_app","/_error"]},self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
self.__BUILD_MANIFEST={__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":["static/chunks/743-fd706aeabb7828e3.js","static/css/8b914e4a9001ee1d.css","static/chunks/pages/index-697895d5144433b5.js"],"/_error":["static/chunks/pages/_error-54de1933a164a1ff.js"],sortedPages:["/","/_app","/_error"]},self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();

View file

@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="./_next/static/css/5c49298423df7aa9.css" as="style"/><link rel="stylesheet" href="./_next/static/css/5c49298423df7aa9.css" data-n-g=""/><link rel="preload" href="./_next/static/css/8b914e4a9001ee1d.css" as="style"/><link rel="stylesheet" href="./_next/static/css/8b914e4a9001ee1d.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="./_next/static/chunks/webpack-e50e9853db18b759.js" defer=""></script><script src="./_next/static/chunks/framework-2c79e2a64abdb08b.js" defer=""></script><script src="./_next/static/chunks/main-2ba37e62325cc71b.js" defer=""></script><script src="./_next/static/chunks/pages/_app-77983e68be50f72a.js" defer=""></script><script src="./_next/static/chunks/743-fd706aeabb7828e3.js" defer=""></script><script src="./_next/static/chunks/pages/index-85192d51d3aa6df8.js" defer=""></script><script src="./_next/static/F195PZl4yn18BfMZaSMUr/_buildManifest.js" defer=""></script><script src="./_next/static/F195PZl4yn18BfMZaSMUr/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><div id="settings-container"></div><div id="notifications-container"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/","query":{},"buildId":"F195PZl4yn18BfMZaSMUr","assetPrefix":".","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="./_next/static/css/5c49298423df7aa9.css" as="style"/><link rel="stylesheet" href="./_next/static/css/5c49298423df7aa9.css" data-n-g=""/><link rel="preload" href="./_next/static/css/8b914e4a9001ee1d.css" as="style"/><link rel="stylesheet" href="./_next/static/css/8b914e4a9001ee1d.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="./_next/static/chunks/webpack-e50e9853db18b759.js" defer=""></script><script src="./_next/static/chunks/framework-2c79e2a64abdb08b.js" defer=""></script><script src="./_next/static/chunks/main-2ba37e62325cc71b.js" defer=""></script><script src="./_next/static/chunks/pages/_app-77983e68be50f72a.js" defer=""></script><script src="./_next/static/chunks/743-fd706aeabb7828e3.js" defer=""></script><script src="./_next/static/chunks/pages/index-697895d5144433b5.js" defer=""></script><script src="./_next/static/t9NOr8PuVZjocZMRyrerF/_buildManifest.js" defer=""></script><script src="./_next/static/t9NOr8PuVZjocZMRyrerF/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><div id="settings-container"></div><div id="notifications-container"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/","query":{},"buildId":"t9NOr8PuVZjocZMRyrerF","assetPrefix":".","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>

View file

@ -2,11 +2,13 @@ import { useState, useEffect } from "react";
import classNames from "classnames";
import Toggle from "../toggle/toggle";
import { useDataContext } from "@/context/data-context";
import styles from "news-site-css/dist/dialog.module.css";
export default function Dialog({ onClose }) {
const [isChecked, setIsChecked] = useState(false);
const { settings } = useDataContext();
useEffect(() => {
setIsChecked(document.body.classList.contains("reduced-motion"));
@ -32,11 +34,11 @@ export default function Dialog({ onClose }) {
</div>
</button>
<header className={styles["dialog-header"]}>
<h2>Settings</h2>
<h2>{settings.header}</h2>
</header>
<section className={styles["dialog-body"]}>
<div className={styles["dialog-item"]}>
<Toggle label="Reduced Motion" onChange={handleChange} checked={isChecked} />
<Toggle label={settings.items.motion.label} onChange={handleChange} checked={isChecked} />
</div>
</section>
</div>

View file

@ -1,12 +1,13 @@
import { useState } from "react";
import classNames from "classnames";
import { more } from "@/data/buttons";
import { useDataContext } from "@/context/data-context";
import styles from "news-site-css/dist/dropdown.module.css";
export default function Dropdown({ children, animatedIconClass }) {
const [isOpen, setIsOpen] = useState(false);
const { buttons } = useDataContext();
function handleChange(e) {
setIsOpen(e.target.checked);
@ -20,7 +21,7 @@ export default function Dropdown({ children, animatedIconClass }) {
<div className={styles.dropdown}>
<input type="checkbox" id="navbar-dropdown-toggle" className={styles["dropdown-toggle"]} onChange={handleChange} checked={isOpen} />
<label htmlFor="navbar-dropdown-toggle" className={styles["dropdown-label"]}>
<span className={styles["dropdown-label-text"]}>{more.label}</span>
<span className={styles["dropdown-label-text"]}>{buttons.more.label}</span>
<div className={classNames("animated-icon", "arrow-icon", "arrow", animatedIconClass)}>
<span className="animated-icon-inner" title="Arrow Icon">
<span></span>

View file

@ -1,10 +1,12 @@
import { content } from "@/data/content";
import { useDataContext } from "@/context/data-context";
import Dropdown from "../dropdown/dropdown";
import NavListItem from "./navlist-item";
import styles from "news-site-css/dist/navbar.module.css";
export default function NavList({ callback, id }) {
const { content } = useDataContext();
const navItems = [];
const dropdownItems = [];

View file

@ -1,12 +1,15 @@
import classNames from "classnames";
import { content } from "@/data/content";
import { useDataContext } from "@/context/data-context";
import { NavLink } from "react-router-dom";
import { HashLink } from "react-router-hash-link";
import styles from "news-site-css/dist/sitemap.module.css";
export default function Sitemap() {
const { content } = useDataContext();
const keys = Object.keys(content);
const navItems = keys.reduce((result, key) => {
result.push(key);

View file

@ -0,0 +1,46 @@
import { createContext, useContext } from "react";
import { content as contentEn } from "@/data/en/content";
import { settings as settingsEn } from "@/data/en/dialog";
import { footer as footerEn } from "@/data/en/footer";
import * as buttonsEn from "@/data/en/buttons";
import * as linksEn from "@/data/en/links";
const strings = {
en: {
content: contentEn,
settings: settingsEn,
footer: footerEn,
buttons: buttonsEn,
links: linksEn,
},
};
const DataContext = createContext(null);
export const DataContextProvider = ({ children }) => {
const defaultLanguage = "en";
const urlParams = new URLSearchParams(window.location.search);
const dir = urlParams.get("dir") ?? "ltr";
const langFromUrl = urlParams.get("lang");
const lang = langFromUrl && langFromUrl in strings ? langFromUrl : defaultLanguage;
document.documentElement.setAttribute("dir", dir);
document.documentElement.setAttribute("lang", lang);
const value = {
lang,
dir,
...strings[lang],
};
return <DataContext.Provider value={value}>{children}</DataContext.Provider>;
};
export const useDataContext = () => {
const dataContext = useContext(DataContext);
if (!dataContext)
throw new Error("A DataProvider must be rendered before using useDataContext");
return dataContext;
};

View file

@ -151,7 +151,7 @@ export const content = {
meta: {
captions: "Photo taken by someone.",
},
title: "Volutpat est velit egestas dui id ornare arcu.",
title: "Nunc felis tellus, ultrices eget massa ac, lobortis laoreet lorem.",
type: "list",
content: [
{
@ -454,7 +454,7 @@ export const content = {
"Orci ac auctor augue mauris augue neque gravida. Lectus magna fringilla urna porttitor rhoncus dolor purus non enim. Sagittis aliquam malesuada bibendum arcu vitae. Pellentesque habitant morbi tristique senectus et netus. Etiam erat velit scelerisque in dictum non consectetur a.",
},
{
title: "Netus et malesuada fames ac turpis egestas maecenas pharetra.",
title: "Suspendisse convallis efficitur felis ac mattis. Cras faucibus ultrices condimentum.",
content:
"Facilisis leo vel fringilla est. Turpis tincidunt id aliquet risus feugiat in ante metus. Viverra ipsum nunc aliquet bibendum enim facilisis. Tristique et egestas quis ipsum suspendisse ultrices gravida dictum. Tristique senectus et netus et malesuada fames ac turpis egestas.",
},

View file

@ -0,0 +1,8 @@
export const settings = {
header: "Settings",
items: {
motion: {
label: "Reduced Motion",
},
},
};

View file

@ -0,0 +1,5 @@
export const footer = {
copyright: {
label: "all rights reserved!",
},
};

View file

@ -38,3 +38,9 @@ export const legal = {
target: "external",
},
};
export const a11y = {
skip: {
label: "Skip to content",
},
};

View file

@ -2,6 +2,7 @@ import React from "react";
import { HashRouter as Router, Routes, Route } from "react-router-dom";
import Page from "@/partials/page/page";
import Head from "next/head";
import { DataContextProvider } from "@/context/data-context";
export default function App() {
return (
@ -10,18 +11,20 @@ export default function App() {
<title>The Daily Broadcast</title>
<meta name="description" content="A news site developed with Next.js." key="description" />
</Head>
<Router>
<Routes>
<Route path="/business" element={<Page id="business" />} />
<Route path="/health" element={<Page id="health" />} />
<Route path="/opinion" element={<Page id="opinion" />} />
<Route path="/politics" element={<Page id="politics" />} />
<Route path="/us" element={<Page id="us" />} />
<Route path="/world" element={<Page id="world" />} />
<Route path="/home" element={<Page id="home" />} />
<Route path="/" element={<Page id="home" />} />
</Routes>
</Router>
<DataContextProvider>
<Router>
<Routes>
<Route path="/business" element={<Page id="business" />} />
<Route path="/health" element={<Page id="health" />} />
<Route path="/opinion" element={<Page id="opinion" />} />
<Route path="/politics" element={<Page id="politics" />} />
<Route path="/us" element={<Page id="us" />} />
<Route path="/world" element={<Page id="world" />} />
<Route path="/home" element={<Page id="home" />} />
<Route path="/" element={<Page id="home" />} />
</Routes>
</Router>
</DataContextProvider>
</>
);
}

View file

@ -4,12 +4,13 @@ import Dialog from "@/components/dialog/dialog";
import SettingsIcons from "../icons/settings-icons";
import SocialIcons from "../icons/social-icons";
import Sitemap from "@/components/sitemap/sitemap";
import { legal } from "@/data/links";
import { useDataContext } from "@/context/data-context";
import styles from "news-site-css/dist/footer.module.css";
export default function Footer() {
const [showPortal, setShowPortal] = useState(false);
const { footer, links } = useDataContext();
function openPortal() {
setShowPortal(true);
@ -31,8 +32,8 @@ export default function Footer() {
<div className={styles["footer-column-center"]}>
<div className={styles["footer-links"]}>
<ul className={styles["footer-links-list"]}>
{Object.keys(legal).map((key) => {
const item = legal[key];
{Object.keys(links.legal).map((key) => {
const item = links.legal[key];
return (
<li className={styles["footer-links-item"]} key={`footer-links-item-${key}`}>
<a href={item.href} id={`footer-link-${key}`} className={styles["footer-link"]}>
@ -49,7 +50,9 @@ export default function Footer() {
<div className={styles["footer-column-left"]}>
<SocialIcons id="footer-social-icons" />
</div>
<div className={styles["footer-column-center"]}>© {new Date().getFullYear()} No Rights Reserved</div>
<div className={styles["footer-column-center"]}>
© {new Date().getFullYear()} {footer.copyright.label}
</div>
<div className={styles["footer-column-right"]}>
<SettingsIcons onClick={openPortal} id="footer-settings-icons" />
</div>

View file

@ -2,30 +2,32 @@ import FacebookIcon from "@/assets/facebook-icon";
import InstagramIcon from "@/assets/instagram-icon";
import TwitterIcon from "@/assets/twitter-icon";
import { social } from "@/data/links";
import { useDataContext } from "@/context/data-context";
import styles from "news-site-css/dist/icons-group.module.css";
export default function SocialIcons({ id }) {
const { links } = useDataContext();
return (
<div className={styles["icons-group"]}>
<ul className={styles["icons-group-list"]}>
<li className={styles["icons-group-item"]}>
<a href={social.facebook.href} id={`${id}-facebook`}>
<a href={links.social.facebook.href} id={`${id}-facebook`}>
<div className={styles["group-icon"]}>
<FacebookIcon />
</div>
</a>
</li>
<li className={styles["icons-group-item"]}>
<a href={social.instagram.href} id={`${id}-instagram`}>
<a href={links.social.instagram.href} id={`${id}-instagram`}>
<div className={styles["group-icon"]}>
<InstagramIcon />
</div>
</a>
</li>
<li className={styles["icons-group-item"]}>
<a href={social.twitter.href} id={`${id}-twitter`}>
<a href={links.social.twitter.href} id={`${id}-twitter`}>
<div className={styles["group-icon"]}>
<TwitterIcon />
</div>

View file

@ -6,14 +6,15 @@ import Header from "../header/header";
import Navigation from "../navigation/navigation";
import Main from "../main/main";
import Footer from "../footer/footer";
import { content } from "@/data/content";
import { Message } from "@/components/message/message";
import { useDataContext } from "@/context/data-context";
import styles from "news-site-css/dist/layout.module.css";
export default function Layout({ children, id }) {
const [showMessage, setShowMessage] = useState(false);
const { content, links } = useDataContext();
useEffect(() => {
setShowMessage(content[id].message);
@ -33,7 +34,7 @@ export default function Layout({ children, id }) {
return (
<>
<HashLink to={`${pathname}#content`} className="skip-link">
Skip to content
{links.a11y.skip.label}
</HashLink>
<div className={styles.page} ref={pageRef}>
<Header />

View file

@ -3,13 +3,14 @@ import classNames from "classnames";
import Navbar from "../../components/navbar/navbar";
import { login } from "@/data/buttons";
import { useDataContext } from "@/context/data-context";
import navStyles from "news-site-css/dist/nav.module.css";
import buttonStyles from "news-site-css/dist/button.module.css";
export default function Navigation() {
const navigate = useNavigate();
const { buttons } = useDataContext();
function callback() {
navigate("/");
@ -28,7 +29,7 @@ export default function Navigation() {
</div>
<div className={navStyles["page-navigation-column-right"]}>
<button id="login-button" className={classNames(buttonStyles.button, buttonStyles["secondary-button"], navStyles["nav-button"])} onClick={logIn}>
{login.label}
{buttons.login.label}
</button>
</div>
</div>

View file

@ -5,10 +5,11 @@ import Layout from "@/partials/layout/layout";
import Section from "../section/section";
import Toast from "@/components/toast/toast";
import { content } from "@/data/content";
import { useDataContext } from "@/context/data-context";
export default function Page({ id }) {
const [showPortal, setShowPortal] = useState(false);
const { content } = useDataContext();
useEffect(() => {
setShowPortal(content[id].notification);

View file

@ -473,7 +473,7 @@ Suites.push({
Suites.push({
name: "NewsSite-Next",
url: "newssite/news-next/dist/index.html#/home",
tags: ["newssite"],
tags: ["newssite", "language"],
async prepare(page) {
await page.waitForElement("#navbar-dropdown-toggle");
},