From 9e68115766793cb9ad7aae121ec32258892c74ce Mon Sep 17 00:00:00 2001 From: James Wilson Date: Mon, 18 May 2026 19:13:13 -0500 Subject: [PATCH 01/14] feat(docs): introduce guided Drupal core start page --- README.md | 9 +- docs/coder-ddev-start.css | 511 +++++++++++++++++++++++++++++++++++ docs/coder-workspace-name.js | 67 +++++ docs/drupal-core.html | 421 +++++++++++++++++++++++++++++ 4 files changed, 1006 insertions(+), 2 deletions(-) create mode 100644 docs/coder-ddev-start.css create mode 100644 docs/coder-workspace-name.js create mode 100644 docs/drupal-core.html diff --git a/README.md b/README.md index e8f7c01..76df7c4 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,14 @@ Coder workspace template for DDEV-based development with Docker-in-Docker support, Node.js, and Git. -**Get started with Drupal core development:** +**Get started (recommended paths):** -[![Open in Coder](https://coder.ddev.com/open-in-coder.svg)](https://coder.ddev.com/templates/coder/drupal-core/workspace?mode=manual) +- **Drupal.org issue or project** → [Drupal Issue Picker](https://start.coder.ddev.com/drupal-issue) (auto-detects core vs contrib and prefills sensible defaults) +- **Multiple DDEV projects in one workspace** → [DDEV Freeform](https://coder.ddev.com/templates/coder/freeform/workspace?mode=manual) +- **Clean Drupal core without an issue fork** → [Guided Drupal core](https://start.coder.ddev.com/drupal-core) (short context page, then the same manual template) +- **Browse all templates** → [coder.ddev.com/templates](https://coder.ddev.com/templates) + +**Advanced:** open the [manual Drupal core template](https://coder.ddev.com/templates/coder/drupal-core/workspace?mode=manual) directly if you already know every parameter you need. ## Features diff --git a/docs/coder-ddev-start.css b/docs/coder-ddev-start.css new file mode 100644 index 0000000..931e2de --- /dev/null +++ b/docs/coder-ddev-start.css @@ -0,0 +1,511 @@ +/** + * Shared tokens + components for start.coder.ddev.com static pages. + * Includes: global reset + skip link, form subpage chrome (drupal-core / drupal-issue), + * and tile/button/note patterns used on index. + * Colors: DDEV brand guide — https://docs.ddev.com/en/stable/developers/brand-guide/ + * DDEV Blue #02a8e2 · DDEV Black #1e2127 · DDEV White #e1ded8 + * Filled buttons use a darker blue than --action so white text meets WCAG 1.4.3 (AA). + */ +:root { + --bg-page: #1e2127; + --bg-elevated: #262c35; + --bg-elevated-hover: #2e3540; + --border: #3d4550; + --border-subtle: #2a3039; + --text: #e1ded8; + --text-secondary: #b5b1ab; + /* Lighter than old #8a8680: ≥4.5:1 on --bg-page and --bg-elevated (WCAG 1.4.3 AA normal text) */ + --text-muted: #a09993; + /* Brand blue — links, focus, borders, non–white-on-blue accents */ + --action: #02a8e2; + --action-pressed: #0184b4; + /* Filled controls (primary CTAs, skip link): #fff vs bg ≥ 4.5:1 (normal text) */ + --btn-primary-bg: #01729d; + --btn-primary-bg-hover: #01658a; + /* Muted primary (disabled): same hue family as --btn-primary-bg, not neutral purple */ + --btn-primary-bg-disabled: color-mix(in srgb, var(--btn-primary-bg) 42%, var(--border)); + --btn-primary-fg: #ffffff; + --btn-primary-fg-disabled: color-mix(in srgb, var(--btn-primary-fg) 58%, var(--text-muted)); + --link: #35c5f4; + --link-hover: #7ddbfc; + --focus: #7ddbfc; + --radius: 12px; + --radius-sm: 8px; + --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; +} + +.cds-body { + font-family: var(--font); + background: var(--bg-page); + color: var(--text); + line-height: 1.6; +} + +.cds-link { + color: var(--link); + font-weight: 600; + text-decoration: none; +} + +.cds-link:hover { + color: var(--link-hover); + text-decoration: underline; +} + +/* Card / tile — one pattern everywhere */ +.cds-tile-grid { + display: grid; + gap: 1rem; + width: min(100%, 720px); +} + +@media (min-width: 560px) { + .cds-tile-grid--2 { + grid-template-columns: 1fr 1fr; + } +} + +.cds-tile { + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 1.35rem 1.4rem; + display: flex; + flex-direction: column; + align-items: stretch; + text-align: left; + transition: border-color 0.15s ease, background 0.15s ease; +} + +.cds-tile:hover { + background: var(--bg-elevated-hover); + border-color: #525a66; +} + +.cds-tile--featured { + border-color: rgba(2, 168, 226, 0.5); + box-shadow: inset 0 1px 0 0 rgba(2, 168, 226, 0.18); +} + +.cds-tile__eyebrow { + font-size: 0.7rem; + font-weight: 700; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--action); + margin-bottom: 0.45rem; +} + +.cds-tile__title { + font-size: 1.05rem; + font-weight: 700; + color: var(--text); + margin-bottom: 0.4rem; + letter-spacing: -0.01em; +} + +.cds-tile__desc { + font-size: 0.9rem; + color: var(--text-secondary); + line-height: 1.55; + margin-bottom: 1.1rem; + flex: 1; +} + +.cds-tile__actions { + display: flex; + flex-direction: column; + gap: 0.65rem; + margin-top: auto; +} + +.cds-tile__actions .cds-btn { + width: 100%; + justify-content: center; + text-align: center; +} + +/* Buttons — DDEV blue primary */ +.cds-btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + font-size: 0.95rem; + font-weight: 600; + text-decoration: none; + border-radius: var(--radius-sm); + padding: 0.65rem 1.1rem; + border: 1px solid transparent; + cursor: pointer; + transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease; +} + +.cds-btn:focus-visible { + outline: 2px solid var(--focus); + outline-offset: 2px; +} + +.cds-btn--primary { + background: var(--btn-primary-bg); + color: var(--btn-primary-fg); +} + +.cds-btn--primary:hover { + background: var(--btn-primary-bg-hover); +} + +/* Secondary — DDEV surface + border; quieter than primary, still on-brand on hover */ +.cds-btn--secondary { + background: var(--bg-page); + color: var(--text); + border-color: var(--border); + box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.04); +} + +.cds-btn--secondary:hover { + background: var(--bg-elevated); + border-color: var(--action); + color: #fff; +} + +.cds-btn--outline { + background: transparent; + color: var(--text); + border-color: var(--border); +} + +.cds-btn--outline:hover { + border-color: var(--action); + color: #fff; +} + +.cds-btn__badge { + height: 36px; + width: auto; + display: block; +} + +.cds-btn--outline .cds-btn__badge { + margin-left: 0.25rem; +} + +/* Muted note / footnote strip */ +.cds-note { + width: min(100%, 720px); + margin-top: 1rem; + padding: 1rem 1.15rem; + font-size: 0.88rem; + color: var(--text-secondary); + line-height: 1.55; + background: var(--bg-elevated); + border: 1px solid var(--border-subtle); + border-radius: var(--radius-sm); +} + +/* Hero subtitle → cross-link intro (drupal-core / drupal-issue): same rhythm on both */ +.cds-note.intro-note { + margin-top: 0.35rem; + margin-bottom: 1.75rem; +} + +.cds-note a { + color: var(--link); + font-weight: 600; + text-decoration: none; +} + +.cds-note a:hover { + text-decoration: underline; + color: var(--link-hover); +} + +.cds-note strong { + color: var(--text); + font-weight: 600; +} + +.cds-note__sep { + color: var(--text-muted); + margin: 0 0.25rem; +} + +/* Inline muted link row (advanced) */ +.cds-muted-row { + margin-top: 0.85rem; + font-size: 0.8rem; + color: var(--text-muted); + text-align: center; + max-width: 720px; +} + +.cds-muted-row a { + color: var(--text-secondary); + text-decoration: underline; +} + +.cds-muted-row a:hover { + color: var(--text); +} + +/* --------------------------------------------------------------------------- + * Global doc reset + skip link (index, drupal-core, drupal-issue) + * --------------------------------------------------------------------------- */ +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body.cds-body { + min-height: 100vh; +} + +.skip-link { + position: absolute; + top: -100%; + left: 1rem; + background: var(--btn-primary-bg); + color: var(--btn-primary-fg); + padding: 0.5rem 1rem; + border-radius: 0 0 6px 6px; + font-size: 0.9rem; + font-weight: 600; + text-decoration: none; + z-index: 999; +} + +.skip-link:hover { + background: var(--btn-primary-bg-hover); +} + +.skip-link:focus { + top: 0; +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +/* --------------------------------------------------------------------------- + * Form subpages: drupal-core, drupal-issue (top chrome + shared controls) + * --------------------------------------------------------------------------- */ +header { + padding: 1.25rem 2rem; + border-bottom: 1px solid var(--border-subtle); + display: flex; + align-items: center; + gap: 1rem; + flex-wrap: wrap; +} + +header a { + font-size: 0.9rem; +} + +header a:hover { + text-decoration: underline; +} + +header .sep { + color: var(--text-muted); +} + +header .title { + color: var(--text); + font-weight: 600; + font-size: 0.9rem; +} + +.page { + max-width: 720px; + margin: 0 auto; + padding: 3rem 2rem 5rem; +} + +.page > h1 { + font-size: 1.75rem; + font-weight: 700; + letter-spacing: -0.02em; + margin-bottom: 0.5rem; + color: var(--text); +} + +.page > .subtitle { + color: var(--text-secondary); + font-size: 1rem; + line-height: 1.5; + margin-bottom: 1.35rem; +} + +/* Form field captions — drupal-core (.field-label) + drupal-issue (.field > label); use tokens only */ +.page .field-label, +.page .field > label { + display: block; + font-size: 0.8rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.07em; + color: var(--text-muted); + margin-bottom: 0.42rem; +} + +.page .field .hint--url { + margin-top: 0.4rem; + line-height: 1.45; +} + +.page .field .hint--url code { + font-family: "SF Mono", Consolas, monospace; + font-size: 0.72rem; + color: var(--link); + background: var(--bg-elevated); + border: 1px solid var(--border); + padding: 0.12em 0.35em; + border-radius: 4px; + word-break: break-all; +} + +.launch-row { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.75rem 1.15rem; +} + +.btn-open { + flex: 1 1 14rem; + min-width: min(100%, 14rem); + width: auto; + background: var(--btn-primary-bg); + color: var(--btn-primary-fg); + border: none; + border-radius: 8px; + padding: 0.85rem 1.5rem; + font-size: 1rem; + font-weight: 600; + cursor: pointer; + transition: background 0.15s ease; +} + +.btn-open:hover { + background: var(--btn-primary-bg-hover); +} + +.btn-open:focus-visible { + outline: 2px solid var(--focus); + outline-offset: 2px; +} + +.launch-note { + flex: 1 1 12rem; + margin: 0; + font-size: 0.82rem; + color: var(--text-secondary); + line-height: 1.45; + max-width: 22rem; +} + +.status { + font-size: 0.9rem; + padding: 0.75rem 1rem; + border-radius: 8px; + margin-bottom: 1rem; + display: none; +} + +.status.loading { + display: block; + background: #161619; + /* #636377 on #161619 ~3.5:1 — WCAG 1.4.11 non-text contrast (AA) */ + border: 1px solid #636377; + color: #999; +} + +.status.error { + display: block; + background: #1f0f0f; + border: 1px solid #5a1a1a; + color: #f87171; +} + +.status.info { + display: block; + background: #0f1a1f; + border: 1px solid #1a4a5a; + color: #7dd3fc; +} + +.notes { + font-size: 0.88rem; + color: var(--text-secondary); + line-height: 1.55; +} + +.notes h2 { + font-size: 0.72rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.1em; + color: var(--text-muted); + margin-bottom: 0.65rem; +} + +.notes h2:not(:first-child) { + margin-top: 1.35rem; +} + +.notes p, +.notes ul { + margin: 0 0 1.25rem; +} + +.notes :last-child { + margin-bottom: 0; +} + +.notes ul { + padding-left: 1.1rem; +} + +.notes li { + margin-bottom: 0.35rem; +} + +.notes a { + color: var(--link); + font-weight: 600; + text-decoration: none; +} + +.notes a:hover { + text-decoration: underline; + color: var(--link-hover); +} + +.divider { + border: 0; + border-top: 1px solid var(--border-subtle); + margin: 2.25rem 0; + height: 0; +} + +.notes--feedback p { + margin: 0; +} + +.feedback-links { + color: var(--text-secondary); + font-size: 0.95rem; + line-height: 1.7; +} diff --git a/docs/coder-workspace-name.js b/docs/coder-workspace-name.js new file mode 100644 index 0000000..202f8e5 --- /dev/null +++ b/docs/coder-workspace-name.js @@ -0,0 +1,67 @@ +/** + * Shared workspace name helpers for start.coder.ddev.com (drupal-core + drupal-issue). + */ +(function (global) { + 'use strict'; + + const PROFILE_SLUG = { + demo_umami: 'umami', + minimal: 'minimal', + standard: 'standard', + }; + + const VERSION_SLUG = { + 10: '10x', + 11: '11x', + 12: '12x', + }; + + function sanitizeWorkspaceName(name) { + return String(name) + .toLowerCase() + .replace(/[^a-z0-9-]/g, '-') + .replace(/-+/g, '-') + .replace(/^-|-$/g, ''); + } + + /** + * Plain Drupal core workspace (no issue fork): {major}x-{profileSlug}, e.g. 12x-umami. + * + * @param {string} drupalMajor + * @param {string} installProfile machine value (e.g. demo_umami) + * @returns {string} + */ + function workspaceNameFromCoreChoices(drupalMajor, installProfile) { + const verKey = String(drupalMajor); + const verSlug = VERSION_SLUG[verKey] || (verKey + 'x'); + const slug = PROFILE_SLUG[installProfile] || String(installProfile).replace(/_/g, '-'); + return verSlug + '-' + slug; + } + + /** + * Issue picker: version + profile + (branch name if multiple branch options, else issue NID). + * + * @param {string} drupalMajor + * @param {string} installProfile + * @param {string|number} issueNid + * @param {string} branchName selected branch + * @param {number} branchOptionCount branches shown in the picker (>1 means disambiguate with branch) + * @returns {string} + */ + function suggestedIssueForkWorkspaceName(drupalMajor, installProfile, issueNid, branchName, branchOptionCount) { + const base = workspaceNameFromCoreChoices(drupalMajor, installProfile); + const nidSeg = String(issueNid); + if (branchOptionCount > 1 && branchName) { + return sanitizeWorkspaceName(base + '-' + branchName); + } + return sanitizeWorkspaceName(base + '-' + nidSeg); + } + + global.CoderWorkspace = { + PROFILE_SLUG: PROFILE_SLUG, + VERSION_SLUG: VERSION_SLUG, + sanitizeWorkspaceName: sanitizeWorkspaceName, + workspaceNameFromCoreChoices: workspaceNameFromCoreChoices, + suggestedIssueForkWorkspaceName: suggestedIssueForkWorkspaceName, + }; +})(typeof window !== 'undefined' ? window : this); diff --git a/docs/drupal-core.html b/docs/drupal-core.html new file mode 100644 index 0000000..3231f74 --- /dev/null +++ b/docs/drupal-core.html @@ -0,0 +1,421 @@ + + + + + + Drupal core — DDEV Coder Workspaces + + + + + + + +
+ DDEV Coder Workspaces + + Drupal core +
+ +
+

Drupal core

+

Choose a major version and install profile, then open your workspace in Coder.

+ +
+ If working on a Drupal core or contrib issue fork or need to test the mainline branch of a contrib project, try the Drupal Issue Picker. +
+ + + +
+
+ Drupal version +
+ + + +
+
+ +
+ Install profile +
+ + + +
+
+ +
+ Site visibility + +
+ + + +
+
+ +
+ + +
Used to generate the URL. Must be lowercase letters, numbers, and hyphens only.
+
E.g. https://drupal-site----username.coder.ddev.com/
+
+
+ +
+ +

Opens in a new tab.

+
+ +
+ +
+

Access

+

Requires a GitHub account — sign in at coder.ddev.com first.

+ +

Install profiles

+

Demo Umami on Drupal 12 can use a pre-built snapshot for a quicker first boot. Minimal, Standard, and Drupal 11.x and 10.x always run a full site install.

+ +

Workspace name

+

A suggested workspace name is auto-generated from the parameters above. It may be changed before clicking launch.

+
+ +
+ + +
+ + + + + From 80e0e625ab4eb2de72cb24fc94f3c91f9749e7fc Mon Sep 17 00:00:00 2001 From: James Wilson Date: Mon, 18 May 2026 19:15:11 -0500 Subject: [PATCH 02/14] feat(docs): refactor landing page entry points --- docs/index.html | 377 ++++++++++++++++++++++++------------------------ 1 file changed, 188 insertions(+), 189 deletions(-) diff --git a/docs/index.html b/docs/index.html index 9f39f5c..4654caf 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3,19 +3,10 @@ - DDEV Coder Workspaces — Drupal Core Development + DDEV Coder Workspaces — Get started + - - +
- -

Coder Workspaces

-

Cloud-hosted development environments powered by DDEV. Full stack, ready in about a minute — no local setup required.

- -
- - - Requires GitHub membership in the ddev org or a sponsor orgrequest access · sign in +
+ +

Coder Workspaces

+

Browser-based environments with DDEV and Docker — full stack, ready in about a minute, no local install.

+ +
+

New here? Read the coder.ddev.com announcement on ddev.com for background on the service and two demo videos.

+
+ +
+ + Sign in via GitHub OAuth. To use DDEV Coder Workspaces, you must be a member of a sponsoring GitHub organization, or of the ddev or coder-ddev-com org. Organizations gain access by sponsoring DDEV at the $100+/month level. Individuals may request contributor access. +
+ +
+ + +
+

DDEV Freeform

+

Multiple DDEV projects in one workspace—each keeps its own hostname via ddev-router. Use this when you want a flexible environment instead of a single curated template.

+ +
+
+ +

+ Not using a Drupal.org issue fork? Launch into a clean Drupal core version branch environment (12.x, 11.x, 10.x) for a quickstart demo workspace. For the full directory—manual flows, contrib, freeform, and more—browse all Coder templates on coder.ddev.com. +

- - Open in Coder - - - +

-
-
-

How it works

-
    -
  1. Sign in with GitHub at coder.ddev.com — access requires the ddev org, a $100+/mo sponsor org, or an approved request
  2. -
  3. Click Create Workspace — your environment sets up automatically
  4. -
  5. Click DDEV Web to open the running site, or VS Code to edit code
  6. -
+

Other entry points

+
+
+

Guided Drupal core

+

Vanilla Drupal core, no issue fork: a few choices here, then straight into Coder to create the workspace.

+ +
+
+

Template library

+

Every Coder template in one place, including flows where you set the full Coder parameters yourself.

+ +
+
-
-

What you get

+
+ +
+

How it works

    -
  1. Drupal core git clone at ~/drupal-core/repos/drupal/ — clean, ready for patches
  2. -
  3. Running Drupal site with Umami demo profile — login admin / admin, or ddev drush uli
  4. -
  5. PHP 8.5, DDEV, Composer, drush, VS Code for Web — all pre-installed
  6. +
  7. Sign in with GitHub at coder.ddev.com (see access note above).
  8. +
  9. Create a workspace from a Drupal core version, an issue fork or contrib project name, or select from available Coder templates.
  10. +
  11. Open DDEV Web for the site or VS Code for the editor.
-
-

Drupal issue development

-
-
-
-

Drupal Issue Picker

-

Enter a Drupal.org issue URL or number — launches a workspace with the issue fork checked out. Supports both Drupal core and contrib modules/themes.

-
- Open Picker -
-
-
- -
-

Other templates

-
-
-
-

DDEV Freeform

-

Run multiple DDEV projects in one workspace, each accessible via its own subdomain through ddev-router

-
- - Open in Coder - -
-
+
+

Drupal core template includes

+
    +
  1. Git clone of Drupal core under ~/drupal-core/repos/drupal/
  2. +
  3. Running site (often Umami demo) — admin / admin or ddev drush uli
  4. +
  5. DDEV, Composer, Drush, VS Code for Web — pre-installed
  6. +
+

More details in the quickstart guide.

-
-

Resources

+
+

Resources

-
-

Feedback & Community

-

Any problems or friction? Create an issue at ddev/coder-ddev or join us for conversation on Drupal Slack #ddev or DDEV Discord.

-
+
+
- From d0d60ef776093b5036b7ed2b578c997492c98e87 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Mon, 18 May 2026 19:16:18 -0500 Subject: [PATCH 03/14] refactor(docs): align drupal-issue page with drupal-core --- docs/drupal-issue.html | 439 +++++++++++++++++------------------------ 1 file changed, 183 insertions(+), 256 deletions(-) diff --git a/docs/drupal-issue.html b/docs/drupal-issue.html index a9bda2a..37dd9fe 100644 --- a/docs/drupal-issue.html +++ b/docs/drupal-issue.html @@ -5,64 +5,13 @@ Drupal Issue Picker — DDEV Coder Workspaces + - +
- DDEV Coder Workspaces + DDEV Coder Workspaces Drupal Issue Picker @@ -387,7 +206,11 @@

Drupal Issue Picker

-

Enter a Drupal issue URL or number to launch a workspace. Also accepts a project URL or machine name for plain contrib development (no specific issue).

+

Paste a drupal.org core or contrib issue URL or number, or a contrib project URL or machine name. We load issue metadata and fork branches when applicable.

+ +
+ To create a clean Drupal core environment without contrib modules or issue forks, try the Guided Drupal core form. +
@@ -471,21 +298,25 @@

Drupal Issue Picker

-
minimal is recommended for contrib development.
+
Minimal is recommended for contrib development.
- -
Must be lowercase letters, numbers, and hyphens only.
+ +
Used to generate the URL. Must be lowercase letters, numbers, and hyphens only.
+
E.g. https://drupal-site----username.coder.ddev.com/
- +
+ +

Opens in a new tab.

+
@@ -509,9 +340,9 @@

Drupal Issue Picker

@@ -526,35 +357,71 @@

Drupal Issue Picker

- + +
Used to generate the URL. Must be lowercase letters, numbers, and hyphens only.
+
E.g. https://drupal-site----username.coder.ddev.com/
- +
+ +

Opens in a new tab.

+
-
-

Notes

-
    -
  • Requires a GitHub account — sign in at coder.ddev.com first
  • -
  • Core issues use the drupal-core template; contrib issues use the drupal-contrib template — detected automatically
  • -
  • Issue fork workspaces always run a full ddev drush si (branch code may differ from the cached database)
  • -
  • The demo_umami fast path (about a minute) is only used for standard Drupal core without an issue fork
  • -
  • Issue fork must exist on git.drupalcode.org — click "Get push access" on the issue page to create one
  • -
  • Contrib dev without an issue: enter a project URL like drupal.org/project/token or just the machine name token
  • -
-
+
-
-

Feedback & Community

-

Any problems or friction? Create an issue at ddev/coder-ddev or join us for conversation on Drupal Slack #ddev or DDEV Discord.

-
+
+

Access

+

Requires a GitHub account — sign in at coder.ddev.com first.

+ +

Install profiles

+

Demo Umami on Drupal 12 can use a pre-built snapshot for a quicker first boot. Minimal, Standard, and Drupal 11.x and 10.x always run a full site install.

+ +

Coder Workspace Templates

+

Core issues use the drupal-core template; contrib issues and project-only dev use drupal-contrib. The picker chooses automatically from the issue or project you load.

+ +

Workspace name

+

A suggested workspace name is auto-generated from the parameters above. It may be changed before clicking launch.

+ +

Issue forks

+

An issue fork must already exist on git.drupalcode.org — use Get push access on the drupal.org issue to create one, then reload here.

+

Issue fork workspaces always run a full ddev drush si so the checked-out branch matches the running site (not a stale snapshot).

+
+ +
+ + + From cedc5c0d300e303b6ad3c2fbe5bbfb39130b5ef6 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Mon, 18 May 2026 19:21:04 -0500 Subject: [PATCH 04/14] docs(start-site): align drupal-issue copy with drupal-core --- drupal-core/template.tf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drupal-core/template.tf b/drupal-core/template.tf index dccd3ae..6fc059f 100644 --- a/drupal-core/template.tf +++ b/drupal-core/template.tf @@ -117,21 +117,21 @@ data "coder_parameter" "drupal_version" { data "coder_parameter" "install_profile" { name = "install_profile" display_name = "Install Profile" - description = "Drupal install profile. demo_umami uses a pre-built database snapshot (12.x only); other profiles and non-12.x versions always run a full site install." + description = "Drupal install profile. Demo Umami on Drupal 12 can use a pre-built snapshot for quicker first boot; Standard, Minimal and Drupal 11.x and 10.x always run a full site install." type = "string" default = "demo_umami" mutable = true order = 3 option { - name = "demo_umami" + name = "Demo Umami" value = "demo_umami" } option { - name = "minimal" + name = "Minimal" value = "minimal" } option { - name = "standard" + name = "Standard" value = "standard" } } From db0ce5371f5890a3155b0882380efe57493ddd2c Mon Sep 17 00:00:00 2001 From: James Wilson Date: Mon, 18 May 2026 22:57:45 -0500 Subject: [PATCH 05/14] feat(docs): expand shared start-site CSS and component gallery Add pick-card controls, dark tokens, and logo assets; document patterns on /components.html. --- docs/coder-ddev-start.css | 999 +++++++++++++++++++++++++++++++++--- docs/components.html | 161 ++++++ docs/logo-coder-on-dark.svg | 8 + docs/logo-ddev-on-dark.svg | 1 + 4 files changed, 1109 insertions(+), 60 deletions(-) create mode 100644 docs/components.html create mode 100644 docs/logo-coder-on-dark.svg create mode 100644 docs/logo-ddev-on-dark.svg diff --git a/docs/coder-ddev-start.css b/docs/coder-ddev-start.css index 931e2de..aef315f 100644 --- a/docs/coder-ddev-start.css +++ b/docs/coder-ddev-start.css @@ -1,12 +1,12 @@ /** - * Shared tokens + components for start.coder.ddev.com static pages. - * Includes: global reset + skip link, form subpage chrome (drupal-core / drupal-issue), - * and tile/button/note patterns used on index. - * Colors: DDEV brand guide — https://docs.ddev.com/en/stable/developers/brand-guide/ - * DDEV Blue #02a8e2 · DDEV Black #1e2127 · DDEV White #e1ded8 - * Filled buttons use a darker blue than --action so white text meets WCAG 1.4.3 (AA). + * Shared design tokens + components for start.coder.ddev.com + * Used on static HTML landing pages and Jekyll docs markdown pages. + * See /components.html for example usage. + * See DDEV brand guide https://docs.ddev.com/en/stable/developers/brand-guide/ + * for primary color definitions. */ :root { + --bg-dark: #131318; --bg-page: #1e2127; --bg-elevated: #262c35; --bg-elevated-hover: #2e3540; @@ -14,15 +14,14 @@ --border-subtle: #2a3039; --text: #e1ded8; --text-secondary: #b5b1ab; - /* Lighter than old #8a8680: ≥4.5:1 on --bg-page and --bg-elevated (WCAG 1.4.3 AA normal text) */ + /* Lighter than old #8a8680: meets WCAG 1.4.3 AA normal text contrast. */ --text-muted: #a09993; /* Brand blue — links, focus, borders, non–white-on-blue accents */ --action: #02a8e2; --action-pressed: #0184b4; - /* Filled controls (primary CTAs, skip link): #fff vs bg ≥ 4.5:1 (normal text) */ + /* Filled button controls use a darker blue so white on blue meets WCAG 1.4.3 AA contrast. */ --btn-primary-bg: #01729d; --btn-primary-bg-hover: #01658a; - /* Muted primary (disabled): same hue family as --btn-primary-bg, not neutral purple */ --btn-primary-bg-disabled: color-mix(in srgb, var(--btn-primary-bg) 42%, var(--border)); --btn-primary-fg: #ffffff; --btn-primary-fg-disabled: color-mix(in srgb, var(--btn-primary-fg) 58%, var(--text-muted)); @@ -93,14 +92,14 @@ letter-spacing: 0.12em; text-transform: uppercase; color: var(--action); - margin-bottom: 0.45rem; + margin: 0 0 0.45rem; } .cds-tile__title { font-size: 1.05rem; font-weight: 700; color: var(--text); - margin-bottom: 0.4rem; + margin: 0 0 0.4rem; letter-spacing: -0.01em; } @@ -108,7 +107,7 @@ font-size: 0.9rem; color: var(--text-secondary); line-height: 1.55; - margin-bottom: 1.1rem; + margin: 0 0 1.1rem; flex: 1; } @@ -157,7 +156,7 @@ /* Secondary — DDEV surface + border; quieter than primary, still on-brand on hover */ .cds-btn--secondary { - background: var(--bg-page); + background: var(--bg-dark); color: var(--text); border-color: var(--border); box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.04); @@ -193,7 +192,7 @@ /* Muted note / footnote strip */ .cds-note { width: min(100%, 720px); - margin-top: 1rem; + margin: 1.25rem 0; padding: 1rem 1.15rem; font-size: 0.88rem; color: var(--text-secondary); @@ -203,8 +202,16 @@ border-radius: var(--radius-sm); } +.cds-note:first-child { + margin-top: 0; +} + +.cds-note:last-child { + margin-bottom: 0; +} + /* Hero subtitle → cross-link intro (drupal-core / drupal-issue): same rhythm on both */ -.cds-note.intro-note { +.cds-note--intro { margin-top: 0.35rem; margin-bottom: 1.75rem; } @@ -263,7 +270,7 @@ body.cds-body { min-height: 100vh; } -.skip-link { +.cds-skip-link { position: absolute; top: -100%; left: 1rem; @@ -277,15 +284,15 @@ body.cds-body { z-index: 999; } -.skip-link:hover { +.cds-skip-link:hover { background: var(--btn-primary-bg-hover); } -.skip-link:focus { +.cds-skip-link:focus { top: 0; } -.sr-only { +.cds-sr-only { position: absolute; width: 1px; height: 1px; @@ -300,7 +307,7 @@ body.cds-body { /* --------------------------------------------------------------------------- * Form subpages: drupal-core, drupal-issue (top chrome + shared controls) * --------------------------------------------------------------------------- */ -header { +.cds-page-header { padding: 1.25rem 2rem; border-bottom: 1px solid var(--border-subtle); display: flex; @@ -309,31 +316,31 @@ header { flex-wrap: wrap; } -header a { +.cds-page-header a { font-size: 0.9rem; } -header a:hover { +.cds-page-header a:hover { text-decoration: underline; } -header .sep { +.cds-page-header__sep { color: var(--text-muted); } -header .title { +.cds-page-header__title { color: var(--text); font-weight: 600; font-size: 0.9rem; } -.page { +.cds-page { max-width: 720px; margin: 0 auto; padding: 3rem 2rem 5rem; } -.page > h1 { +.cds-page > h1 { font-size: 1.75rem; font-weight: 700; letter-spacing: -0.02em; @@ -341,18 +348,18 @@ header .title { color: var(--text); } -.page > .subtitle { +.cds-page__subtitle { color: var(--text-secondary); font-size: 1rem; line-height: 1.5; margin-bottom: 1.35rem; } -/* Form field captions — drupal-core (.field-label) + drupal-issue (.field > label); use tokens only */ -.page .field-label, -.page .field > label { +/* Form field captions — drupal-core (.cds-field__label) + drupal-issue (.cds-field > label) */ +.cds-page .cds-field__label, +.cds-page .cds-field > label { display: block; - font-size: 0.8rem; + font-size: 0.85rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.07em; @@ -360,14 +367,14 @@ header .title { margin-bottom: 0.42rem; } -.page .field .hint--url { +.cds-page .cds-field .cds-hint--url { margin-top: 0.4rem; line-height: 1.45; } -.page .field .hint--url code { +code { font-family: "SF Mono", Consolas, monospace; - font-size: 0.72rem; + font-size: 0.84em; color: var(--link); background: var(--bg-elevated); border: 1px solid var(--border); @@ -376,14 +383,103 @@ header .title { word-break: break-all; } -.launch-row { +pre { + background: var(--bg-dark); + border: 1px solid var(--border-subtle); + border-radius: var(--radius-sm); + padding: 1.25rem 1.5rem; + overflow-x: auto; + margin-bottom: 1.25rem; +} + +pre code { + background: none; + border: none; + padding: 0; + font-size: 0.9rem; + color: #c9d1d9; +} + +.cds-hint { + font-size: 0.8rem; + color: var(--text-secondary); + margin-top: 0.3rem; +} + +.cds-field__label + .cds-hint { + margin-bottom: 0.5rem; +} + +/* #636377 on #161619 ~3.5:1 — WCAG 1.4.11 non-text contrast (AA) */ +.cds-field input[type="text"], +.cds-field select, +.cds-input-row input { + width: 100%; + background: #161619; + border: 1px solid #636377; + border-radius: 8px; + padding: 0.65rem 1rem; + color: #e8e8e8; + font-size: 0.95rem; + outline: none; + transition: border-color 0.15s ease; +} + +.cds-input-row input { + flex: 1; + width: auto; + padding: 0.7rem 1rem; +} + +.cds-input-row input::placeholder { + /* #888 on #161619 ~5.9:1 — WCAG 1.4.3 (AA) */ + color: #888; +} + +.cds-field select { + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%23a09993' d='M1 1l5 5 5-5'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 1rem center; + padding-right: 2.5rem; +} + +.cds-field input[type="text"][readonly] { + color: #aaa; + cursor: default; +} + +.cds-field input[type="text"]:focus, +.cds-field select:focus, +.cds-input-row input:focus { + border-color: var(--action); + outline: 2px solid var(--action); + outline-offset: 2px; +} + +.cds-fields { + display: flex; + flex-direction: column; + gap: 1.15rem; + margin-bottom: 1.35rem; +} + +.cds-radio-row { + display: flex; + flex-wrap: wrap; + gap: 0.65rem; + align-items: stretch; + justify-content: flex-start; +} + +.cds-launch-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem 1.15rem; } -.btn-open { +.cds-btn-open { flex: 1 1 14rem; min-width: min(100%, 14rem); width: auto; @@ -398,16 +494,44 @@ header .title { transition: background 0.15s ease; } -.btn-open:hover { +.cds-btn-open:hover { + background: var(--btn-primary-bg-hover); +} + +.cds-btn-open:focus-visible { + outline: 2px solid var(--focus); + outline-offset: 2px; +} + +.cds-btn-load { + background: var(--btn-primary-bg); + color: var(--btn-primary-fg); + border: none; + border-radius: 8px; + padding: 0.7rem 1.25rem; + font-size: 0.95rem; + font-weight: 600; + cursor: pointer; + white-space: nowrap; + transition: background 0.15s ease; +} + +.cds-btn-load:hover { background: var(--btn-primary-bg-hover); } -.btn-open:focus-visible { +.cds-btn-load:disabled { + background: var(--btn-primary-bg-disabled); + color: var(--btn-primary-fg-disabled); + cursor: not-allowed; +} + +.cds-btn-load:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; } -.launch-note { +.cds-launch-note { flex: 1 1 12rem; margin: 0; font-size: 0.82rem; @@ -416,7 +540,7 @@ header .title { max-width: 22rem; } -.status { +.cds-status { font-size: 0.9rem; padding: 0.75rem 1rem; border-radius: 8px; @@ -424,35 +548,40 @@ header .title { display: none; } -.status.loading { +.cds-status--loading { display: block; background: #161619; - /* #636377 on #161619 ~3.5:1 — WCAG 1.4.11 non-text contrast (AA) */ border: 1px solid #636377; color: #999; } -.status.error { +.cds-status--error { display: block; background: #1f0f0f; border: 1px solid #5a1a1a; color: #f87171; } -.status.info { +.cds-status--info { display: block; background: #0f1a1f; border: 1px solid #1a4a5a; color: #7dd3fc; } -.notes { - font-size: 0.88rem; +.cds-status--sample.cds-status--loading, +.cds-status--sample.cds-status--error, +.cds-status--sample.cds-status--info { + display: block; +} + +.cds-notes { + font-size: 0.92rem; color: var(--text-secondary); line-height: 1.55; } -.notes h2 { +.cds-notes h2 { font-size: 0.72rem; font-weight: 700; text-transform: uppercase; @@ -461,51 +590,801 @@ header .title { margin-bottom: 0.65rem; } -.notes h2:not(:first-child) { +.cds-notes h2:not(:first-child) { margin-top: 1.35rem; } -.notes p, -.notes ul { +.cds-notes p, +.cds-notes ol, +.cds-notes ul { margin: 0 0 1.25rem; } -.notes :last-child { +.cds-notes :last-child { margin-bottom: 0; } -.notes ul { +.cds-notes ul { padding-left: 1.1rem; } -.notes li { +.cds-notes li { margin-bottom: 0.35rem; } -.notes a { +.cds-notes a { color: var(--link); font-weight: 600; text-decoration: none; } -.notes a:hover { +.cds-notes a:hover { text-decoration: underline; color: var(--link-hover); } -.divider { +.cds-feedback { + color: var(--text-secondary); + font-size: 0.95rem; + line-height: 1.65; +} + +.cds-divider { border: 0; border-top: 1px solid var(--border-subtle); margin: 2.25rem 0; height: 0; } -.notes--feedback p { - margin: 0; +.cds-input-row { + display: flex; + gap: 0.75rem; + margin-bottom: 1.35rem; +} + +.cds-issue-panel[hidden] { + display: none !important; +} + +.cds-issue-title { + font-size: 1.05rem; + font-weight: 600; + color: var(--link); + margin-bottom: 1.75rem; + padding: 0.75rem 1rem; + background: rgba(2, 168, 226, 0.06); + border: 1px solid rgba(2, 168, 226, 0.22); + border-radius: 8px; +} + +.cds-issue-title__label { + display: block; + font-size: 0.75rem; + font-weight: 400; + color: #888; + margin-bottom: 0.2rem; + text-transform: uppercase; + letter-spacing: 0.06em; +} + +.cds-issue-title__link { + color: inherit; + text-decoration: underline; +} + +.cds-template-badge { + display: inline-block; + font-size: 0.7rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.08em; + padding: 0.15rem 0.5rem; + border-radius: 4px; + margin-top: 0.4rem; +} + +.cds-template-badge--core { + background: #1a2a1a; + color: #86efac; + border: 1px solid #166534; +} + +.cds-template-badge--contrib { + background: rgba(2, 168, 226, 0.1); + color: var(--link); + border: 1px solid rgba(2, 168, 226, 0.45); +} + +.cds-manual-notice { + font-size: 0.85rem; + color: #888; + margin-bottom: 1.25rem; + padding: 0.65rem 0.9rem; + background: #111114; + border: 1px solid #222228; + border-radius: 6px; +} + +.cds-share-intro { + font-size: 0.8rem; + color: var(--text-secondary); + line-height: 1.4; + margin: 0 0 0.45rem; + max-width: 38rem; +} + +/* Full-width primary CTA (stacked forms, access gate) */ +.cds-btn--block { + width: 100%; + justify-content: center; + text-align: center; +} + +/* --------------------------------------------------------------------------- + * Documentation shell (Jekyll default layout) + markdown prose + * --------------------------------------------------------------------------- */ +.cds-doc-nav { + padding: 1rem 2rem; + border-bottom: 1px solid var(--border-subtle); +} + +.cds-doc-nav a { + font-size: 0.9rem; + color: var(--link); + font-weight: 600; + text-decoration: none; +} + +.cds-doc-nav a:hover { + color: var(--link-hover); + text-decoration: underline; +} + +.cds-doc-main { + max-width: 720px; + margin: 0 auto; + padding: 3rem 2rem 6rem; +} + +.cds-doc-main--demo-top { + padding-top: 1.5rem; +} + +:where(.cds-doc-main) h1 { + font-size: 2rem; + font-weight: 700; + margin-bottom: 1rem; + letter-spacing: -0.02em; + line-height: 1.25; + color: var(--text); +} + +:where(.cds-doc-main) h2 { + font-size: 1.35rem; + font-weight: 600; + margin: 2.5rem 0 0.75rem; + color: var(--text); } -.feedback-links { +:where(.cds-doc-main) h3 { + font-size: 1.1rem; + font-weight: 600; + margin: 1.75rem 0 0.5rem; + color: var(--text); +} + +:where(.cds-doc-main) p { + margin-bottom: 1rem; + color: var(--text-secondary); +} + +:where(.cds-doc-main) a { + color: var(--link); + font-weight: 600; + text-decoration: none; +} + +:where(.cds-doc-main) a:hover { + color: var(--link-hover); + text-decoration: underline; +} + +:where(.cds-doc-main) ul, +:where(.cds-doc-main) ol { + margin: 0 0 1rem 1.5rem; color: var(--text-secondary); +} + +:where(.cds-doc-main) li { + margin-bottom: 0.35rem; +} + +:where(.cds-doc-main) hr { + border: none; + border-top: 1px solid var(--border-subtle); + margin: 2rem 0; +} + +.cds-doc-main table { + width: 100%; + border-collapse: collapse; + margin-bottom: 1.25rem; font-size: 0.95rem; - line-height: 1.7; +} + +.cds-doc-main th { + text-align: left; + padding: 0.6rem 0.75rem; + border-bottom: 2px solid var(--border-subtle); + color: var(--text-muted); + font-weight: 600; + font-size: 0.85rem; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.cds-doc-main td { + padding: 0.6rem 0.75rem; + border-bottom: 1px solid var(--border-subtle); + color: var(--text-secondary); +} + +.cds-doc-main strong { + color: var(--text); + font-weight: 600; +} + +.cds-doc-main blockquote, +.cds-blockquote { + margin: 0 0 1rem; + border-left: 3px solid var(--action); + padding: 0.2rem 0 0.2rem 1rem; + color: var(--text-muted); + font-size: 0.95rem; + line-height: 1.55; +} + +.cds-doc-main blockquote p, +.cds-blockquote p { + margin: 0 0 0.5rem; +} + +.cds-doc-main blockquote p:last-child, +.cds-blockquote p:last-child { + margin-bottom: 0; +} + +.cds-doc-main blockquote cite, +.cds-blockquote cite { + display: block; + margin-top: 0.65rem; + font-size: 0.85rem; + font-style: normal; + color: var(--text-secondary); +} + +.cds-doc-main img { + max-width: 100%; +} + +.cds-doc-cta { + margin: 1.25rem 0 1.75rem; +} + +.cds-doc-main a.cds-btn { + color: var(--btn-primary-fg); + text-decoration: none; +} + +.cds-doc-main a.cds-btn:hover { + text-decoration: none; +} + +.cds-doc-main a.cds-btn--secondary { + color: var(--text); +} + +.cds-doc-main a.cds-btn--secondary:hover { + color: #fff; +} + +.cds-doc-main a.cds-btn--outline { + color: var(--text); +} + +.cds-doc-main a.cds-btn--outline:hover { + color: #fff; +} + +/* --------------------------------------------------------------------------- + * Access gate + callouts (access-denied.html) + * --------------------------------------------------------------------------- */ +.cds-access-denied { + min-height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; + padding: 2rem; + gap: 2rem; +} + +.cds-gate-card { + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 2.5rem; + max-width: 520px; + width: 100%; +} + +.cds-emoji-hero { + font-size: 2.5rem; + margin-bottom: 1.25rem; + line-height: 1; +} + +.cds-gate-card h1 { + font-size: 1.5rem; + font-weight: 700; + color: var(--text); + margin-bottom: 0.75rem; +} + +.cds-gate-card .cds-gate-subtitle { + font-size: 1rem; + color: var(--text-muted); + margin-bottom: 2rem; + line-height: 1.7; +} + +.cds-callout { + background: var(--bg-page); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + padding: 1.25rem 1.5rem; + margin-bottom: 2rem; + text-align: left; +} + +.cds-callout--with-icon { + display: flex; + align-items: flex-start; + gap: 0.75rem; + background: var(--bg-elevated); + padding: 0.85rem 1.2rem; + margin-bottom: 1.75rem; + font-size: 0.95rem; + color: var(--text-secondary); + max-width: 36rem; +} + +.cds-callout--with-icon svg { + flex-shrink: 0; + margin-top: 0.1rem; +} + +.cds-callout__title { + font-size: 0.85rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.07em; + color: var(--text-muted); + margin-bottom: 0.85rem; +} + +.cds-checklist { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +/* + * Rows use padding + an absolutely positioned check — not flex on
  • — so mixed + * inline content does not become separate flex items. Wrap each row’s copy in a block + * (typically

    ) especially when a row has multiple paragraphs or rich markup. + */ +.cds-checklist > li { + position: relative; + display: block; + padding-left: calc(0.65rem + 1.05em); + color: var(--text-secondary); + font-size: 0.95rem; +} + +.cds-checklist > li::before { + content: "\2713"; + position: absolute; + left: 0; + top: 0.12em; + color: var(--action); + font-weight: 700; + line-height: 1.35; + width: 1em; + text-align: center; +} + +.cds-checklist > li > p { + margin: 0 0 0.45rem; +} + +.cds-checklist > li > p:last-child { + margin-bottom: 0; +} + +.cds-checklist a { + color: var(--link); + font-weight: 600; + text-decoration: none; +} + +.cds-checklist a:hover { + text-decoration: underline; + color: var(--link-hover); +} + +.cds-stack { + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.cds-access-footer { + font-size: 0.85rem; + color: var(--text-muted); + text-align: center; +} + +.cds-access-footer a { + color: var(--text-secondary); + text-decoration: none; +} + +.cds-access-footer a:hover { + color: var(--link-hover); +} + +/* Numbered step list (homepage “How it works”, etc.) — use on

      */ +.cds-steps { + list-style: none; + counter-reset: cds-step; + padding: 0; + margin: 0; +} + +.cds-steps > li { + counter-increment: cds-step; + position: relative; + display: block; + padding: 1rem 0 1rem calc(1.75rem + 1rem); + margin: 0; + border-bottom: 1px solid var(--border-subtle); + color: var(--text-secondary); + font-size: 0.95rem; +} + +.cds-steps > li p { + margin: 0 0 0.75rem; +} + +.cds-steps > li p:last-child { + margin-bottom: 0; +} + +.cds-steps > li::before { + content: counter(cds-step); + position: absolute; + left: 0; + top: 0.85rem; + width: 1.75rem; + height: 1.75rem; + background: rgba(2, 168, 226, 0.12); + border: 1px solid rgba(2, 168, 226, 0.4); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.75rem; + font-weight: 700; + color: var(--action); +} + +.cds-steps a, +.cds-steps .cds-link { + color: var(--link); + font-weight: 600; + text-decoration: none; +} + +.cds-steps a:hover, +.cds-steps .cds-link:hover { + text-decoration: underline; + color: var(--link-hover); +} + +/* Pattern gallery (components.html) */ +.cds-pattern-title { + font-size: 1.1rem; + font-weight: 600; + color: var(--text); + margin: 2.25rem 0 1rem; +} + +.cds-preview-box { + border: 1px solid var(--border-subtle); + border-radius: 8px; + overflow: hidden; + margin-bottom: 2rem; +} + +.cds-preview-box--dashed { + border-style: dashed; + padding: 1rem; +} + +.cds-preview-box--dashed .cds-gate-card { + margin: 0 auto; +} + +/* Max width helpers */ +.cds-mw-40 { + max-width: 40rem; +} + +.cds-mw-28 { + max-width: 28rem; +} + +.cds-demo-gap-top { + margin-top: 1rem; +} + +.cds-demo-gap-section { + margin-top: 2.5rem; +} + +/* --------------------------------------------------------------------------- + * Homepage hero (index.html) + * --------------------------------------------------------------------------- */ +.cds-hero { + min-height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; + padding: 2rem 1.25rem; + position: relative; +} + +.cds-hero__logos { + display: flex; + align-items: center; + justify-content: center; + gap: 3rem; + margin: 0 2rem 2rem; +} + +@media (max-width: 560px) { + .cds-hero__logos { + gap: 1rem; + flex-direction: column; + } +} + +.cds-hero__logo--ddev { + height: 60px; +} + +.cds-hero__logo--coder { + height: 30px; +} + +.cds-hero h1 { + font-size: clamp(2rem, 5vw, 3rem); + font-weight: 700; + letter-spacing: -0.02em; + margin-bottom: 0.75rem; + color: var(--text); +} + +.cds-hero__tagline { + font-size: 1.1rem; + color: var(--text-secondary); + max-width: 34rem; + margin-bottom: 1.75rem; + line-height: 1.55; +} + +.cds-announce { + max-width: 36rem; + margin-bottom: 1.25rem; + padding: 0.9rem 1.15rem; + text-align: left; + font-size: 0.95rem; + color: var(--text-secondary); + line-height: 1.55; + background: rgba(2, 168, 226, 0.06); + border: 1px solid rgba(2, 168, 226, 0.22); + border-radius: var(--radius-sm); +} + +.cds-hero__inner { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + max-width: 760px; + padding-bottom: 3.5rem; +} + +.cds-scroll-hint { + position: absolute; + bottom: 2rem; + left: 50%; + transform: translateX(-50%); + color: var(--text-muted); + font-size: 0.75rem; + letter-spacing: 0.06em; + text-transform: uppercase; + display: flex; + flex-direction: column; + align-items: center; + gap: 0.35rem; + animation: cds-bob 2s ease-in-out infinite; + z-index: 2; + pointer-events: none; +} + +.cds-scroll-hint::after { + content: "↓"; + font-size: 1rem; + color: var(--text-secondary); +} + +@keyframes cds-bob { + 0%, 100% { transform: translateX(-50%) translateY(0); } + 50% { transform: translateX(-50%) translateY(6px); } +} + +@media (prefers-reduced-motion: reduce) { + .cds-scroll-hint { + animation: none; + } +} + +.cds-details { + max-width: 760px; + margin: 0 auto; + padding: 5rem 1.25rem 6rem; +} + +.cds-details section { + margin-bottom: 3.25rem; +} + +.cds-details h2 { + font-size: 0.78rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.1em; + color: var(--text-muted); + margin-bottom: 1.1rem; +} + +.cds-link-list { + display: flex; + flex-direction: column; + gap: 0.55rem; +} + +.cds-link-list a { + font-size: 0.95rem; +} + +/* --------------------------------------------------------------------------- + * Radio pick cards (drupal-core.html) + * --------------------------------------------------------------------------- */ +.cds-pick-card { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + gap: 0.4rem; + text-align: center; + flex: 1 1 5.75rem; + min-width: 5.5rem; + max-width: 8.5rem; + min-height: 7.65rem; + padding: 0.5rem 0.55rem 0.6rem; + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: 10px; + cursor: pointer; + transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease; +} + +.cds-pick-card:hover { + border-color: #484f58; + background: var(--bg-elevated-hover); +} + +.cds-pick-card:has(.cds-pick-card__input:checked) { + border-color: var(--action); + box-shadow: inset 0 0 0 1px rgba(2, 168, 226, 0.35); + background: rgba(2, 168, 226, 0.07); +} + +.cds-pick-card:has(.cds-pick-card__input:focus-visible) { + outline: 2px solid var(--focus); + outline-offset: 2px; +} + +.cds-pick-card__check { + flex-shrink: 0; + width: 2.1rem; + height: 2.1rem; + border-radius: 50%; + border: 2px solid var(--border); + display: flex; + align-items: center; + justify-content: center; + margin-top: 0.18rem; + margin-bottom: 0.2rem; + background: transparent; + transition: border-color 0.15s ease, background 0.15s ease, transform 0.15s ease; +} + +.cds-pick-card__check svg { + width: 1.05rem; + height: 1.05rem; + stroke: #fff; + stroke-width: 2.75; + stroke-linecap: round; + stroke-linejoin: round; + fill: none; + opacity: 0; + transform: scale(0.65); + transition: opacity 0.15s ease, transform 0.15s ease; +} + +.cds-pick-card:has(.cds-pick-card__input:checked) .cds-pick-card__check { + background: var(--btn-primary-bg); + border-color: var(--btn-primary-bg); +} + +.cds-pick-card:has(.cds-pick-card__input:checked) .cds-pick-card__check svg { + opacity: 1; + transform: scale(1); +} + +.cds-pick-card__text { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + flex: 1 1 auto; + gap: 0.12rem; + width: 100%; + min-height: 0; +} + +.cds-pick-card__title { + font-weight: 700; + font-size: 1rem; + color: var(--text); + line-height: 1.2; +} + +.cds-pick-card__sub { + font-size: 0.72rem; + font-weight: 500; + color: var(--text-secondary); + line-height: 1.35; + max-width: 100%; } diff --git a/docs/components.html b/docs/components.html new file mode 100644 index 0000000..fd008cb --- /dev/null +++ b/docs/components.html @@ -0,0 +1,161 @@ + + + + + + Component reference — DDEV Coder Workspaces + + + + + Skip to main content + +
      + DDEV Coder Workspaces + + Component reference +
      + +
      +

      Component reference

      +

      Patterns from coder-ddev-start.css used across start.coder.ddev.com static pages, the Jekyll docs layout, and access-denied. Keep one source of truth here; use page-local styles only for layout quirks.

      + +
      + +

      Documentation nav + prose

      +

      Jekyll guides use .cds-doc-nav + .cds-doc-main (see _layouts/default.html).

      +
      + +
      +

      Sample guide title

      +

      Body copy uses var(--text-secondary). Inline link matches brand.

      +

      Section

      +
        +
      • List item one
      • +
      • List item two
      • +
      +

      inline code and a block:

      +
      ddev start
      +ddev describe
      +
      +

      Blockquotes in Markdown render as <blockquote> inside .cds-doc-main — no extra class needed.

      + Example citation +
      +
      +
      + +

      Blockquote

      +

      Guides: plain <blockquote> under .cds-doc-main. Other pages: add class="cds-blockquote" so the same rules apply outside the doc shell.

      +
      +

      Standalone quote — tips, asides, or short excerpts you author by hand on static pages.

      + Optional attribution or source +
      + +

      Tiles + buttons

      +
      +
      +

      Eyebrow

      +

      Tile title

      +

      Short description with secondary text color.

      + +
      + +
      + +

      Numbered steps

      +

      Ordered procedures with circular step counters — apply .cds-steps to an <ol> (homepage “How it works”).

      +
        +
      1. First step with a link and strong text.
      2. +
      3. Second step with nested copy. +

        Paragraph inside the step (e.g. from Markdown).

        +
      4. +
      5. Third step — inline code and a cds-link.
      6. +
      + +

      Notes + feedback strip

      +
      +

      Note #1 section title

      +

      Notes use <section> + .cds-notes + aria-labelledby with uppercase small <h2>.

      +
      +
      +
      +

      Note #2 section title

      +

      Notes make be separated by <hr class="cds-divider"> to add a horizontal rule and visually separate the sections.

      +
      + +

      Checklist

      +

      Bullets with leading check marks — .cds-checklist. Wrap each row in a block element (usually <p>) so multi-line rows stay grouped. Often nested in .cds-callout (see access-denied.html).

      +
      +
      Example qualifier block
      +
        +
      • Item with linked detail

      • +
      • Plain item

      • +
      • +

        Third item — lead sentence.

        +

        Supporting detail in a second paragraph (same row).

        +
      • +
      +
      +

      Same list pattern without the callout shell:

      +
        +
      • Docker installed on the host

      • +
      • Sysbox or rootless runtime configured

      • +
      + +

      Status + launch row

      +
      Loading example…
      +
      Error example.
      +
      Info example.
      +
      + +

      Opens in a new tab.

      +
      + +

      Access gate

      +

      Used on access-denied.html — centered with .cds-access-denied; card uses .cds-gate-card, checklist .cds-checklist.

      +
      +
      + +

      Access Required

      +

      Subtitle in muted tone.

      +
      +
      Callout title
      +
        +
      • Checklist item with link

      • +
      +
      + +
      +
      + +

      Field + URL hint

      +
      +
      + + +
      URL pattern: https://ddev-web--12x-umami--username.coder.ddev.com/
      +
      +
      + +

      + ← Home · ddev/coder-ddev · This page +

      +
      + + + diff --git a/docs/logo-coder-on-dark.svg b/docs/logo-coder-on-dark.svg new file mode 100644 index 0000000..5d30a91 --- /dev/null +++ b/docs/logo-coder-on-dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/docs/logo-ddev-on-dark.svg b/docs/logo-ddev-on-dark.svg new file mode 100644 index 0000000..dcc9f03 --- /dev/null +++ b/docs/logo-ddev-on-dark.svg @@ -0,0 +1 @@ + From 7136fa1e1584d6fa17b402e39efb512bbb3b2fe6 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Mon, 18 May 2026 22:58:01 -0500 Subject: [PATCH 06/14] refactor(docs): consolidate landing and Jekyll layout on shared CSS Replace inline CSS on index, access-denied, and the default Jekyll layout with coder-ddev-start.css. --- docs/_layouts/default.html | 138 +------------------ docs/access-denied.html | 164 ++-------------------- docs/index.html | 276 +++++-------------------------------- 3 files changed, 54 insertions(+), 524 deletions(-) diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index c24f816..5a0f0f2 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -4,143 +4,19 @@ {{ page.title }} — DDEV Coder Workspaces - + + - + - + Skip to main content -