feat: home screen and navigation design
This commit is contained in:
1 parent
30a4df47b1
commit
930b836241
24 files changed
+1774
-19
No files matched your search
@@ -0,0 +1,124 @@
|
||||
Feature: Home screen
|
||||
|
||||
As a logged-in RenewCMS owner
|
||||
I want /home to summarize how many articles I have, how many are online or drafts, and my five
|
||||
most recently updated articles, all from the single GET /v1/article/ call the route already
|
||||
makes
|
||||
So that I land somewhere useful after logging in, instead of an empty dashboard or a screen that
|
||||
silently fails
|
||||
|
||||
Background:
|
||||
Given /home is a verified route (meta.auth "verified") rendered as HomePage inside
|
||||
DashboardShell, per docs/design/routes.md
|
||||
And HomePage calls GET /v1/article/ once per navigation; there is no separate stats endpoint,
|
||||
so the three stat tiles and the recent list are both derived from that one response
|
||||
And the PageHeader shows breadcrumb "Home" (mobile title "Home") and a primary action "New
|
||||
article" opening NewArticleModal
|
||||
And a "Connect your website" card is always rendered on the page, in every state (Loading,
|
||||
Default, Empty and Error alike): icon plug, title "Connect your website", text "Your site
|
||||
reads published articles from RenewCMS. Share this guide with whoever builds it.", and a
|
||||
link "Open the guide" navigating to /integration
|
||||
And a greeting reading "{greeting}, {username}" sits above the subtitle in every state
|
||||
(Loading, Default, Empty and Error alike); it is computed from the session's username and
|
||||
the device's local hour via Date.getHours(), needs no request of its own since the session
|
||||
is already resolved by the app-boot flow before HomePage ever renders, and so never has its
|
||||
own loading or error state
|
||||
And hours 0 through 11 give the greeting "Good morning", hours 12 through 17 give "Good
|
||||
afternoon", and hours 18 through 23 give "Good evening"
|
||||
And once the list resolves with at least one article, the subtitle reads "Here's where things
|
||||
stand on your site.", three stat tiles show the total article count labelled "articles", the
|
||||
online count labelled "online" and the draft count labelled "drafts", and a recent list shows
|
||||
the 5 most recently updated articles, each with its title, an ArticleStatusBadge (online or
|
||||
draft) and its updated date, linking to /article/:id/edit
|
||||
And while the list request is in flight, skeleton placeholders replace the stat tiles and the
|
||||
recent list rows, but only after 150 ms, so a fast response never flashes a skeleton
|
||||
And when the list resolves with zero articles, the subtitle reads "Welcome to RenewCMS.", and
|
||||
the stat tiles and recent list are replaced by an empty state: icon file-text, title "Write
|
||||
your first article", text "It starts as a draft, so nothing appears on your site until you
|
||||
publish it.", and a single action "New article" that opens NewArticleModal
|
||||
And when the list request fails with a 500 or a network error, the breadcrumb, greeting and
|
||||
subtitle stay visible, the subtitle stays "Here's where things stand on your site.", and the
|
||||
stat tiles and recent list are replaced by an inline role="alert" banner: icon circle-x,
|
||||
title "Couldn't load your articles", text "Check your connection and try again.", and a
|
||||
single action "Try again"
|
||||
|
||||
Scenario: Skeletons appear only after 150 ms, never for a fast response
|
||||
Given the user navigates to /home for the first time in this session
|
||||
When GET /v1/article/ has not resolved 150 ms after the navigation
|
||||
Then skeleton placeholders replace the three stat tiles and the five recent-list rows
|
||||
And the recent list container is aria-busy="true"
|
||||
When GET /v1/article/ then resolves 200 with a non-empty list of articles
|
||||
Then the skeletons are replaced by the Default state's stat tiles and recent list
|
||||
Given a second, separate navigation to /home
|
||||
When GET /v1/article/ resolves in under 150 ms with a non-empty list of articles
|
||||
Then no skeleton is ever shown, and the Default state's content renders directly
|
||||
|
||||
Scenario: Default — the list loaded with a mix of online and draft articles
|
||||
Given GET /v1/article/ resolves 200 with 6 articles, 4 online and 2 drafts, most recently
|
||||
updated first: "How we price a bathroom renovation" (online), "Winter checklist for timber
|
||||
windows" (online), "Choosing tiles for a small bathroom" (draft), "A guide to underfloor
|
||||
heating" (online), "When to reseal a stone worktop" (draft), and "Small bathroom lighting
|
||||
ideas" (online, least recently updated)
|
||||
When the user navigates to /home
|
||||
Then the subtitle reads "Here's where things stand on your site."
|
||||
And the stat tiles read "6" "articles", "4" "online" and "2" "drafts"
|
||||
And the recent list shows exactly the first 5 articles above, in that order, each with its
|
||||
ArticleStatusBadge and updated date, and each row links to its /article/:id/edit
|
||||
And "Small bathroom lighting ideas" does not appear in the recent list
|
||||
And the "Connect your website" card's "Open the guide" link navigates to /integration, and
|
||||
the header's "New article" action opens NewArticleModal
|
||||
|
||||
Scenario: Empty, first run — zero articles
|
||||
Given GET /v1/article/ resolves 200 with zero articles
|
||||
When the user navigates to /home
|
||||
Then the subtitle reads "Welcome to RenewCMS."
|
||||
And no stat tiles are shown
|
||||
And an empty state is shown in place of the recent list: icon file-text, title "Write your
|
||||
first article", text "It starts as a draft, so nothing appears on your site until you
|
||||
publish it.", and a single action "New article"
|
||||
When the user activates "New article"
|
||||
Then NewArticleModal opens
|
||||
|
||||
Scenario Outline: Error — a 500 or a network failure shows the same inline alert
|
||||
Given GET /v1/article/ <failure>
|
||||
When the user navigates to /home
|
||||
Then the breadcrumb, greeting and subtitle remain visible, and the subtitle stays "Here's
|
||||
where things stand on your site."
|
||||
And no stat tiles or recent list are shown
|
||||
And an inline alert with role="alert" is shown in their place: icon circle-x, title
|
||||
"Couldn't load your articles", text "Check your connection and try again.", and a single
|
||||
action "Try again"
|
||||
|
||||
Examples:
|
||||
| failure |
|
||||
| fails with a 500 response |
|
||||
| never reaches the server |
|
||||
|
||||
Scenario: Retry re-issues the request and recovers into the Default state
|
||||
Given the user is on /home in the Error state, because GET /v1/article/ failed
|
||||
When the user activates "Try again"
|
||||
Then GET /v1/article/ is called again
|
||||
When it resolves 200 with 6 articles, 4 online and 2 drafts
|
||||
Then the Alert is replaced by the stat tiles reading "6" "articles", "4" "online", "2" "drafts",
|
||||
and the recent list
|
||||
|
||||
Scenario: The list is fetched exactly once per navigation
|
||||
Given the user navigates to /home
|
||||
Then GET /v1/article/ is called exactly once
|
||||
And both the stat tiles and the recent list are derived from that single response, with no
|
||||
second request made for either
|
||||
|
||||
Scenario Outline: The greeting matches the hour of day
|
||||
Given the session's username is "marta"
|
||||
And the device's local hour is <hour>
|
||||
When the user views /home
|
||||
Then the greeting above the subtitle reads "<greeting>, marta"
|
||||
|
||||
Examples:
|
||||
| hour | greeting |
|
||||
| 0 | Good morning |
|
||||
| 11 | Good morning |
|
||||
| 12 | Good afternoon |
|
||||
| 17 | Good afternoon |
|
||||
| 18 | Good evening |
|
||||
| 23 | Good evening |
|
||||
Reference in new issue
Block a user