Redesign the homepage and docs theme - #202
Conversation
Rebuild the site around the Goravel mark. The mark is treated as real geometry rather than a logo: the lattice it is cut from, its five pieces, and the path a request takes through it are derived from public/logo.svg and shared by every drawing on the site. Homepage (layout: goravel-home) The stock VitePress home layout showed an adjective headline and six emoji feature cards with no code on the page. It is replaced by seven full height sections, each carrying one idea and something the reader can work: - Hero: the same route written in Laravel PHP and in Goravel Go, so the reason a Laravel developer would switch is visible before any scroll - Follow one request: GET /tasks stop by stop, with the file and the lines that run at each stop - Laravel's structure, written in Go: eight concepts in both languages, with the matching lines lit together in each file - Five layers, thirty facades: the mark pulled apart, a piece at a time - Start with the core: Goravel Lite filling in from 4 of 30 facades - Open source: stars, contributors and the community links the page has always carried Sections advance themselves while on screen, stop the moment the reader picks a tab, and hold still under prefers-reduced-motion. Documentation shell - Three column grid with one rule per column edge: the sidebar column runs unbroken from the top of the screen, and everything to its right is capped by a single hairline under the header - Rules inside a column run from that column's rule to the edge of the screen, so no rule stops in the middle of the page - Header is one row on the page's own grid: wordmark, links, search, language and project links, with no dividers of its own - Search is a first class control, matching the outlined button, and its modal is one white sheet - Sidebar rows carry no rules; section, page and current page are told apart by weight and a 2px accent on the column edge - Outline rail leads with On this page; the method index, built from the rendered page, follows it No markdown content changes. Sidebar groups are collapsed by default and reordered so Upgrade and Prologue come last.
The comparison carried one line per concept in places, which showed the naming matches but not that the shape of the code matches. Each concept now shows enough of the real call to be judged: - Validation shows the rules map and what happens when it fails - Queues shows job arguments and the queue it goes on - Cache shows Remember with the closure that fills it - ORM adds the limit so the chain reads as a chain - Scheduling wraps the way it is actually written Testing is added as a concept, since it is one of the reasons to pick a framework at all: a feature test hitting /tasks and asserting 200, in PHPUnit and in Goravel's suite. Every Go snippet uses the API as documented: facades.Cache().Remember, facades.Queue().Job().OnQueue().Dispatch, s.Http(s.T()).Get and response.AssertStatus. Also ignore design/, which holds the design sources rather than code that ships with the site.
The homepage speaks in small mono labels marked with the lattice cell the mark is cut from. The docs used the same mono but not the same marker, so the two read as separate products. - The layer tag becomes a label: uppercase, tracked, with a cyan cell - On this page and Methods take the same cell in construct grey - The method index drops to 11.5px on an 18px line and gains air above it, so it reads as an aid to the outline rather than a second outline A page now says which layer of the framework it belongs to in the same voice the homepage used to teach the five layers.
The bar mixed destinations with controls: Quickstart and Translate were content links, Versions and Video Tutorials were menus, and none of them described the shape of the documentation. Four destinations now do: - Docs, the way in: installation, configuration, structure - Guides, the how to: the basics, digging deeper, database, ORM, testing, security, AI - Framework, the internals: lifecycle, container, providers, facades - Community, a menu: GitHub, Discord, the video series, the contribution guide and how to add a language Versions leaves the bar because the sidebar already carries a version control, and Translate leaves it because the locale switcher already sits beside the search. Each destination sets an activeMatch so the bar shows where the reader is. Applied to all three locales.
Three gaps found while reading the page rather than measuring it. The thirty facades on the homepage were plain text. They are the quickest way into the reference, so each one now links to the page that documents it, from Route through to Telemetry. The Community menu pulled every link into one list. It now carries three sections laid side by side, each with a label in the shell's voice: Connect, Learn and Contribute. A menu with sections reads as sections. The Lite build skipped a layer. Four steps added one piece each and then Install everything filled in the Application layer along with the other twenty four facades, so one of the five pieces never arrived on its own. Adding Validation gives every layer its own moment: core, HTTP, data, async, application, then the whole set.
The menu was a rounded card floating over the page on a shadow, sitting on top of the bar's own rule. That is the one thing this design does not do anywhere else, and no amount of adjusting its padding was going to fix it, which is what the last few passes were doing. It is now a panel. Its top edge is the bar's rule. Its columns are divided by verticals that run the panel's full height, from that rule down to the panel's own rule, which bleeds the width of the screen. Its content stands on the same grid as the bar above it, 96px in on the homepage and 40px in the docs. Rows carry an icon: a brand mark where the destination has one people already know, a line drawn at the shell's own weight where it does not. Both sit back in grey and follow the label to the accent. The theme's external arrow goes, since the icon already says where a row leads. The locale switch keeps the small sheet. It is a control with three options, not a section of the site.
The video series and the written guides were the only two rows still carrying a favicon fetched from youtube.com and devchalk.com: a third party request from the navigation, a raster mark that cannot take the row's colour, and a weight that did not match the icons beside it. Both are drawn now. The play mark is deliberately generic, because that row points at YouTube in English and Uzbek and at Bilibili in Chinese. On the installation page, "Tip" was a level four heading wearing a callout's clothes. It put an entry in the page outline that is not a section, and gave the page an anchor of %E2%9C%85-tip. It is a tip container now, which is what it always was. Three sibling headings lose the emoji they were carrying, and a horizontal rule that sat between two headings goes, since the headings already do that work. Applied to all three locales.
Three headings lost their emoji in the last change. That was my call and it was the wrong one: an emoji in a heading an author chose is a voice, not noise, and stripping it is not mine to decide. The Tip container stays, because that was a different problem: a heading that was not a section, putting an entry in the outline and giving the page an anchor of %E2%9C%85-tip.
Typography - Mona Sans for text and headings, IBM Plex Mono kept for code and labels. Width carries the display voice, so the homepage and page titles take a wider cut and the docs stay at normal width. - Body moves to 17px/29px. Measured across 318 rendered lines: median 68 characters, which is what the measure token always claimed. - Name a CJK fallback per platform, since Mona Sans covers latin only. Callouts - info, tip, warning and danger were two looks for four names. Each now has its own ground, rule weight and mark. Severity is the one place the palette gives way: warning takes amber, danger red, both confined to a near-white tint, a 2px rule and an 8px mark. - A title an author typed is set as text, not as a type label. The markup VitePress emits is identical either way, so the container renderer is wrapped to mark the difference. - details reads as a disclosure: the lattice mark leads, a chevron closes the row and turns when it opens. The shell - A docs page carries no site navigation, because the sidebar is the navigation there. The bar keeps the wordmark, search, version, language and the project. The homepage keeps the destinations. - Goravel / Docs is one lockup, so the word no longer appears in the bar twice. Discord and X leave the bar and live in Community only. - Version and language are the same control built the same way, and the version chooser lists versions, not the hostnames they are served from. - Search sits over the article column and is exactly as wide as the measure. - The bar is one object across the site: one inset at every page and width. - Community links move to a docs footer, which the hidden nav would otherwise have stranded. Markdown - Add footnotes, task lists, sub, sup and definition lists, none of which VitePress ships, and style each in the existing vocabulary. - Enable Shiki's word-highlight transformers, so both the comment and the fence syntax work instead of rendering as text. - Convert 15 blockquotes that were doing a callout's job into typed containers, classified by what each does to the reader rather than by the word Note, and mirror them into the other two locales where the count matches. Two are left for someone who reads the language. - Drop 180 dead toc directives: the outline carries the headings beside the article and the local nav carries them on a phone. Code blocks - The line-number gutter had no line-height of its own and inherited the body's, so every number drifted four pixels further from its line. Across 105 blocks the worst drift is now one pixel. - A block that scrolls inside itself cannot keep a gutter in sync, so the upgrade guide drops its numbers and wraps rather than clipping lines. - Diff blocks get room for their markers. - Code inside a callout is the same block on a lighter ground, and that ground is painted to the band's edges rather than laid out, so the gutter and the text keep a normal block's geometry. - Keep the language label visible on hover. Elsewhere - Brand marks in the community menu carry their owner's colour and the video row follows its own platform per locale. - Serve the wordmark from a resampled asset: the original is an indexed PNG the browser had to take down elevenfold. - The primary button was white on cyan at 2.95:1. Ink on the same cyan measures 6.07:1. - Consolidate the stylesheets: no selector is now declared twice, verified by comparing 116,348 computed properties across 3,422 elements before and after.
- Code inside a callout paints its ground to the band's edges. The block clipped its own overflow, which cut the header rule back to the inset box while the ground bled past it; the horizontal scroll lives on the pre, so the block no longer clips. At narrow widths the theme already bleeds code by 24px, so the rule takes no extra offset there. - The sidebar and the outline each had three active signals at once: a colour, a weight and a bar. Each now has one. The page you are on is cyan with the lattice mark beside its label; the section you are in goes to ink with the same mark. - The docs footer is one row of the next few places to go, not a second site navigation. The homepage keeps the fuller footer. - A heading sits close to the paragraph it introduces and far from the section before it, so long pages read as chapters while scrolling. - Small technical labels move from 11px to 12px.
- Rewrite goravel.css and shell.css so every element is styled once. Tables, the pager, callouts and code blocks were each declared up to five times. A band now bleeds through two variables instead of a copy of every rule for each width. - Replace the VitePress nav bar with a component of our own, and fold the version and language menus into one component. The language menu links to the same page in each language through VitePress's own helper, and both menus close on Escape, on a click outside and when focus leaves. - Components carry their own scoped styles; shell.css only restyles the default theme's frame, sidebar, outline and search. - Style the Algolia modal through its variables where it has them. - Draw the menu icons from Iconify instead of hand-written paths. - The homepage drops code it never used: a hero view, text-on-face geometry, translations of strings it does not show, overrides for the nav bar it replaced, and the raw HTML bodies of its three index pages. The two cycling hooks are one. Fixes - The upgrade guide scrolled the whole page sideways on a phone and painted past the column rule on desktop. Its text now starts on the article's edge. - A code group is one band, so inside a callout it no longer sits in a grey box of its own. - Open menu chevrons pointed left instead of up. - Search result icons were 48px tall with a stray rule across them. - On a phone, nested quotes and footnotes overflowed the screen and the sidebar mark covered its label. Between 768px and 959px, bands stopped 8px short of the screen edge. Checked by comparing computed styles and geometry of 48,000 elements across 10 pages at three widths, a cascade check that leaves no declaration that never applies, and a code block audit over 78 pages.
- Open Collective carries its own logo in its brand colour instead of a generic heart. - Contribution Guide and Add a Language draw from Lucide, whose strokes hold up at menu size better than Carbon's thin glyphs. Carbon is no longer used. - Every menu icon is 20px, so brand marks, glyphs and the DevChalk avatar sit on one size instead of three.
- The mark is a fixed SVG drawing with two small tables: piece shapes and the request's stops. CSS turns it, pulls pieces out and draws the route on with pathLength, so the projection maths in geometry.ts and the Stage wrapper are gone. Every figure shares one viewBox and lines keep their pixel width with non-scaling strokes. - Menu icons are Iconify classes from the Tailwind plugin, and GitHub uses the theme's own social icon, replacing the code that built SVG strings. The Community menu is built by one function instead of three copies. - The syntax theme is one short scope table. The dark palette is gone with dark mode, which had no design and rendered code white on a light ground for readers whose system is dark. - DocMeta reads the page's own file path and keeps one layer table; MethodIndex collects methods in one pass. - Comments are kept only where they explain a workaround or a number. Fixes - The phone menu showed an external arrow on its own line under every Community row, because the theme only omits it for links holding an svg. It now uses the desktop panel's labels and spacing. - At 1100px the version and language menus were squeezed by the search. - Shiki's inline ground on each pre made code inside a callout grey again. Checked with a computed style diff across 10 pages at three widths, every code character on 11 pages, the breadcrumb and method index on all 74 English pages, and side by side screenshots of every mark state.
The first crumb uses the nav's own label for each language, and the layer label goes through the homepage translations, so Chinese and Uzbek pages no longer show English there.
Docs - The method index only lists real method names, so Telemetry and the ORM guide no longer show their section headings as methods. - Code block headers put the label on the article's edge. A first line that is only a file path comment becomes the header title. - The sidebar marks the current page with colour and the diamond only. - The layer label above an article links to the layers on the homepage. - Small mono labels move from 11px to 12px. Homepage - Laravel's structure lists its concepts down the side and stacks the PHP and Go files, so it no longer repeats the tabs and panel above it. - Start with the core runs the install as a sequence of commands, and the mark assembles beside it as each layer's pieces slide into place. - The open source section ends on one row of links. The WeChat QR codes open on click instead of four blocks, and the footer is tighter.
hwbrzzl
left a comment
There was a problem hiding this comment.
I'm thinking if it's better to remove the UZ language, given we don't have enough energy to maintain multiple languages, and it's easy to translate any language via browsers' AI.
- Above 1440px the homepage content box stopped every full-width rule short of the screen edge. The page margin now grows with the screen instead, so rules bleed to both edges at any width. - The Laravel and Lite sections gain a top rule, so their column rule no longer starts in empty space. - The docs sidebar keeps its width above 1440px. The theme widened it there, covering the start of the article. - The pager's rule belongs to the pager, so it spans the band even without a previous page, and on a phone the next page's rule runs edge to edge. - Link hairlines in the open source row are underlines, not borders.
Yes, we can remove Uzbek in a separate PR so this diff stays reviewable. |
Fixes - The Chinese and Uzbek homepages linked facades and footer links to the English docs, and left stats labels, footer headings and the copyright in English. They now use the page's language, and the footer's language names are links. - Menus and the WeChat QR codes did not close on a click outside in Safari, which does not focus a clicked button. One helper built on @vueuse/core closes them on an outside click, Escape, or focus leaving. - @shikijs/transformers is back on v3, the version VitePress already uses, so the highlighter is not installed twice. - Remove the old VitePress homepage styles and the emoji web font they loaded on every page. Cleanups - The uppercase label and the diamond marker are each defined once, with one letter spacing. - Homepage columns and callout bands share their common rules, and the five code blocks render through one CodeLines component. - External links and the version list live in links.ts. Contributors are names, with avatars built from them. - useCycle uses vueuse for observing, timing, visibility and reduced motion. - The locale sidebars keep master's formatting, i18n.ts moves to the theme root, and two type errors are fixed.
🤖 Automated reviewThis is an AI-generated code review. Please double-check each finding before acting. SummaryPR #202 rebuilds the docs theme and homepage: a custom Verdict
FindingsMust Fix
Should Fix
Nits
Automated Checks
|
- Each piece of the mark uses the path and colour of public/logo.svg: light blue on top, cyan on the right, dark teal on the left, flat with no outlines. The three colours are tokens used only by the mark. - A piece out of focus becomes a pale tint of its own colour, so the logo stays recognisable. Your own code (the Service stop) leaves every piece pale, and a layer Lite has not installed waits outside as an outline. - The request route and its marker are drawn in ink, so they read on any of the blues. The rotation in the Laravel section is gone. - Code blocks no longer show a scrollbar when the code fits. The tint of a lit line bleeds past the text from the block, not from each line.
- Get started has white text. It sits on the deeper cyan, since white on the bright cyan is 2.95:1 and unreadable for many; on the deeper one it is 4.9:1. Hover turns the button ink. - The homepage runs Artisan as go run . artisan, which works on Windows too, in the Lite steps and the Laravel comparison. - Contributor avatars are in colour. - The second hero button opens Compare with Laravel instead of a page next to the one Get started opens. - The sidebar starts with Prologue and Upgrade again, as on master, in all three languages. - Less space above section headings in the docs: 60px instead of 84px.
Past 1440px the docs article stayed 800px and the outline column took the rest, which left most of a wide screen empty. The site now stops at 1440px, the width its homepage and docs are laid out for, and sits centred with a border on each side running top to bottom. Every full-width rule ends on those borders. The nav, the sidebar and the Community menu are fixed to the screen, so they are placed inside the frame by the same offset. Nothing changes at 1440px or below.
- The nav and the Community menu render their own links, so they skipped the default theme's rule that adds .html to page links while clean URLs are off. They now use the theme's normalizeLink, the same helper as the default nav. The docs footer writes .html like the homepage footer does. All links now match the pages' real addresses, not a server fallback. - markdown-it-sub is removed. No page uses subscript, and it turned the Chinese release notes' (~Q1和~Q3) into a subscript "Q1和".
- Stars and forks come from GitHub in the visitor's browser, without a token. The answer is kept for an hour, and a refusal also waits an hour, so a visitor asks GitHub at most once an hour. - Until that answer arrives, or if GitHub refuses, the page shows the numbers read when the site was built. If the build cannot reach GitHub either, it uses a saved copy, so a build never fails. - The current release is read at build time. The contributor count is the length of the hand-kept list, so it always matches the avatars shown.
|
@hwbrzzl Done, the stats are live now. They come from GitHub's public API, so no token is needed. That API only allows 60 requests an hour per visitor, so I added a few fallbacks:
For contributors, I kept the list manual, and the count comes from that list so it always matches the avatars. |
Chinese - The 404 page, the method index and "Your code" on the homepage are translated, and the 404 page links stay in the reader's language. - The homepage drawing's screen reader labels are built from translated words instead of English sentences. - The rate limiting heading has the id rate-limiting, so the homepage's RateLimiter link lands on it. The v1.10 upgrade guide's link follows. Docs - Notes still written as "Notice:" or "注意:" quotes are callouts, with the same type in English and Chinese. Loading - The homepage component loads only on the homepages. The code every doc page downloads drops from 140KB to 113KB (45KB to 36KB gzipped). - Fonts are requested from the page head, so they download alongside the stylesheet instead of after it.
…ndings - The packages page draws its coverage bars when the site is built, so they no longer depend on a script reading the rendered table afterwards. - The Chinese sidebar lists AI before Security, as English does. - The version label, the thirty facades and the contributor count each come from the list they describe instead of a second copy of the number. - The contributor list sits with the homepage's other data. - The method index avoids :has(), which a browser without support rejects for the whole selector, leaving no index at all. - The breadcrumb copes with a sidebar that is not a list of groups. - The footer logo reserves its width, so the footer does not jump. - A pull request is built the way a deploy is, so dead links and build errors show up before merging.
Replace the request-flow and five-layer sections with a page that shows what Goravel ships, using the brand mark as art instead of a diagram. - Hero: the mark on its isometric grid, one call to action and a copyable install command - Laravel, line for line: PHP and Go pairs with matching lines highlighted, keyboard-accessible tabs that tour once and stop when the reader picks one - 30 facades, one framework: an alphabetical facade index plus six capability cells with verbatim snippets (one process, gin or fiber, Docker-backed tests, AI SDK, telemetry, one binary) - Start with the core: the mark assembles as Lite facades are installed, with a running count - Open source: live stars, a release and support timeline read from prologue/releases.md, core team, contributors and ways to join All release-specific content lives in .vitepress/theme/home/config.ts. The page is split into one component per section, GoravelMark is reduced to pieces, grid and states, and home.css drops the rules for the removed sections. Unused translation keys are removed and Chinese strings added for the new copy. Also: - nav: replace the mislabelled Guides and Framework links with Packages and Releases - load the default theme without its bundled Inter fonts - docs: fix two broken links in compare-with-laravel.md and the core developer profile link in contributions.md
- task-scheduling: replace the Chinese table headers on the English page with Method and Description, and fix the "Crone" typo - artisan-console: the route handler used *gin.Context, which is not a Goravel handler. Use func(ctx http.Context) http.Response in the English, Chinese and Uzbek pages, and Route().Get instead of the nonexistent GET on the Chinese page - homepage: update the title, description, Open Graph and Twitter text in English and Chinese to match the new page, and replace meta.png with a card rendered from the new hero
Clicking a tab left the section dead: mouse focus and hover both paused the line highlight, and a manual pick stopped the tab tour for good. - the line highlight keeps running after a mouse click, even while the pointer rests on the card - the tab tour resumes 8 seconds after a manual pick, once the pointer has left the card - hover only holds the tabs in place, so the code cannot switch while it is being read - keyboard focus (focus-visible), reduced motion, off-screen and a hidden browser tab still pause everything Also fix the tour stalling on tabs with a single matching pair (Events, Artisan): the highlight never moved there, so the tour never advanced. Every tab now stays for at least three beats before moving on. Replace useCycle with a smaller useTicker and move the tour logic into HomeLaravel, its only user.
Notes written as plain "Note:" lines, emoji "Tip:" lines or blockquotes now use the tip, info and warning containers the rest of the docs use. Applied to the same spots in English and Chinese. - packages: info and tip containers, the how-to steps moved inside the tip as a numbered list, stray asterisk removed from the table header - facades, authentication, orm, routing, testing, filesystem, installation, configuration: blockquotes and "Note:" lines converted, each typed by what it says (tip, info or warning) - task-scheduling: the "one server" note listed memcached and dynamodb, which Goravel has no drivers for. It now says the default cache must be shared by all servers, such as redis, and that memory will not work - installation: remove emoji from headings - normalise ":::tip" to "::: tip" in both languages
The page showed two status columns of check marks and an unlabelled "code example" column in plain text, with absolute links that broke on the versioned sites and sent Chinese readers to English pages. - one table, Feature, Laravel, Goravel, with real inline code on both sides and relative links. Applied to English and Chinese - correct four Goravel examples that did not match the API: Gate.Allows takes a map, Mail.To takes a slice, ValidateRequest needs an argument, and Event and Queue Job need the args slice - add examples to the rows that had none (Testing, Mock, Package Development) and rename labels to match where they link: Routing, Migrations, Logging, ORM - where one framework lacks a feature, the cell shows its mark greyed out with a cross and the words, instead of an emoji Add a Brand component for docs pages: <Brand laravel />, <Brand goravel /> and the "no" variant. The table headers use it. Pages with "aside: false" now take the full content width instead of leaving an empty right rail, and feature names in the first column of doc tables no longer break mid-word.
…s en and zh_CN - correct Avg, AcceptJSON and View().Exists to match the framework - use # comments in shell blocks so copied commands run - repoint 34 broken anchors, add the missing Cache Key Prefix section - require Golang 1.25, mention Goravel Lite in the installer step - label 22 code blocks, drop Eloquent wording, fix typos
🤖 Automated reviewThis is an AI-generated code review. Please double-check each finding before acting. SummaryRe-review at Verdict
FindingsMust Fix
Should Fix
Nits
Automated Checks
Resolved since the first review: footer/nav One note for the eventual uz removal: the locale name is hardcoded in several places ( |
- layer badge is a plain label now that the homepage has no layers section - restore the layer label translations for zh_CN and uz_UZ - footer columns follow the FOOTER config instead of a fixed count - fail the build clearly when logo.svg pieces or a release date cannot be read - fetch only the star count and pass GITHUB_TOKEN to the docs build - giscus en-US locale key, Brand goravel prop, version label fallback
…ry pages Neither page has section headings, so the "On this page" column rendered empty with its rule. Both now set aside: false, as the Laravel comparison page does, in en, zh_CN and uz_UZ. The content takes the full width and the package descriptions fit on one line. Also on the packages page: goravel/gemini (51.8%) moves above goravel/sqlite (45.2%) so the table is in coverage order as its note says, and the English intro is reworded.











What
A redesign of the homepage and the docs theme.
// config/app.go.Notes for review
GoravelMark.vue. To change the drawing, edit its paths.[[toc]]lines were removed.Testing
Checked in Chrome and Firefox at desktop, tablet and phone widths, in English, Chinese and Uzbek.
pnpm docs:buildpasses.