Skip to content

About

The web site for the App Fair Project home page at https://appfair.org

Resources

Stars

2 stars

Watchers

1 watching

Forks

Repository files navigation

appfair.org

The source for the App Fair Project website: a static site built with Astro and deployed to GitHub Pages by .github/workflows/.

Editorial style

Follow STYLE.md for project naming and site prose.

Local development

Requires Node 22.12 or newer.

npm install
npm run dev       # http://localhost:4321, with hot reload
npm run build     # production build into dist/, then the Pagefind search index
npm run preview   # serve dist/ (search only works here and in production, not in dev)

Structure

astro.config.mjs        site URL, i18n routing, markdown pipeline
src/
├── content/
│   ├── blog/           blog posts (markdown; the file name is the URL slug)
│   └── pages/          standalone pages, served at /<path>/ (marketplace/, imprint, privacy, …)
├── content.config.ts   the two collections' frontmatter schemas
├── i18n/               en.json and one JSON table per locale, plus the t() helper
├── layouts/            BaseLayout: <head>, nav, footer, theme + design bootstrap
├── components/         Nav, Footer, ThemeToggle, LangSwitcher, Search, …
├── pages/              routes: index, blog/, blog/[slug], blog/rss.xml, [...slug], og/, 404
├── styles/             global.css (system), themes.css (styles × light/dark), layouts.css
└── lib/                site constants (URLs, social links, stores), post helpers
public/                 static assets (icons, store badges, images, the App Index schema)

Localization

Every string in the site chrome and on the homepage is looked up by key from src/i18n/<locale>.json, falling back to en.json for any key a locale has not translated. To translate more of the site, add keys to the locale file; to add a locale, add it to src/i18n/locales.mjs and create its JSON.

