Skip to content
Open
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
115 changes: 95 additions & 20 deletions src/components/SiteFooter.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,132 @@
import { createLink } from "@tanstack/react-router";
import { useTranslation } from "react-i18next";

import type { Locale } from "../lib/locale";

import { Footer } from "../design-system/footer";
import { Link } from "../design-system/link";
import { useLocale } from "../lib/LocaleContext";
import { AtStoreLogo } from "./AtStoreLogo";

const FooterLink = createLink(Link);

const FOOTER_LINK_GROUPS = [
type LocaleLink = {
kind: "locale";
to: "/$locale" | "/$locale/about";
tKey: string;
};
type SearchLink = {
kind: "search";
to: "/search" | "/apps/all";
search: { sort: "popular" };
tKey: string;
};
type PlainLink = {
kind: "plain";
to:
| "/developers/atproto"
| "/products/manage"
| "/apps/tags"
| "/apps/lexicons";
tKey: string;
};
type FooterLinkDef = LocaleLink | SearchLink | PlainLink;

const LINK_GROUPS: Array<{ titleKey?: string; links: Array<FooterLinkDef> }> = [
{
links: [
{ href: "/about", label: "About" },
{ href: "/home", label: "Home" },
{ href: "/search", label: "Search" },
{ href: "/developers/atproto", label: "Developer API" },
{ href: "/products/manage", label: "Manage listings" },
{ kind: "locale", to: "/$locale/about", tKey: "siteFooter.nav.about" },
{ kind: "locale", to: "/$locale", tKey: "siteFooter.nav.home" },
{
kind: "search",
to: "/search",
search: { sort: "popular" },
tKey: "siteFooter.nav.search",
},
{
kind: "plain",
to: "/developers/atproto",
tKey: "siteFooter.nav.developerApi",
},
{
kind: "plain",
to: "/products/manage",
tKey: "siteFooter.nav.manageListings",
},
],
},
{
title: "Apps",
titleKey: "siteFooter.apps.groupTitle",
links: [
{ href: "/apps/all", label: "All Apps" },
{ href: "/apps/tags", label: "Categories" },
{ href: "/apps/lexicons", label: "Shared data" },
{
kind: "search",
to: "/apps/all",
search: { sort: "popular" },
tKey: "siteFooter.apps.allApps",
},
{ kind: "plain", to: "/apps/tags", tKey: "siteFooter.apps.categories" },
{
kind: "plain",
to: "/apps/lexicons",
tKey: "siteFooter.apps.sharedData",
},
],
},
] as const;
];

function renderLink(link: FooterLinkDef, locale: Locale, label: string) {
switch (link.kind) {
case "locale": {
return (
<FooterLink key={link.to} to={link.to} params={{ locale }}>
{label}
</FooterLink>
);
}
case "search": {
return (
<FooterLink key={link.to} to={link.to} search={link.search}>
{label}
</FooterLink>
);
}
case "plain": {
return (
<FooterLink key={link.to} to={link.to}>
{label}
</FooterLink>
);
}
}
}

