feat(landing): DocsUI::Landing — a config-driven marketing landing page#55
Merged
Conversation
Every consuming site (and this dogfood site) was hand-rolling a home page. Add a shared DocsUI::Landing component driven by a new c.landing config block (DocsKit::LandingConfig): - a hero: eyebrow, title (wrap a run in **double asterisks** to accent it in the primary color), lead, an optional install code snippet, and CTA buttons; - a features card grid; and - a registry-grouped documentation index built from nav_groups, so it never drifts from the authored pages. Every field is optional — with an empty c.landing it still renders a minimal hero (brand + doc index), never a broken page — and its .md/.text twin works like any page (it composes DocsUI::Shell, rendered layout:false). - lib/docs_kit/landing_config.rb: the config + Cta/Feature value objects (Hash → value-object normalization, like TopbarLink), wired as c.landing (memoized like c.seo). - app/components/docs_ui/landing.rb: the component. - Generator: landings#show now renders DocsUI::Landing; the initializer template documents c.landing. - Dogfood: the docs-kit site's own landing now uses it (config in the initializer), proving the pattern on a real site. This is the first landing pattern proven on a MOUNTED docs app (a docs section inside a larger Rails app whose "/" is already taken) — contributed back from that use case. Tests: 91 config/component-config examples + a dogfood request spec; full gem suite 755 green, 94.7% line coverage, rubocop clean.
The docs_chrome system spec asserts have_link('Get started', href: '/docs/overview');
the dogfood landing config pointed it at /docs/installation. Align the CTA with
the existing chrome contract.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Every consuming site — and this dogfood site — hand-rolls its home page: a hero, some feature cards, and a list of doc links. That's the same shape every time, so it should be a component you configure, not code you copy.
This gap is sharpest on a mounted docs app — a docs section living inside a larger Rails app whose
/is already taken (e.g. an authenticated dashboard). There, the landing can't live at/like a standalone docs site; it lives at the docs root, and the app owns the layout. This PR is contributed back from exactly that use case (a fintech app mounting its developer docs at/docs), which is the first time the landing pattern has been exercised outside a standalone site.What
A shared
DocsUI::Landingcomponent driven by a newc.landingconfig block (DocsKit::LandingConfig):eyebrow,title(wrap a run in**double asterisks**to accent it in the primary color, so a site can highlight a word without HTML),lead, an optionalinstallcode snippet, andctas.featurescards (lucide icon + title + body).nav_groups, so it never drifts from the authored pages. Toggle withc.landing.doc_index = false.Every field is optional — with an empty
c.landingit still renders a minimal hero (brand + doc index), never a broken page. It composesDocsUI::Shell(a full document), so it renders withlayout: falselikeDocsUI::Page, and its.md/.texttwin works like any page.Changed
lib/docs_kit/landing_config.rb— the config plusCta/Featurevalue objects (Hash → value-object normalization, mirroringTopbarLink). Wired asc.landing, memoized likec.seo.app/components/docs_ui/landing.rb— the component.landings#shownow rendersDocsUI::Landing; the initializer template documentsc.landing.docs/config/initializers/docs_kit.rb), replacing the hand-rolledViews::Landings::Show.Tests
spec/docs_kit/landing_config_spec.rb— the config + value objects (defaults, normalization,btn_class,external?, install lexer).spec/docs_kit/configuration_spec.rb—#landingreturns a memoizedLandingConfig.docs/spec/requests/progressive_enhancement_spec.rb— the rendered landing (hero title with the highlighted span, a feature, a CTA, the doc index) served with JS off.Full gem suite 755 examples, 0 failures, 94.7% line coverage; rubocop clean (131 files); dogfood request specs green.
Notes
The component spec is a config/value-object unit spec rather than a full-render spec, because rendering
DocsUI::Shellstandalone needs a live Rails view context (csrf_meta_tags/stylesheet_link_tag/ importmap tags) — the same reasonDocsUI::Pageisn't loaded in the Rails-free suite. The full render is covered by the dogfood request spec, matching how the existing chrome is tested.Follow-up (not in this PR): a
DocsUI::Landingsection on the Components doc page.