Locale routes (/fr/…, /de/…, …) exist for every page. Pages without a translated copy — the blog and the policy pages today — render their English content under the locale prefix with localized chrome (Astro's i18n fallback with fallbackType: 'rewrite'). A translated page would be a localized copy of the markdown file; wiring that up is the next step when translations arrive.

English content pages, developer guides and blog listings/posts use TranslationNotice.astro to show a compact notice in the selected language on non-English routes. Its copy lives in page.translationNotice in every locale table. Translated pages such as the homepage and donation page omit it. When adding translated content, omit the notice for that content as well.

Shared navigation, footer, accessibility labels, developer navigation and copy controls use the locale tables too. Service labels live under footer.social; retain brand spellings unless a conventional local name exists. Article text and documentation examples remain in their source language.

src/middleware.ts localizes rendered links to known site pages, including Markdown and MDX links, before the HTML is served or built. Assets, downloads, RSS, external URLs, fragment-only links and language-switcher links remain unchanged. Add data-keep-language to an anchor to explicitly keep an unprefixed link. Search results and interactive guide links use the same URL rules in the browser. Run npm test for URL and translation coverage, and tests/localization.browser.mjs against a production preview to check navigation, search and layouts with and without JavaScript.

Design picker (development only)

The site's design is Fairground (style) + Split (layout), set as design in src/lib/site.ts. In npm run dev a Design button in the bottom-right corner switches between the alternative styles and layouts that were built for comparison. The homepage hero is text-only; the retained graphic options have no effect. It sets data-style / data-layout / data-visual on <html>, remembers the choice in localStorage, and honours ?style=…&layout=…&visual=…&theme=… in the URL. Production builds (npm run build, and so the deployed site) render neither the picker nor its bootstrap script, so they always show the default.

To retire the alternatives: delete src/components/DesignPicker.astro, its two showPicker includes in BaseLayout.astro, designOptions in src/lib/site.ts, the non-default variants in HeroVisual.astro, and the unused blocks in themes.css and layouts.css.

Search

Pagefind indexes dist/ after the build (npm run build). Only default-locale pages carry data-pagefind-body, and the index is forced to one language, so a visitor on any locale searches the whole (English) site.

Website analytics

Production pages load GoatCounter from the shared BaseLayout.astro, using https://appfair.goatcounter.com/count. The dashboard is at appfair.goatcounter.com; no API key is needed in the site. The script is omitted in development, and GoatCounter ignores localhost previews by default. The website privacy policy describes the analytics.

License

The App Fair Project © 2026 by the App Fair is licensed under CC BY-SA 4.0.

Developer documentation

src/content/pages/docs/ supplies /docs/, linked as Developers in the header. MDX pages embed SubmissionFlow.astro (linked SVG) and SubmissionStep.astro. The checklist's command generation, input validation and versioned local-storage parsing live in src/lib/submission.mjs. Run npm test for their regression tests. No commands are executed by the checklist.

SubmissionGuide.astro renders a normal single-column document. Each SubmissionStep.astro contains one numbered heading, explanatory prose, and its actions and reference links. The same step component renders the personalized commands. The overview and section anchors use native page scrolling; there are no nested scrolling panes or synchronization handlers.

SubmissionForm.astro initializes submission-checklist.ts, which updates commands, validates input and saves app details. SubmissionValue.astro updates prose identities through submission-state.ts and submission-values.mjs. Commands live in submission.mjs; keep guide step IDs matched to stepIds. The obsolete /docs/checklist/ route has been removed.

The policy pages are /app-rules/ for users and /docs/inclusion-criteria/ for developers. Keep their requirements aligned; the developer page holds submission details.

Docs use the normal content collection, localized fallback routes, sitemap and Pagefind build. Use npm run build followed by npm run preview to test search; Astro dev does not build its index. When changing the submission process, check the standard Day scaffold, shared Day CI workflow and catalog workflow before updating command examples. Generated checklist commands assume a personal catalog fork.

With Playwright available, run the end-to-end checks against the preview server:

SITE_URL=http://127.0.0.1:4323 node tests/guide.browser.mjs
SITE_URL=http://127.0.0.1:4323 node tests/instruction-tabs.browser.mjs
SITE_URL=http://127.0.0.1:4323 node tests/releases.browser.mjs
SITE_URL=http://127.0.0.1:4323 node tests/policies.browser.mjs
# Set PLAYWRIGHT_MODULE to a package path if Playwright is installed outside this checkout.

Admonitions

Use GitHub-style alerts in Markdown or MDX. The shared renderer supplies a label, icon and light/dark colors. Ordinary blockquotes remain quotations.

> [!INFO] iOS testing in CI
> GitHub CI can run iOS tests and capture screenshots.

Supported types: NOTE (context), INFO (platform facts), TIP (shortcuts), IMPORTANT (requirements), WARNING (likely mistakes), and CAUTION (irreversible changes). The optional title is plain text. The body supports normal Markdown, including links, lists and code blocks. Use callouts for exceptions and supporting advice; keep the main instructions in the guide.

For Astro components or interactive MDX, use the equivalent component:

import Admonition from '../components/Admonition.astro';

<Admonition kind="info" title="iOS testing in CI" id="ios-ci-note">
  GitHub CI can run iOS tests and capture screenshots.
</Admonition>

src/lib/admonitions.mjs defines the variants and icons. rehype-admonitions.mjs renders Markdown alerts; Admonition.astro renders component callouts. Both use the site-wide styles in src/styles/admonitions.css. Static callouts use role="note", not an interrupting live alert.

Copyable code samples

Markdown fenced code blocks automatically get a floating copy button. In Astro or MDX, use CodeBlock.astro for generated examples:

import CodeBlock from './components/CodeBlock.astro';
<CodeBlock code="day launch" label="Copy launch command" />

CodeCopy.astro is included by BaseLayout.astro; it shares the button template, styles and clipboard handler across both forms. Code remains selectable without JavaScript. A successful copy shows a checkmark and “Copied” for two seconds. Clipboard failure selects the text and shows manual-copy instructions instead. Copying reads the current code text, including edits to generated commands, and preserves whitespace. Add data-no-copy to a pre or an ancestor to opt out. Inline code is unaffected.

Token availability

The app token field checks https://api.github.com/users/{token} after 600 ms without an edit. This unauthenticated endpoint resolves both users and organizations and supports CORS. Green means a 404 (apparently available), red means an existing account, blue means checking, and amber means the check failed. GitHub can still reserve or reject a name at creation. Results are cached in memory for five minutes; obsolete requests are aborted and ignored. Checks time out after eight seconds and pause on API rate limits. They never block the guide or request credentials. Invalid tokens do not trigger requests.

Alternative instructions

InstructionTabs.astro presents a step's methods as keyboard-accessible tabs. Each method can contain a command, operation links, and ordered instructions; commands are optional for browser-only steps. The first method is selected initially; arrow keys, Home and End switch methods. App-detail edits update both panels without changing the selected tab. Without JavaScript, or when printed, both methods remain visible. Each panel uses the shared CodeBlock copy control.

Linked section headings

Use SectionHeading.astro in MDX for an explicit, short section anchor:

import SectionHeading from '../../../components/SectionHeading.astro';

<SectionHeading id="distribution" title="Does the App Fair require exclusivity?" />

The heading defaults to H2 (level={3} or level={4} selects a lower level). Its link icon appears on hover or keyboard focus, stays visible on touch devices, and works without JavaScript. Keep the ID stable when changing the question. FAQ entries use this component in src/content/pages/docs/faq.mdx.

About

The web site for the App Fair Project home page at https://appfair.org

Resources

Stars

2 stars

Watchers

1 watching

Forks

Used by

Contributors

Languages