export function SiteFooter() {
const { locale } = useLocale();
const { t } = useTranslation("common");

return (
<Footer.Root>
<Footer.Section>
<Footer.Logo>
<AtStoreLogo />
</Footer.Logo>
<Footer.NavSection>
{FOOTER_LINK_GROUPS.map((group, index) => (
{LINK_GROUPS.map((group, i) => (
<Footer.NavGroup
key={"title" in group ? group.title : `links-${index}`}
title={"title" in group ? group.title : undefined}
key={i}
title={group.titleKey ? t(group.titleKey as never) : undefined}
>
{group.links.map((link) => (
<FooterLink key={link.href} to={link.href as never}>
{link.label}
</FooterLink>
))}
{group.links.map((link) =>
renderLink(link, locale, t(link.tKey as never)),
)}
</Footer.NavGroup>
))}
</Footer.NavSection>
</Footer.Section>

<Footer.Section>
<Footer.Copyright>
{new Date().getFullYear()} at-store Copyright. All rights reserved.
{t("siteFooter.copyright", { year: new Date().getFullYear() })}
</Footer.Copyright>
</Footer.Section>
</Footer.Root>
Expand Down
9 changes: 8 additions & 1 deletion src/components/SiteHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Flex } from "../design-system/flex";
import { IconButton } from "../design-system/icon-button";
import { Navbar, NavbarAction, NavbarLogo } from "../design-system/navbar";
import { fontSize } from "../design-system/theme/typography.stylex";
import { useLocale } from "../lib/LocaleContext";
import { AtStoreLogo } from "./AtStoreLogo";
import { LanguageSwitcher } from "./LanguageSwitcher";
import { NavbarAuth } from "./NavbarAuth";
Expand All @@ -30,6 +31,7 @@ const styles = stylex.create({
});

export function SiteHeader() {
const { locale } = useLocale();
const { data: session } = useQuery(user.getSessionQueryOptions);
const { data: notifications } = useQuery({
...notificationApi.getProductNotificationsQueryOptions({ limit: 50 }),
Expand All @@ -43,7 +45,12 @@ export function SiteHeader() {

return (
<Navbar hideHamburgerButton={true}>
<NavbarLogoLink to="/" style={styles.logoContent} hasUnderline={false}>
<NavbarLogoLink
to="/$locale"
params={{ locale }}
style={styles.logoContent}
hasUnderline={false}
>
<AtStoreLogo variant="navbar" />
</NavbarLogoLink>

Expand Down
2 changes: 1 addition & 1 deletion src/i18n/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export {
* different surfaces in parallel. `common` is for site-wide chrome (header,
* footer, switcher); page-specific surfaces get their own namespace.
*/
export const NAMESPACES = ["common", "about"] as const;
export const NAMESPACES = ["common", "about", "home"] as const;
export type Namespace = (typeof NAMESPACES)[number];

export const DEFAULT_NAMESPACE: Namespace = "common";
16 changes: 16 additions & 0 deletions src/i18n/locales/en-XA/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,21 @@
"en": "[~~ Éñĝļîšĥ ~~]",
"en-XA": "[~~ Þšéüðö (éñ-ẊÅ) ~~]"
}
},
"siteFooter": {
"copyright": "[~~~~ {{year}} åţ-šţöŕé Çöþýŕîĝĥţ. Åļļ ŕîĝĥţš ŕéšéŕṽéð. ~~~~]",
"nav": {
"about": "[~~ Åƀöüţ ~~]",
"home": "[~~ Ĥöḿé ~~]",
"search": "[~~ Šéåŕçĥ ~~]",
"developerApi": "[~~ Ðéṽéļöþéŕ ÅÞÎ ~~]",
"manageListings": "[~~ Ḿåñåĝé ļîšţîñĝš ~~]"
},
"apps": {
"groupTitle": "[~~ Åþþš ~~]",
"allApps": "[~~ Åļļ Åþþš ~~]",
"categories": "[~~ Çåţéĝöŕîéš ~~]",
"sharedData": "[~~ Šĥåŕéð ðåţå ~~]"
}
}
}
34 changes: 34 additions & 0 deletions src/i18n/locales/en-XA/home.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"ogTitle": "[~~~ åţ-šţöŕé | Åþþš öñ ţĥé Åţḿöšþĥéŕé ~~~]",
"ogDescription": "[~~~~ Ðîšçöṽéŕ åþþš åñð ţööļš åçŕöšš ţĥé Åţḿöšþĥéŕé. Ƒîñð ýöüŕ ñéẋţ ƒåṽöŕîţé åþþ ţöðåý! ~~~~]",
"hero": {
"eyebrow": "[~~ Ţĥé ÅŢ Þŕöţöçöļ åþþ ðîŕéçţöŕý ~~]",
"title": "[~~ Åþþš öñ ţĥé Åţḿöšþĥéŕé ~~]",
"description": "[~~~~ Ðîšçöṽéŕ ţĥé ƀéšţ åþþš ţĥé Åţḿöšþĥéŕé ĥåš ţö öƒƒéŕ. Ŵîţĥ éṽéŕý þŕöðüçţ ýöü öŵñ ýöüŕ ðåţå åñð üšé ţĥé šåḿé îðéñţîţý åçŕöšš åļļ åþþš. ~~~~]"
},
"claimBanner": {
"title_one": "[~~ Çļåîḿ ýöüŕ ļîšţîñĝ ~~]",
"title_other": "[~~ Çļåîḿ ýöüŕ ļîšţîñĝš ~~]",
"continue": "[~~ Çöñţîñüé ~~]",
"body_one": "[~~~~ \"{{name}}\" îš šţîļļ öñ ţĥé šţöŕé ŕéþö. Çļåîḿ îţ ţö ḿåñåĝé üþðåţéš ƒŕöḿ ýöüŕ ÞЊ. ~~~~]",
"body_other": "[~~~~ Ýöü ĥåṽé {{count}} ļîšţîñĝš öñ ţĥé šţöŕé ŕéþö. Çļåîḿ ţĥéḿ ţö ḿåñåĝé üþðåţéš ƒŕöḿ ýöüŕ ÞЊ. ~~~~]"
},
"browseSection": {
"eyebrow": "[~~ ßŕöŵšé Åþþš ~~]",
"title": "[~~ Ƒîñð åþþš ýöü'ļļ ļöṽé ~~]"
},
"popularSection": {
"eyebrow": "[~~ Þöþüļåŕ Ŕîĝĥţ Ñöŵ ~~]",
"title": "[~~ Ţŕéñðîñĝ åçŕöšš ţĥé éçöšýšţéḿ ~~]"
},
"newSection": {
"eyebrow": "[~~ Ñéŵ & Ñöţéŵöŕţĥý ~~]",
"title": "[~~ Ƒŕéšĥ åþþš ĵüšţ åððéð ~~]"
},
"sectionHeader": {
"seeAll": "[~~ Šéé Åļļ ~~]"
},
"popularItem": {
"explore": "[~~ Éẋþļöŕé ~~]"
}
}
16 changes: 16 additions & 0 deletions src/i18n/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,21 @@
"en": "English",
"en-XA": "Pseudo (en-XA)"
}
},
"siteFooter": {
"copyright": "{{year}} at-store Copyright. All rights reserved.",
"nav": {
"about": "About",
"home": "Home",
"search": "Search",
"developerApi": "Developer API",
"manageListings": "Manage listings"
},
"apps": {
"groupTitle": "Apps",
"allApps": "All Apps",
"categories": "Categories",
"sharedData": "Shared data"
}
}
}
34 changes: 34 additions & 0 deletions src/i18n/locales/en/home.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"ogTitle": "at-store | Apps on the Atmosphere",
"ogDescription": "Discover apps and tools across the Atmosphere. Find your next favorite app today!",
"hero": {
"eyebrow": "The AT Protocol app directory",
"title": "Apps on the Atmosphere",
"description": "Discover the best apps the Atmosphere has to offer. With every product you own your data and use the same identity across all apps."
},
"claimBanner": {
"title_one": "Claim your listing",
"title_other": "Claim your listings",
"continue": "Continue",
"body_one": "\"{{name}}\" is still on the store repo. Claim it to manage updates from your PDS.",
"body_other": "You have {{count}} listings on the store repo. Claim them to manage updates from your PDS."
},
"browseSection": {
"eyebrow": "Browse Apps",
"title": "Find apps you'll love"
},
"popularSection": {
"eyebrow": "Popular Right Now",
"title": "Trending across the ecosystem"
},
"newSection": {
"eyebrow": "New & Noteworthy",
"title": "Fresh apps just added"
},
"sectionHeader": {
"seeAll": "See All"
},
"popularItem": {
"explore": "Explore"
}
}
6 changes: 4 additions & 2 deletions src/i18n/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import type { Namespace } from "./config";

import enXAAbout from "./locales/en-XA/about.json";
import enXACommon from "./locales/en-XA/common.json";
import enXAHome from "./locales/en-XA/home.json";
import enAbout from "./locales/en/about.json";
import enCommon from "./locales/en/common.json";
import enHome from "./locales/en/home.json";

export const resources: Record<string, Record<Namespace, unknown>> = {
en: { common: enCommon, about: enAbout },
en: { common: enCommon, about: enAbout, home: enHome },
// en-XA is a dev-only pseudo-locale. Rollup replaces import.meta.env.DEV
// with `false` in prod and tree-shakes the dead branch + JSON assets.
...(import.meta.env.DEV
? { "en-XA": { common: enXACommon, about: enXAAbout } }
? { "en-XA": { common: enXACommon, about: enXAAbout, home: enXAHome } }
: {}),
};
Loading
Loading