diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 50d417d..8ccb56a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,8 +1,12 @@ name: CodeQL -# Weekly code scanning of the Rust API service and the TypeScript site, on GitHub-hosted runners. -# It runs once the repository is public (code scanning of a private repository needs a licence); -# until then every run is skipped. +# Code scanning of the Rust API service and the TypeScript site, on GitHub-hosted runners. +# +# The repository uses GitHub's default code scanning setup (Settings > Code security), which scans +# Rust, TypeScript and the workflows themselves every week. While default setup is on, GitHub +# refuses results uploaded by a workflow like this one, so the weekly schedule here is skipped and +# the job runs only when started by hand (after switching default setup off). Code scanning of a +# private repository needs a licence, so a private copy skips every run. on: schedule: - cron: "17 4 * * 1" @@ -14,7 +18,7 @@ permissions: jobs: analyze: name: analyze (${{ matrix.language }}) - if: ${{ !github.event.repository.private }} + if: ${{ !github.event.repository.private && github.event_name == 'workflow_dispatch' }} runs-on: ubuntu-latest timeout-minutes: 30 permissions: diff --git a/.github/workflows/k8s-build.yml b/.github/workflows/k8s-build.yml index 70509a4..f7b2985 100644 --- a/.github/workflows/k8s-build.yml +++ b/.github/workflows/k8s-build.yml @@ -109,7 +109,9 @@ jobs: if printf '%s' "$out" | grep -qi '^set-cookie:'; then echo "::error::a response set a cookie"; exit 1; fi } check /robots.txt 200 '^Disallow: /$' - check / 200 '.md` | the text of each install page | | `content/platform/*.md` | Ever Connect, anonymous usage statistics, free and paid | | `content/hosting/` | chooser text, the hosting list and its schema | +| `apps/web/public/logo/`, `apps/web/public/logos/` | this site's logo, and the logos of the Ever products and hosting providers (where each comes from: `logos/README.md`) | | `tools/` | repository checks, each with a self-test | | `deploy/docker/web/Dockerfile`, `deploy/docker/api/Dockerfile` | the two production images | diff --git a/apps/web/package.json b/apps/web/package.json index ff1689f..413db0c 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -2,6 +2,7 @@ "name": "@ever-sh/web", "version": "0.1.0", "private": true, + "license": "Apache-2.0", "description": "ever.sh: run Ever products on your own infrastructure.", "type": "module", "scripts": { diff --git a/apps/web/public/apple-touch-icon.png b/apps/web/public/apple-touch-icon.png new file mode 100644 index 0000000..f56607b Binary files /dev/null and b/apps/web/public/apple-touch-icon.png differ diff --git a/apps/web/public/favicon.ico b/apps/web/public/favicon.ico new file mode 100644 index 0000000..6a39bc5 Binary files /dev/null and b/apps/web/public/favicon.ico differ diff --git a/apps/web/public/favicon.svg b/apps/web/public/favicon.svg index cd7d5fd..5bfe339 100644 --- a/apps/web/public/favicon.svg +++ b/apps/web/public/favicon.svg @@ -1,12 +1 @@ - - ever.sh - - - - - - - - - - +ever.sh diff --git a/apps/web/public/logo/ever-icon.svg b/apps/web/public/logo/ever-icon.svg new file mode 100644 index 0000000..ee9a589 --- /dev/null +++ b/apps/web/public/logo/ever-icon.svg @@ -0,0 +1 @@ +Ever diff --git a/apps/web/public/logo/ever-selfhost.svg b/apps/web/public/logo/ever-selfhost.svg new file mode 100644 index 0000000..442887d --- /dev/null +++ b/apps/web/public/logo/ever-selfhost.svg @@ -0,0 +1 @@ +ever.sh diff --git a/apps/web/public/logos/README.md b/apps/web/public/logos/README.md new file mode 100644 index 0000000..076e8a4 --- /dev/null +++ b/apps/web/public/logos/README.md @@ -0,0 +1,67 @@ +# Logos + +The logos ever.sh shows next to the names they identify: the Ever products and the places they +can run. Each mark is a trademark of its owner. It is used here for identification only, and its +use does not imply endorsement (the footer of every page says so). Apart from the two ever® +lockups made for this site (described below), the files are copies of the owners' artwork, not +redrawings; the notes say what was changed (a title for screen readers, a colour, a trimmed +canvas). + +On the dark theme, a mark whose colours do not read there is shown as the brand's white version +(`reverseOnDark` in `apps/web/src/logos.ts`). + +## This site (`../logo/`) + +| File | Source | +|---|---| +| `ever-icon.svg` | The Ever mark from the header of (the same mark heads ). Only the gradient layer is kept. | +| `ever-selfhost.svg` | The ever® selfhost wordmark. "ever®" is the exact outline of the ever® works wordmark in the header of . "selfhost" is set in Fira Sans Light Italic, the face of "works" there (same size, baseline and starting point; the outlines of "works" redrawn this way match the original), and converted to outlines. The font is from and is not part of this repository. | + +`../favicon.svg`, `../favicon.ico` and `../apple-touch-icon.png` are the Ever mark as the Ever +product sites use it for their favicons (), on this site's violet +gradient. + +## Ever products (`ever/`) + +The ever® lockups, each a single outline in the text colour, as on the products' own sites. + +| File | Source | +|---|---| +| `ever/gauzy.svg` | Header of | +| `ever/teams.svg` | Header of | +| `ever/works.svg` | Header of | +| `ever/rec.svg` | Header of | +| `ever/demand.svg` | The Ever products list in the footer of | +| `ever/traduora.svg` | Made like `../logo/ever-selfhost.svg`: "ever®" from , "traduora" in Fira Sans Light Italic. sets its name as text, so there is no outline to copy. | + +## Hosting providers (`vendors/`) + +Marks from [Simple Icons](https://github.com/simple-icons/simple-icons) 16.33.0 are filled with the +brand colour Simple Icons records for them. The others come from the owner's brand kit or website. + +| File | Source | Notes | +|---|---|---| +| `vendors/docker.svg` | Docker logo kit, | The mark in Ocean Blue (`docker-mark-ocean-blue.svg`). Simple Icons still has the previous whale and colour. | +| `vendors/kubernetes.svg` | | #326CE5 | +| `vendors/helm.svg` | | #0F1689; white on the dark theme | +| `vendors/hostinger.svg` | | #673DE6 | +| `vendors/railway.svg` | | #0B0D0E; white on the dark theme | +| `vendors/render.svg` | | #000000; white on the dark theme | +| `vendors/digitalocean.svg` | | #0080FF | +| `vendors/netlify.svg` | | #00C7B7 | +| `vendors/koyeb.svg` | | #121212; white on the dark theme | +| `vendors/easypanel.svg` | Easypanel brand assets, | The logomark, unchanged. | +| `vendors/heroku.svg` | Heroku logo kit, | The mark for light backgrounds (#5A1BA9), with the empty canvas around it trimmed; white (the kit's reversed version) on the dark theme. | +| `vendors/elestio.svg` | Elestio press kit, | The colour "e" symbol, taken with its mask from `elestio-logo-color.svg`; the kit has it as `elestio-icon-color-512px.png`. | +| `vendors/northflank.svg` | (the mark in the site header) | Unchanged. | +| `vendors/repocloud.svg` | | The app icon (white "RC" on RepoCloud blue, #3F00FF), from the site's pinned-tab outline. | + +Fly.io has no logo here: its brand guidelines () ask for +written permission before its logo is used. The chooser shows a neutral icon instead, as it does +for any host without a logo. + +## Adding a logo + +Copy the owner's SVG (or the Simple Icons one) into `vendors/`, add the host to `HOST_LOGOS` in +`apps/web/src/logos.ts` (a dark mark gets `reverseOnDark`), add a row above, and check it on both +themes. diff --git a/apps/web/public/logos/ever/demand.svg b/apps/web/public/logos/ever/demand.svg new file mode 100644 index 0000000..9a20a7c --- /dev/null +++ b/apps/web/public/logos/ever/demand.svg @@ -0,0 +1 @@ +Ever Demand diff --git a/apps/web/public/logos/ever/gauzy.svg b/apps/web/public/logos/ever/gauzy.svg new file mode 100644 index 0000000..1d4fb27 --- /dev/null +++ b/apps/web/public/logos/ever/gauzy.svg @@ -0,0 +1 @@ +Ever Gauzy diff --git a/apps/web/public/logos/ever/rec.svg b/apps/web/public/logos/ever/rec.svg new file mode 100644 index 0000000..99ca208 --- /dev/null +++ b/apps/web/public/logos/ever/rec.svg @@ -0,0 +1 @@ +Ever Rec diff --git a/apps/web/public/logos/ever/teams.svg b/apps/web/public/logos/ever/teams.svg new file mode 100644 index 0000000..a14e05d --- /dev/null +++ b/apps/web/public/logos/ever/teams.svg @@ -0,0 +1 @@ +Ever Teams diff --git a/apps/web/public/logos/ever/traduora.svg b/apps/web/public/logos/ever/traduora.svg new file mode 100644 index 0000000..761d8ca --- /dev/null +++ b/apps/web/public/logos/ever/traduora.svg @@ -0,0 +1 @@ +Ever Traduora diff --git a/apps/web/public/logos/ever/works.svg b/apps/web/public/logos/ever/works.svg new file mode 100644 index 0000000..70cdc22 --- /dev/null +++ b/apps/web/public/logos/ever/works.svg @@ -0,0 +1 @@ +Ever Works diff --git a/apps/web/public/logos/vendors/digitalocean.svg b/apps/web/public/logos/vendors/digitalocean.svg new file mode 100644 index 0000000..e038c6e --- /dev/null +++ b/apps/web/public/logos/vendors/digitalocean.svg @@ -0,0 +1 @@ +DigitalOcean diff --git a/apps/web/public/logos/vendors/docker.svg b/apps/web/public/logos/vendors/docker.svg new file mode 100644 index 0000000..a2e6d5d --- /dev/null +++ b/apps/web/public/logos/vendors/docker.svg @@ -0,0 +1 @@ +Docker diff --git a/apps/web/public/logos/vendors/easypanel.svg b/apps/web/public/logos/vendors/easypanel.svg new file mode 100644 index 0000000..a219033 --- /dev/null +++ b/apps/web/public/logos/vendors/easypanel.svg @@ -0,0 +1 @@ +Easypanel diff --git a/apps/web/public/logos/vendors/elestio.svg b/apps/web/public/logos/vendors/elestio.svg new file mode 100644 index 0000000..2e26bb9 --- /dev/null +++ b/apps/web/public/logos/vendors/elestio.svg @@ -0,0 +1 @@ +Elestio diff --git a/apps/web/public/logos/vendors/helm.svg b/apps/web/public/logos/vendors/helm.svg new file mode 100644 index 0000000..88e38cb --- /dev/null +++ b/apps/web/public/logos/vendors/helm.svg @@ -0,0 +1 @@ +Helm diff --git a/apps/web/public/logos/vendors/heroku.svg b/apps/web/public/logos/vendors/heroku.svg new file mode 100644 index 0000000..4f622fc --- /dev/null +++ b/apps/web/public/logos/vendors/heroku.svg @@ -0,0 +1 @@ +Heroku diff --git a/apps/web/public/logos/vendors/hostinger.svg b/apps/web/public/logos/vendors/hostinger.svg new file mode 100644 index 0000000..a571559 --- /dev/null +++ b/apps/web/public/logos/vendors/hostinger.svg @@ -0,0 +1 @@ +Hostinger diff --git a/apps/web/public/logos/vendors/koyeb.svg b/apps/web/public/logos/vendors/koyeb.svg new file mode 100644 index 0000000..a51b93c --- /dev/null +++ b/apps/web/public/logos/vendors/koyeb.svg @@ -0,0 +1 @@ +Koyeb diff --git a/apps/web/public/logos/vendors/kubernetes.svg b/apps/web/public/logos/vendors/kubernetes.svg new file mode 100644 index 0000000..4e0334d --- /dev/null +++ b/apps/web/public/logos/vendors/kubernetes.svg @@ -0,0 +1 @@ +Kubernetes diff --git a/apps/web/public/logos/vendors/netlify.svg b/apps/web/public/logos/vendors/netlify.svg new file mode 100644 index 0000000..e68b275 --- /dev/null +++ b/apps/web/public/logos/vendors/netlify.svg @@ -0,0 +1 @@ +Netlify diff --git a/apps/web/public/logos/vendors/northflank.svg b/apps/web/public/logos/vendors/northflank.svg new file mode 100644 index 0000000..d5da39b --- /dev/null +++ b/apps/web/public/logos/vendors/northflank.svg @@ -0,0 +1 @@ +Northflank diff --git a/apps/web/public/logos/vendors/railway.svg b/apps/web/public/logos/vendors/railway.svg new file mode 100644 index 0000000..58f361f --- /dev/null +++ b/apps/web/public/logos/vendors/railway.svg @@ -0,0 +1 @@ +Railway diff --git a/apps/web/public/logos/vendors/render.svg b/apps/web/public/logos/vendors/render.svg new file mode 100644 index 0000000..db84d65 --- /dev/null +++ b/apps/web/public/logos/vendors/render.svg @@ -0,0 +1 @@ +Render diff --git a/apps/web/public/logos/vendors/repocloud.svg b/apps/web/public/logos/vendors/repocloud.svg new file mode 100644 index 0000000..57262fd --- /dev/null +++ b/apps/web/public/logos/vendors/repocloud.svg @@ -0,0 +1 @@ +RepoCloud diff --git a/apps/web/src/app.css b/apps/web/src/app.css index c3c9058..cb1ea66 100644 --- a/apps/web/src/app.css +++ b/apps/web/src/app.css @@ -201,6 +201,36 @@ @apply text-xs text-muted-foreground; } + /* Logos (`~/components/Logo.tsx`): an that keeps its proportions in the box its width and + height attributes reserve. */ + .logo { + display: inline-block; + flex: none; + object-fit: contain; + } + + /* On the dark theme, a mark whose own colours do not read there (black, or a dark brand colour) + is shown as the brand's white version: a white silhouette of the same mark. */ + @media (prefers-color-scheme: dark) { + :root:not([data-theme="light"]) .logo-reverse-dark { + filter: brightness(0) invert(1); + } + } + + :root[data-theme="dark"] .logo-reverse-dark { + filter: brightness(0) invert(1); + } + + /* The neutral icons (a server, a cloud, a file) are drawn in the muted text colour. */ + .neutral-icon { + flex: none; + color: hsl(var(--muted-foreground)); + } + + .footer-note { + @apply max-w-[900px] text-xs leading-5 text-muted-foreground; + } + .notice { @apply rounded-lg border border-border bg-muted px-4 py-3 text-sm; } diff --git a/apps/web/src/app.tsx b/apps/web/src/app.tsx index f3c5db8..c0c04ad 100644 --- a/apps/web/src/app.tsx +++ b/apps/web/src/app.tsx @@ -10,14 +10,19 @@ import { Router } from "@solidjs/router"; import { FileRoutes } from "@solidjs/start/router"; import { ErrorBoundary, For, Suspense } from "solid-js"; +import { Logo } from "./components/Logo"; +import { EVER_MARK, SITE_WORDMARK } from "./logos"; import { PRODUCTS } from "./products"; function Header() { return (
+ {/* The trademark note the other Ever sites carry under their footer, word for word. */} +
+ +
); } diff --git a/apps/web/src/components/Logo.tsx b/apps/web/src/components/Logo.tsx new file mode 100644 index 0000000..dc67c8d --- /dev/null +++ b/apps/web/src/components/Logo.tsx @@ -0,0 +1,70 @@ +/** + * Logos and the two neutral icons, all static markup: a logo is an `` of its SVG file, an + * icon is inline SVG in the text colour. Nothing here needs JavaScript in the browser. + */ +import { Show } from "solid-js"; + +import type { Logo as LogoFile } from "~/logos"; + +/** + * A logo, `height` pixels tall (or `unit` pixels per unit of the file's viewBox, which keeps the + * ever® part of every Ever lockup the same size); the width follows the logo's proportions. `alt` + * defaults to the brand's name; pass "" where the same name is already written next to it. + */ +export function Logo(props: { + logo: LogoFile; + height?: number; + unit?: number; + alt?: string; + class?: string; +}) { + const height = () => props.height ?? props.logo.height * (props.unit ?? 1); + const width = () => (props.logo.width / props.logo.height) * height(); + return ( + {props.alt + ); +} + +/** + * A neutral icon where there is no brand logo: a server (running it yourself), a cloud (a host + * without a logo) or a file (the environment file of an install page). + */ +export function NeutralIcon(props: { kind: "server" | "cloud" | "file"; size?: number }) { + const size = () => props.size ?? 24; + return ( + + ); +} diff --git a/apps/web/src/components/ProductNav.tsx b/apps/web/src/components/ProductNav.tsx index 78b0cd6..a7cb856 100644 --- a/apps/web/src/components/ProductNav.tsx +++ b/apps/web/src/components/ProductNav.tsx @@ -1,10 +1,13 @@ /** - * A product's breadcrumbs and sub-navigation: its guide pages (only those that exist; a missing - * content file simply has no tab) and, for installable products, the install page. + * A product's breadcrumbs and sub-navigation: the product's own lockup, its guide pages (only + * those that exist; a missing content file simply has no tab) and, for installable products, the + * install page. */ import { For, Show } from "solid-js"; +import { Logo } from "~/components/Logo"; import { productTabs } from "~/content"; +import { PRODUCT_LOGOS } from "~/logos"; import { installable, type Product } from "~/products"; export function ProductNav(props: { product: Product; current: string; currentLabel?: string }) { @@ -29,8 +32,15 @@ export function ProductNav(props: { product: Product; current: string; currentLa )} -