Skip to content

Repository files navigation

morphicblocks.com

Landing page for Morphic Blocks — the marketing/entry site at https://morphicblocks.com. Built with Astro.

Docs (docs.morphicblocks.com) and the interactive playground (playground.morphicblocks.com) live in separate repos.

Develop

bun install
bun run dev      # local dev server
bun run build    # static build to ./dist
bun run preview  # preview the built site

Configuration

Every switchable value (site name, tagline, university, and all links) is an environment variable — nothing is hardcoded in components. Change them in one place and the whole site updates.

cp .env.example .env   # then edit .env
Variable Purpose
PUBLIC_SITE_NAME Brand name in header/footer/title
PUBLIC_SITE_URL Canonical site URL (canonical tags, sitemap, link previews)
PUBLIC_SITE_TAGLINE Footer tagline
PUBLIC_SITE_DESCRIPTION <meta description>
PUBLIC_UNIVERSITY Footer attribution (hidden if empty)
PUBLIC_UNIVERSITY_DE German name of the organization, used on /de/
PUBLIC_UNIVERSITY_URL Link target of the footer attribution
PUBLIC_NPM_PACKAGE Package name in the install command
PUBLIC_NPM_URL "View on npm" link
PUBLIC_DOCS_URL Docs link
PUBLIC_PLAYGROUND_URL Playground link
PUBLIC_GITHUB_URL Repository link
PUBLIC_IMPRINT_URL Imprint link
PUBLIC_PRIVACY_URL Privacy link
PUBLIC_DISCLAIMER_URL Disclaimer (Haftungsausschluss) link
PUBLIC_IMPRINT_URL_EN English imprint, if a translated page exists
PUBLIC_PRIVACY_URL_EN English privacy page, if one exists
PUBLIC_DISCLAIMER_URL_EN English disclaimer, if one exists

These are build-time PUBLIC_* vars baked into the static output. On Cloudflare Pages, set them in the project's environment variables. Reading happens in one place: src/config.ts.

Structure

public/            # static assets served as-is
  logo.svg         # PLACEHOLDER logo, replace with the real mark
  favicon.svg
  modes/           # one capture per mode, paired by order with i18n/ui.ts
  screenshots/     # every image here appears in the slider, see below
src/
  config.ts        # single source for all env-driven values
  env.d.ts         # typed env vars
  i18n/ui.ts       # display strings, per language
  i18n/utils.ts    # language detection and locale-aware paths
  data/screenshots.json  # optional slider captions, keyed by filename
  layouts/Base.astro
  components/Header.astro, Footer.astro, Landing.astro
  pages/index.astro      # English (default, unprefixed)
  pages/de/index.astro   # German
  styles/global.css   # design tokens — restyle the site from here

Languages

English is the default and lives at /; German lives at /de/. The header has a language toggle styled like the theme toggle: it shows the language it switches to (DE on the English page) and links to the current page in that language. With only two languages it reads as a toggle; if more are added it cycles through them, and a list or dropdown would suit better.

All display copy sits in src/i18n/ui.ts, one entry per language. English takes its tagline and description from the PUBLIC_SITE_TAGLINE / PUBLIC_SITE_DESCRIPTION variables so .env stays the source for those; everything else is literal text. src/i18n/ui.ts types the German entry against the English one, so a missing key is a type error rather than a blank spot on the page.

Both locales render the same components/Landing.astro, so markup and styles are written once. To add a language: add an entry to ui.ts, list its code in languages, add it to i18n.locales in astro.config.mjs, and create src/pages/<code>/index.astro mirroring the German page. Code samples stay in English.

Screenshots

The slider shows every image in public/screenshots/, so adding a capture is a matter of dropping the file in. Files are ordered by name, so prefix them (01-, 02-) when the order matters.

Captions are optional. src/data/screenshots.json maps a filename to alt text and a caption per language; a file with no entry still appears, with a generic alt and no caption. The slider is CSS scroll-snap with no JavaScript, so it works with any number of images, one included: with a single image the "scroll or swipe" hint is not rendered, and with none the section is dropped entirely.

Notes

  • The logo (public/logo.svg) is a placeholder — replace the file to swap it everywhere.
  • Imprint / Privacy / Disclaimer point wherever PUBLIC_IMPRINT_URL, PUBLIC_PRIVACY_URL and PUBLIC_DISCLAIMER_URL say. Each has an optional _EN counterpart used on the English pages; leave it empty when no translated page exists and both languages fall back to the base URL.
  • A link whose PUBLIC_* variable is unset or empty is not rendered at all (no dead # links). A footer column with no remaining links is dropped too.
  • Links to other sites open in a new tab; in-site paths do not.
  • The output is a plain static site, so any static host works. See Deploy for the Docker route.

Deploy

The site ships as a Docker image: a bun stage builds it, an nginx stage serves the result. Two compose files, so the same image can be run with or without a reverse proxy in front.

deploy_docker.sh picks the compose files for you, so the only thing you choose is which machine you are on:

cp .env.example .env              # once, then edit DEPLOY_DOMAIN

./deploy_docker.sh local          # build and start here, on :9350
./deploy_docker.sh prod           # build and start behind Traefik
./deploy_docker.sh prod down      # stop and remove
./deploy_docker.sh prod logs -f   # follow the logs

Given no action it runs up -d --build, which is what you want almost every time. Anything after the mode is handed straight to docker compose, so ps, build --no-cache and the rest work as well. Before running it checks that .env exists, and in prod mode that the traefik network is there, since both failures are otherwise obscure.

The same thing without the script:

docker compose up -d --build                                    # local
docker compose -f docker-compose.yaml \
               -f docker-compose.prod.yaml up -d --build        # prod

The second file adds only the Traefik router labels and the external traefik network. It expects Traefik to be running already and attached to that network. Traefik terminates TLS and forwards plain HTTP to the container, so nginx listens on port 80 only and holds no certificate.

DEPLOY_DOMAIN is the one value that differs per deployment, along with HTTP_PROXY and friends if the build host needs a proxy. Everything else (image and container names, the loopback port, the entrypoint and network names) is the same for every clone and is written directly in the compose files.

Because the PUBLIC_* values are baked in at build time, changing any of them means rebuilding: docker compose … up -d --build again.

About

Landing page for Morphic Blocks

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages