* Restore the Ruby 4.0.6 upgrade PR #4831 committed a stale Gemfile.lock over the newer one, taking .ruby-version back to 3.2.3 and rolling back active_median, dalli, parallel, rbs and selenium-webdriver. Dockerfile and .devcontainer/Dockerfile still build on Ruby 4, so the Gemfile's version check fails against the image. Restores both files to what they were before that merge. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Tidy plantings#show, and make cards and menus consistent This page read as a page about the crop rather than about one member's planting, and its sections each did things their own way. Changes follow the conventions written up in the UI consistency guide. Identity - Title, meta description and OpenGraph all read "<crop> planting by <owner>"; the hero carries a muted "planting by X in Y" subtitle and the scientific name moves to the crop card. - Breadcrumb's last item is plain text, not a link to the current page. Actions - One actions menu per page: a quiet three-dot button in the top right of the hero, rendered by the new PlantingActions island, opening the EditPlanting, RecordHarvest, SaveSeeds, MarkFinished and AddPhoto dialogs that already existed for the garden list. - Menu items are lower case, so a menu reads as a list of things you can do rather than a row of headings. - Transplanting moves out of the sidebar into a dialog off that menu: it is done once in a planting's life and should not hold real estate. - The second seed-saving dropdown and the loose photo buttons are gone; each section keeps one quiet "add" on its heading bar as the non-JS path. - The plant-part icons from the server-rendered harvest form now reach the dialog, via icon_url on HarvestFormSerializer. Fact cards - Every card fills the same four slots, and the core cards always render so one planting's page has the same shape as the next. - Progress reads as a percentage with "day 43 of 90" beneath; quantity and "grown from" merge into one card rather than both saying "seedling"; rating is stars and renders even when unrated. - Dates go through I18n.l and standard_time_distance instead of assembling abbr_month_names by hand. - Adds Planting#planned?, replacing three copies of age_in_days < 0. - Perennial no longer claims the plant "grows back each year". Cards by type - Harvest cards get square corners, a warm accent and the harvest icon, and say "<crop> harvest", so they are not mistaken for plantings. - Seed cards are drawn as seed packets: portrait, papery, torn top edge, printed band, small print along the foot and the year saved stamped on them. Layout - The page wrapper is .planting-show, not .planting: that is the planting *card's* class, and its absolutely positioned badges and quick actions were leaking onto this page. - Sections are bordered blocks with their heading bar as the lid, so a heading and its content read as one thing. - One spacing scale, and the hero aligns to the same left edge as everything below it. Copy - Section headings and empty states go through en.yml, in one voice. - "Add a photo to visually track growth of this planting, to Flickr, iNaturalist or Pl@ntNet" was nonsense: photos come from Flickr only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Use the harvest and seed cards site-wide, and rate a planting in place The new harvest cards and seed packets only appeared on plantings#show. Everywhere else either used the old thumbnails or hand-rolled its own markup, which is what made harvests and plantings look alike in the first place. - members#show and members/_harvests render harvests/card. The latter also wrapped each card in another .card, which nested a card in a card. - The homepage harvest list was hand-rolled markup beside a seeds section that already used seeds/card; both now use the shared partials. - Homepage seed packets go in an .index-cards grid. Outside one they have no width, and the packet's 3:4 ratio made each half the page wide. - harvests/_harvest and seeds/_seed chose between card and thumbnail on a `full:` local that nothing passes. Both render the card. The crop pages' harvest and seed panels are lists of links in a sidebar, not card grids, so they are left alone. Section "add" buttons now open the same dialogs as the actions menu, via a data-planting-dialog attribute the island listens for. Their href stays as the fallback without JavaScript. The rating card is now clickable: for someone who may edit the planting it renders StarRating, which saves the new rating and puts it back if the save fails. The card's own heading is the label, so the fieldset legend is hidden rather than saying "Rating" twice. "More photos" is a plain link again, and only shows when there are more photos than the page is displaying — the photos are now paginated to 12, where before the whole set was loaded and the link always showed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Put the like button beside the planting's name It sat on its own below the hero, with a section's worth of space above and below it, reading as an orphan rather than as something belonging to the planting. It now sits on the title line, right after the name, at its own size rather than the title's. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Draw a border around the planting's own data The title, facts, photos, harvests, seeds and planned activities now sit inside one subtle border, so they read as one body of data rather than running into the sidebar beside them. Also drops the raised shadow from the like button. The global .btn shadow made the heart look like a call to action it isn't. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Tidy the planting page sidebar, and the add-photo dialog The sidebar was three blocks with three different treatments: a bare owner card, the shared crop card, and a bordered neighbours section. They now all use the same sections as the main column, with a heading bar each. - The owner block leads with the avatar and who grows this where, rather than a heading repeating "Planted by". - The crop card renders without its footer here. "Add to my garden" and "Save seeds" made no sense beside a planting you are already growing, and the page offers both already. crops/_crop takes actions: false; everywhere else keeps them. - Partials shared with other pages bring their own .card, which inside a section is a box in a box, so those are flattened. Add-photo dialog: - It now says what it is adding to: "Add photo to chives planting", rather than "Add a photo to chives". Garden cards say which garden. - While Flickr is being read the body holds roughly the height the picker will take and centres the spinner, instead of a short dialog with a spinner in the corner that jumps open when the photos arrive. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Say what kind of record a page is about in its title "Chives" is a crop. A page about one member's chives should say "Chives planting" in its heading, not leave the reader to work it out from the furniture around it. The same for harvests and saved seeds. - plantings#show: "Chives planting", subtitle "by <owner> in <garden>". - harvests#show: "Basil harvest", subtitle "by <owner> · <date>". The owner was in a %small inside the h1 before. - seeds#show: already said "seeds"; it now names who saved them. Gardens are left as they are: a garden's name is the member's own, so the noun belongs in the subtitle rather than appended to a name that may already contain it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * One corner radius for all data cards, and harvest months by season Cards used three different shapes: plantings rounded at 5%, harvests and seed packets square. A percentage radius also draws an ellipse that changes with the card's size, so a tall packet and a square planting card curved differently. There is now one $card-radius, used by every data card and by the section boxes. Harvest months are grouped into the grower's own seasons, three months each, named and kept together, starting at their spring — so a Wellington gardener sees spring begin in September. Where we have no latitude we show the plain January-to-December row rather than guessing at a hemisphere. The grower's location now appears in the page subtitle. It decides the seasons and the harvest times, so it belongs with the rest of the planting's identity rather than only as a "nearby" link in the sidebar. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Tidy the harvest months block It was loose text at the end of the timeline partial: a bare "Harvest months:" label, twelve badges, and a trailing "in <place>" that now repeats the location in the page subtitle. - Moved into its own partial with a proper label, rather than trailing off the timeline. - Dropped the repeated location. - A legend says what a highlighted month means. Nothing said so before. - The empty state is its own muted line instead of a sentence running on from the label, and no longer says "we need more data" at the reader. - Each badge carries its full month name for screen readers, and highlighted ones say they are harvest months. The quiet months were aria-hidden, so a screen reader heard the harvest months with no calendar around them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Give the sidebar crop block its own partial Reusing crops/_crop inside a section meant a card inside a box: a white strip between the green heading and the photo, the card's own shadow sitting proud of the section, a photo that overshot the right edge, and two corner radii disagreeing. Flattening it with negative margins was fighting the card rather than fixing it. plantings/_crop is written for this spot instead: the photo runs edge to edge under the heading bar, the crop's name is title-cased with its scientific name beneath, and the growing times are a short list rather than three stats laid out side by side. crops/_crop goes back to how it was, including its footer buttons, since nothing needs to suppress them now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Update the specs for the tidied planting page Mostly copy and flow changes from the tidy-up, but two real bugs came out of running them. Bugs fixed: - planting_actions_props didn't pass planted_at or today, which MarkFinishedModal needs to decide whether "today" may be offered and where the date box starts. Without them the dialog threw while rendering, and with no error boundary React tore down the whole island, so the actions menu vanished entirely. - The dialogs reloaded the page from inside the save callback, tearing the page down while the dialog was still finishing its own update. They now close first and reload on the next tick. Menu items are lower-cased in CSS, as the garden cards already do it, rather than by calling downcase on the shared button translations. That was mangling labels other pages show in sentence case. Specs: - Menu, dialog and section-heading flows updated: the actions menu opens dialogs rather than navigating, so recording a harvest, marking a planting finished, editing and transplanting all drive the dialog. - Copy: "grows this in", "day 14 of 50", "Planned" for a future planting, "4 of 5", the new harvest-months wording, and the add-photo dialog naming what it adds to. - The parent-seed example asserted a link to the planting, which came from the breadcrumb; the last crumb is the page you are on, so it is plain text now and the example checks the seed link instead. - Removed spec/features/shared_examples/append_date.rb. It drove the old datepicker finish flow and had one caller. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Stop avatars shifting the page during feature specs spec/features/places/searching_a_place_spec.rb intermittently failed on "goes to members' index page": the click on "View all members >>" landed on nothing and the browser stayed put. Member avatars come from gravatar.com over the network and were rendered with img-fluid and no dimensions, so they reserved no space until they arrived. The link sits directly under that grid. Capybara found the link, an avatar landed, the link moved, and the click missed. rails_helper meant to prevent this, but its guard tested for Poltergeist's url_blacklist. Poltergeist is long gone and Selenium's browser has no such method, so the condition was always false and the block never ran. - Give the two avatar image tags explicit width and height, so the box is reserved before the image loads. This fixes real layout shift for members too, not only the specs. - Replace the dead guard with config.x.blank_avatars, which browser specs set, making avatar_uri return a blank inline GIF. Helper specs still assert the real Gravatar URLs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Fix avatar URI logic to prevent layout shift in all environments * Add waiting assertions to prevent premature content checks after saving harvest * Refactor PlantingActions to improve dialog handling and state management Enhance PlantingRating to prevent multiple saves and improve error messaging * Fix date input handling in planting edit dialog * Add neighbour planting sidebar with improved styling and layout * Tidy crops#show, and share the record page layout The planting page's layout was planting-specific CSS. It is now a shared .record-page / .record-panel in _record_page.scss, and crops#show uses it: the crop's own data inside one border, the sidebar outside, sections as bordered blocks with a heading bar as the lid. Along the way a duplicate section rule and two copies of the kebab button styling collapsed into one each. Crop page: - Scientific and alternate names sit under the crop's name, where they belong, instead of having a sidebar card of their own. Wranglers add and edit them from the actions menu, in a dialog; the loose "Add" buttons in the page body are gone. - The actions menu is the same three-dot kebab as plantings, in the top right of the hero. The "you are a CROP WRANGLER" banner is gone: seeing the menu already tells you that. Menu items have no icons now, except delete, which keeps its icon and its red. - Growing facts were split three ways — prose in the hero, prediction cards in the main column, an OpenFarm list in the sidebar — and the hero prose was the same fields as the OpenFarm ones. One "Growing X" section of fact cards now holds all of it. - The sidebar listed planting, harvest and seed counts directly above three sections with those same names. The counts are headline numbers in the hero instead, which also fills the space the hero was wasting. - Main column reads top to bottom: how to grow it, how members grow it, varieties, companions, photos, video, where it grows, posts, history. Headings say something rather than naming a partial. - Crop actions are just "Add to my garden". Recording a harvest, saving seeds, posting and marking a planting failed all belong to a planting you already have. - The charts section rendered as an empty white strip whenever a crop had any plantings or harvests but no chart to draw. - The hero photo moved to the sidebar, where it has room. Also: the whimsical icons perch on the heading bar below them rather than sitting inside the box, the garden picker dialog gives every row the same shape so the names line up, and crops/_grown_for.html.haml is deleted — nothing rendered it once its content moved into the growing cards. Specs are not updated yet: crop_detail_page_spec clicks "Record harvest" on this page, which no longer exists. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Refactor crop-related views and styles for improved layout and functionality - Update styles in _crops.scss for better alignment and spacing. - Enhance _record_page.scss with a new section footer for actions. - Modify _alternate_names.html.haml to improve dropdown functionality for editing and deleting names. - Change _history.html.haml header to "Edit history" for clarity. - Adjust _info.haml to display sowing method and sun requirements prominently. - Revise _openfarm_data.html.haml to remove unnecessary comments and clarify content. - Update _photos.html.haml to include a section footer for the "More photos" link. - Refine _posts.html.haml to streamline the display of posts and actions. - Improve _scientific_names.html.haml to enhance dropdown functionality for scientific names. - Update tests in alternate_name_spec.rb and scientific_name_spec.rb to reflect UI changes. - Remove unused _grown_for.html.haml_spec.rb file. * Replace language text field with a dropdown select for improved user experience * Enhance editable forms and fact cards for improved user interaction and layout * Refactor styles and improve layout for planting details, including muted text color updates and enhanced card displays * Refactor crop detail page for improved SEO and user experience, including updated links and content for planting and growing information. * Adjust section add button width for better layout on heading bar * Update link text for consistency and clarity in crop detail page --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Daniel O'Connor <daniel.oconnor@gmail.com>
14 KiB
Design rules
Growstuff strives for consistent design. This is very much a work in progress. Much of the site predates this document. Where a page disagrees with a rule here, the rule is the target; fix it when you're next in there.
A page says what it is about
A record page names its record type in the heading. Not "Chives" — that's a crop. "Chives planting". Harvests and saved seeds do the same.
| Record | h1 |
Subtitle, muted |
|---|---|---|
| Planting | <crop> planting |
by <owner> in <garden> |
| Harvest | <crop> harvest |
by <owner> · <date> |
| Seed | <crop> seeds |
saved by <owner> |
The noun goes in the h1 itself, not only in the subtitle. A garden is the
exception: its name is the member's own, so the noun sits in the subtitle
rather than being appended to a name that may already contain it.
The <title> tag and the OpenGraph title carry the same sentence, so a shared
link announces the same thing the page does.
Where the grower is goes in the subtitle too. It decides the seasons and the harvest times, so it's one of the first things worth knowing.
The actions menu
Every record page carries one actions menu: a three-dot (kebab) button, in the top right of the hero, on the title's line. Plantings and crops both use it; the rest should follow.
┌──────────────────────────────────────────────┐
│ 🌱 Sunflower ⋮ │ ← the kebab, top right
│ by shiny in The Deck │
There is no separate banner saying you may edit something. Seeing the menu at all is what tells you that.
- Quiet, not raised: transparent, no border, a muted icon that darkens on hover, focus and while the menu is open.
- Items in order: edit, add photo, the state changes, then a divider, then delete last.
- Rendered only when the member may edit the record.
- One menu per page. No second dropdown further down, and no loose buttons doing the same job.
- No nested dropdowns and no forms inside the menu.
- No icons on the items — the words are the list, and a column of little pictures beside them is noise. Delete is the exception: it keeps its icon and its red, so the one dangerous item still looks dangerous.
- Items are lower case, done in CSS (
text-transform: lowercaseon.dropdown-item). Never by callingdowncaseon the label — those strings are buttons elsewhere, where they read as sentence case. - Rare actions belong in the menu rather than the page. Transplanting happens once in a planting's life, so it takes no permanent room in the sidebar; the menu item opens it in a dialog.
Forms open over the page
Adding or changing one record opens a dialog, saves, and leaves the member where they were. Photos, harvests, saved seeds, editing a planting and marking one finished all work this way.
- The dialog is the whole form, not a picker that then navigates away.
- It says what it is acting on: "Add photo to chives planting", not "Add a photo to chives".
- Icons that helped on the old form come with it — the plant-part pictures in the harvest dialog, for instance.
- While it is loading, it holds roughly the height it will end up, with the spinner centred, so it doesn't jump open when the content arrives.
Section headings and their "add"
Every section that can take a new record carries the same control: a small "+ add" button at the right-hand end of its green heading bar.
┌──────────────────────────────────────────────────────┐
│ Harvests [ + add ]│ ← green bar
├──────────────────────────────────────────────────────┤
│ No harvests recorded yet. │ ← white body
└──────────────────────────────────────────────────────┘
- Inside the bar, not above or below it, and not out at the column edge. An "add" floating in the whitespace beside a heading reads as unrelated to the section it acts on.
- A plus icon, then the word "add", lower case. The heading beside it already says what is being added, so the button doesn't repeat it: "add", not "Add harvest".
- Outlined, not filled. Transparent background with a thin white border, white text, smaller than the heading. It sits on the green without competing with it, and fills slightly on hover and focus.
- The same control everywhere — harvests, seeds saved, photos. A section with nothing to add (activities) simply has no button, and its bar is otherwise identical.
- It opens the dialog, and its
hrefis the fallback for a ctrl-click or a member without JavaScript.
Other links in a section body are plain links, not buttons: "More photos" is a link, and only appears when there are more photos than the page is already showing.
The record panel
Everything that is the record — its title, its facts, its photos, its harvests, its planned activities — sits inside one subtle bordered panel. The sidebar sits outside it.
┌─────────────────────────────────────────┐ ┌──────────────┐
│ 🌱 Common Thyme planting ⋮ │ │ Grower │
│ by shiny in The Deck · Wellington │ ├──────────────┤
│ │ │ … │
│ HARVEST MONTHS │ └──────────────┘
│ Not enough data on this crop yet. │
│ │ ┌──────────────┐
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ │ Crop │
│ │fact│ │fact│ │fact│ │fact│ │ ├──────────────┤
│ └────┘ └────┘ └────┘ └────┘ │ │ … │
│ │ └──────────────┘
│ ┌─────────────────────────────────────┐ │
│ │ Harvests [+ add] │ │ sidebar:
│ ├─────────────────────────────────────┤ │ outside the
│ │ No harvests recorded yet. │ │ panel
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘
the record panel
Without it the page runs straight into the sidebar and reads as one flat wash of content. The border says: this is the thing you came here for; that other stuff is context.
- Subtle and dark, a hairline rather than a heavy rule, with the same corner radius as everything else.
- No background of its own. The page colour shows through, so the white sections inside it still stand out.
- The hero is inside it, with no side padding of its own, so the title starts on the same left edge as every section below it.
- One spacing scale between the sections it holds.
This is the pattern for every record page, not just plantings. Harvests, saved seeds and gardens should each get the same panel around their own data, with the sidebar outside it.
Sections within the panel
A section is a bordered block with its green heading bar as the lid, so the heading and the content beneath it read as one thing. Sidebar blocks use the same vocabulary, so the two columns look related without looking identical.
Two traps:
- Don't nest a grid card inside a section. A partial written for
.index-cardsbrings its own card, shadow and radius; inside a section that's a box in a box — a white strip under the heading, a shadow sitting proud of the border, an image overshooting the edge. Write a partial for that spot instead; flattening the card with negative margins is fighting it. - Give the page wrapper its own class.
.plantingis the planting card, and its absolutely positioned badges will leak onto the page. The page is.planting-show, and the panel inside it is.planting-detail.
Cards
Scrolling a mixed grid, you should know what kind of thing each card is before reading a word of it. A planting, a harvest and a packet of seeds are three different things and should not look alike.
Each record type has one _card partial, used everywhere that type appears
in a grid — the same card on the record's page, the member's page, the crop
page and the homepage, not a different look per page.
Cards are for grids. In a narrow sidebar they become one huge photo per item, so a sidebar shows a compact row instead — a small square thumbnail, then the one or two facts that matter there. The neighbours list is the example: the crop is the same for every row, so each says who grows it and where.
What stays the same for the grid cards: a photo, the crop name, a link to the
record, an owner credit, and one shared corner radius ($card-radius, a fixed length — a
percentage draws an ellipse that changes with the card's size). Cards are told
apart by colour, proportion and texture, never by their corners.
Planting
┌──────────────────┐
│ │
│ photo │
│ │
├──────────────────┤
│ Cos lettuce │
│ [harvesting now]│ ← badges
│ ▓▓▓▓▓▓░░░░ 61% │ ← how far along it is
├──────────────────┤
│ Planted by skud │
│ in Back Garden │
└──────────────────┘
A planting is a span of time, so the card shows where it has got to: white, green accent, badges and a progress bar.
Harvest
┌══════════════════┐ ← warm accent along the top
│ │
│ photo │
│ 🧺 │ ← the harvest icon, on the photo
├──────────────────┤
│ Cos lettuce │
│ harvest │
│ ( leaf ) │ ← plant part, in the warm accent
├──────────────────┤
│ picked 3 Mar │
│ by skud │
└──────────────────┘
A harvest is an event: one crop, one plant part, one day. So where a planting card shows progress, a harvest card shows the date it happened, and the title says "<crop> harvest" rather than just the crop. The warm accent and the icon are what separate it from a planting at a glance.
Seed
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ← torn top edge
┌──────────────────┐
│ ┌──────────────┐ │
│ │ illustration│ │ ← inset window, printed frame
│ │ saved │ │ ← the year, stamped at an angle
│ │ 2026 ⟋ │ │
│ └──────────────┘ │
│ COS LETTUCE │ ← printed band
│ seeds saved by │
│ skud │
│ ················ │
│ 20 SEEDS · SOW │ ← the small print
│ BEFORE MAR 2027 │
└──────────────────┘
A seed card is drawn as a seed packet: portrait (3:4), a papery ground rather than white, a torn strip across the top, the photo inset behind a printed frame, the crop name in a bold printed band, and the small print along the foot — quantity, sow-by date, organic, whether it's up for trade.
A home-saved packet has the year written on it, so ours does too: the year saved, stamped at a slight angle in the corner of the window.
The risk with a decorative card is that it gets hard to scan in a long trading list, so the crop name and the sow-by date stay at normal contrast; the paper, the frame and the tear carry the theming.
Fact cards
The small cards on a record page each hold one fact. The value slot holds
one thing — a number, a word or an icon — never a compound like 43/90 or
4/5, and the sub-line beneath always renders so the cards line up.
- Progress reads as a percentage, with "day 43 of 90" beneath.
- Quantity and what it was grown from are one card, not two both saying "seedling".
- Rating is stars you can click to rate, not a number.
- Say what's true: a perennial keeps growing year to year — it doesn't "grow back each year".
Harvest months
Grouped into the grower's own seasons: three months each, named, starting at their spring — March in the northern hemisphere, September in the southern. Where we have no latitude, show the plain twelve-month row rather than guessing at a hemisphere.
Whenever months or badges are highlighted to mean something, a legend says what the highlighting means.
Small things
The like button sits on the title line, beside the name it belongs to, at its own size. It's a quiet control, not a raised one.