Skip to content

feat(storybook): post categories, clearer wording and timed changes for Plus in Feed Explain and Tune - #6960

Merged
idoshamun merged 35 commits into
mainfrom
claude/settings-personalization-303eed
Oct 19, 2026
Merged

idoshamun merged 35 commits into
mainfrom
claude/settings-personalization-303eed

Conversation

@idoshamun

@idoshamun idoshamun commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

Changes

Feed Explain, Feed settings and Tune in Storybook, after the personalization demo. One change reaches production: the Content preferences copy, described at the end.

Demo fixes

  • Post categories. The 14 categories (News, Opinions, Tutorials, Drama, Hot takes and the rest) are wired end to end. A hidden category drops posts that didn't come from a follow, the same as challenger/5.0's $allowed_cc(). Cards show a post's category as a row with Hide. The complaint box understands "too much drama" or "a break from hot takes". Tune gets a Categories tab that uses the same useFeedSettings/useAdvancedSettings hooks as Content preferences, with how many posts of each kind your next page has. Content preferences stays where it is.
  • Shared wording and tooltips. policy/glossary.ts holds one verb, effect and undo line per action (Follow, Show more, Show less, Stop learning, Fewer like this, Hide, Block). Cards, the complaint box, Feed settings and Tune all use it, with a one-line tooltip on each control. "Not interested" and a bare "Less" are retired.
  • Timed changes as Plus. Show less, Stop learning, blocks and hidden categories can last 3 days, 1 week or until you change them, with "until Thu" shown where they're set. Free viewers keep "Until I change it", and the other two are locked behind the shared PlusSection. Plus viewers also get a "Changes that end on their own" list with End now.
  • The downvote card is the Explain card, in a Downvote mode that says why the post was shown.

Review fixes since the demo

  • Category rows on cards are plain rows, like topics and sources.
  • Tune and the Feed settings lists keep their order while you click. A row shows its new state where it is, and only reopening re-sorts.
  • The leave notice has real padding and clearer copy, with specific undo buttons like "Unhide Tutorials".
  • The Plus divider is centered, with a Get Plus button under the section. Tune's topic and source rows open the same Plus section as the card's topic popover, from their boost.

Data

The per-post categories in policy/postCurations.ts come from a read-only production query for the 64 story posts. The public Post type doesn't expose them.

Production change

FeedSettingsContentPreferencesSection used to call every switch a hard filter that "won't show up at all". For categories that isn't true. daily-api sends hidden categories as allowed_content_curations, and both For You arms apply that only to posts that didn't come from a follow: lofn's default filter wraps $allowed_cc() in ($follow() || …), and challenger/5.0 does the same. The copy now says that categories you turn off still come through from sources and squads you follow. The rest of the section is unchanged.

Events

No new tracking events.

Experiment

No new experiments.

Manual Testing

  • Every Feed settings page, Tune and the Explain stories, at 1440 and 375, with no horizontal overflow, as both free and Plus viewers.
  • pnpm --filter webapp test, the full webapp tsc, and a local Storybook build, after syncing with main.

Preview domain

https://claude-settings-personalization.preview.app.daily.dev

The Personalization center was a page of its own, so most people would
never find it. This design rebuilds Feed settings around it instead, in
a new "Features/Feed Settings" story group that uses the real settings
menu pieces, the webapp's AccountPageContainer and the phone ShellBlock.

Feed settings becomes:
- Overview (new, first): learn from my reading, the AI agent, what
  shapes For You at a glance, your next page, and Start over.
- Topics (was Tags): follows and topics from reading with their boosts,
  then the real tag directory.
- Sources and people (was Content sources): follows with boosts and a
  search for more.
- Ranking (new): every ranking setting.
- Filters: the real Content preferences and Blocked sections on one
  page. It is the only place to unblock; Topics and Sources link to it.
- AI superpowers and General, unchanged.

The separate Personalization page is gone. The feed's Feed settings
button, the dock and card links open the matching settings page. msw
handlers answer the real blocked lists and feed preferences from the
personalization store, so a block or an Undo from either side shows on
the other. On a phone the changes bar shows once there is something to
undo, above the page's search field.
The page lists only what you follow and its boosts, so the Follow a
source chips and their search go. With no search field on the page, the
phone changes bar no longer moves up for one.
Both sections render their parts as siblings and take their spacing from
the page around them. The real settings pages wrap every section in a
flex column with gap-4; the design rendered these two bare, so the
banner, dividers and fields sat flush against each other.
Topics, Sources and people, Ranking and the Overview used their own card
style, so next to Filters, AI superpowers and General they looked like a
separate product. They now use the feed settings sections' language: a
bold title over a tertiary description, plain list rows, dividers
between blocks, and secondary buttons. Changes confirm in the app's
toast with Undo instead of a floating bar, and the prototype goes back
to the feed from the page heading.

Your next page and the Left out list are gone. They belonged to the
single Personalization page and don't make sense in settings pages;
the Overview keeps learning, what shapes your feed, your AI agent and
Start over.
The agent is the quickest way to change everything on these pages, so it
now sits right under the page intro, above Learn from your reading.
…trols

Moving personalization into Feed settings lost the single page where a
change showed in the feed right away. Tune brings that back on For You:
the topic, source and ranking controls sit in a panel beside the feed
(a bottom sheet on phones), the page re-ranks as you change them, and
cards that moved show New or how many places they moved. The panel's
footer counts what changed and offers Undo; Done keeps the new page.

Tune opens from the Explain bar or from a settings page's Live preview,
and links back to the matching settings page.

Settings and Tune render from one list, rankingControls, which names
each control's settings page and Tune tab. A control added to one of
its sections, or a new entry, shows up in both, so neither can fall
behind. The learning switch moved into its own section so both can
share it.
Free viewers choose what's in their feed; Plus viewers set exact numbers.
Free gets follow, block, Fewer like this and a level per topic (Off, Less
or Auto) and per source (Less or Auto). Plus swaps the levels for the
exact boost sliders and unlocks the Ranking page, which free viewers see
read only behind the feed settings Plus banner.

Every screen story has a Free and Plus switch that updates the signed-in
user, so the real Plus checks (usePlusSubscription, the settings menu,
AI superpowers) follow it. The new Features/Feed Free vs Plus stories
show the split, "Too much AI" on each plan, a card topic, and the Topics
and Ranking pages on desktop and phone.

"Too much AI" on a free account has to work, but lowering a topic's
boost barely moves the page: its posts also come in through other topics
and follows. So in the story's policy, Less and Off push down every post
that carries the topic, and Less halves instead of the config's 0.8,
which left the page unchanged. Show less AI sets the whole AI family to
Less on every plan, and the Topics page lists turned-down topics that
aren't in the profile. What's off? suggestions that set a number show a
Plus tag and Get Plus for free viewers.

The popular fill-in switch moves from Ranking to the Overview, next to
Learn from your reading, so Ranking is all Plus.
Off read like Block, but it only stopped a topic counting as an interest.
Not interested is the phrase people know from other feeds for "stop
recommending this", so the free level is now Not interested, Less or
Auto. Picking it on a topic or source you follow also unfollows it,
since you can't be not interested in something you follow; following
again clears it.

Sources get the same three levels. A source set to Not interested has its
posts pushed down like Less. The card row reads "Not interested" with
Undo, What's off? offers "Not interested in AI", and the Plus slider's
bottom reads "No boost" so Off never shows next to Block.
Brings Tune, the live feed beside the personalization controls, onto the
branch with the free vs Plus split, so one branch has all of it. The
Popular posts switch becomes its own section in rankingControls, so it
shows on the Overview and on Tune's Ranking tab above the locked ranking
settings, and a page's controls get a divider between them.
Shared pieces for the cards, the complaint box, Feed settings and Tune.

- policy/glossary.ts: one verb, effect and undo line per feed action
  (Follow, Show more, Show less, Stop learning, Fewer like this, Hide a
  category, Block, plus Auto, Unfollow, Unblock and Just this post), with
  describeAction for tooltips.
- policy/timed.ts: durations (3 days, 1 week, until I change it),
  expiry keys for topic and source levels and for blocks, formatUntil
  ("until Sun", "until Thu, Oct 22"), getActiveState, which the policy
  now applies so an ended change is ignored, and the messages for the
  notice when one ends.
- State gains expiries. The store takes a clock (now), clears changes that
  already ended and says so, takes an optional duration on Show less,
  Show more, Stop learning and blocks, and adds fewerLikeThis, which
  removes the post and, with a duration, shows less of its main topic.
- Not interested is retired. Stop learning replaces it on topics: reading
  stops counting but a follow keeps its base weight, and nothing is
  unfollowed. Sources keep Show less and Auto. The level pickers use the
  glossary verbs, and Segmented options take a description shown as a
  tooltip.
- Fix: the Sources page used isDemoted without defining it.
…x card

Cards
- Every icon button and level has a tooltip from the glossary, so Follow,
  Block and Fewer like this say what they do.
- The topic boost popover lists Show more, Auto, Show less and Stop
  learning with what each does, plus how long (3 days, 1 week, until I
  change it). Rows and leave notices say "Showing less until Sun" or
  "Blocked until Thu, Oct 22".
- Fewer like this asks how far to go: just this post, or show less of its
  main topic for 3 days or a week.

Complaint box
- Each suggestion says what changes, what stays, how to undo it, and its
  effect on the next page from the policy preview ("AI goes from 6 posts
  to 4 on your next page").
- Complaints that sound temporary ("a break from Fireship for a few
  days") offer Show less and Block for 3 days, a week or until changed.

After a downvote
- In place of "Don't show me posts from...", the card shows why the post
  was there and the likeliest fixes (Show less of its topic, Show less from
  its source, or just remove it) with a duration, plus Report, Don't ask
  again and Explain my feed, which turns Explain on at that card.

Also: tall popovers stay on screen and scroll; the What it needs story
notes that downvotes aren't evidence in the inferred profile and that
changes can't expire today; stories 15 and 16 show the fix card and a
break that ended; Free vs Plus copy uses the glossary verbs.
The user wants categories kept in Feed settings > Content preferences
and also in Tune. Tune gets a Categories tab whose section reads and
writes through the same useFeedSettings and useAdvancedSettings hooks
and the same list helper as Content preferences, so a category turned
off in one shows off in the other.

rankingControls entries can now name the existing settings section that
already shows them, so the Filters page doesn't render the control twice
while Tune still gets it from the shared list. The settings mocks serve
the 14 categories daily-api seeds, and keep advanced settings across
refetches.
…and the fix card

The 14 post categories (content curation) from daily-api's seeds, wired
end to end and waiting on the real per-post values, which the public Post
type doesn't expose. Until they arrive, no post has a category and
nothing below shows.

- policy/curation.ts: the categories (id, setting title, one-post label)
  and postCurations, the map the real values go into.
- State gains blockedCurations. A hidden category removes a post unless
  it came from a follow, like $allowed_cc() in challenger/5.0
  (blocked_curation). Hiding can be timed like blocks, and its end shows
  in the notice. The store adds setCurationHidden.
- Cards: a post with categories shows them in place of its least telling
  topic row, as chips with a one-tap Hide each, so the card keeps its
  height. Leave notices say "You hid Drama" with Show again.
- Complaint box: "too much drama", "no memes", "only tutorials" and
  "a break from hot takes" map to Hide (timed when temporary) or Hide
  everything but; "more tutorials" says the feed can only hide kinds.
- Downvote fix card: Hide its category, for a post not from a follow.
- What it needs: categories on the Post type, and a setting for every
  kind the feed assigns (the seeds have 14, the captured production
  settings list 8).
… and Tune

Topic and source rows take the level pickers' new glossary verbs and add
the card's "How long" choice once a level is set (3 days, 1 week, until
I change it), with "Show less until Thu, then back to Auto." while it
runs. A new section lists every change that ends on its own, blocks
set from cards included, each with End now. It sits at the top of the
Overview and of Tune's Topics tab, and hides while nothing is timed, so
rankingControls entries can now say when they show.

Follow, Unfollow, the turned-down topics and the Tune categories carry
the glossary line as a tooltip, and the categories say that sources you
follow still come through. Tune's tabs scroll on a phone and the desktop
panel is wide enough for all four.
…timing

Tune's Categories tab and Content preferences now read and write the
store's blockedCurations through the settings API mocks, so a kind of
post hidden on a card, in the complaint box, in Tune or in Content
preferences shows hidden everywhere and changes the feed. The mocks take
the category list from policy/curation.ts and keep only the API's
descriptions.

A hidden category in Tune offers the same How long choice as the other
levels and says when it shows again; timed hides join the changes that
end on their own. Each category will say how many posts of its kind are
on your next page once posts carry categories, like the cards. The
Overview's Filters summary counts hidden kinds too.

Settings and Tune share one hook that binds the mocks to the store and
refetches blocks and feed settings when they change; feed settings
never refetch on mount, so the inactive ones refetch too.
Fills the story's per-post categories with post.contentCuration for
exactly the 64 story posts, read from the production database with one
read-only query on the replica. Every post had one category: Opinion 29,
Story 20, News 5, Tutorial 4, Release 4, Hot take 2. A post with none
would stay out rather than be guessed.

Cards now show each post's kind with Hide, the complaint box counts
them on the page, and Tune's category counts can read the same map.
Content preferences called every switch a hard filter that stops a post
from showing at all. For categories that isn't so: daily-api sends
hidden categories as allowed_content_curations, and both For You arms
apply them only to posts that didn't come from a follow. lofn's default
filter wraps $allowed_cc() in ($follow() || ...), and challenger/5.0
does the same. So the copy now says categories you turn off still come
through from sources and squads you follow, which matches the Hide
wording in Feed Explain, and keeps the rest of the section as it is.
…nge them

The user found Tune hard to follow when a click moved rows: following a
topic from reading jumped it into Topics you follow, a new boost re-sorted
the list, and a timed change made a section appear at the top.

Lists now keep the order and grouping they had when their page or tab
opened (useFrozenGroups). A row shows its new state where it is: a topic
followed from reading stays under Topics from your reading with Unfollow,
an unfollowed source or person stays with Follow, and a change ended
from the timed list stays, marked ended. New rows join the end of their
list, and which sections show is decided when the page or tab opens.
Opening Tune or the page again sorts afresh.
Review feedback on the Explain cards.

- Categories: each of a post's categories is its own row, styled like
  the topic and source rows (label and a meta line, no icon, text lined
  up with theirs) with the same Block-style button, which hides it. They
  always come last, after the topics and the source, and the card keeps
  three rows so nothing moves.
- Timed changes are Plus. plus.tsx gains isTimedLocked and
  PlusDurationPicker: for free viewers 3 days and a week show the Plus
  mark and can't be picked, with a Plus line, and Until I change it stays
  free. It gates the topic popover, Fewer like this (which gains a free
  Show less until changed choice), the complaint box suggestions and the
  downvote fix card. Segmented options can be locked. bootAsPlus moves
  to plus.tsx, and Card states and A break that ended boot as Plus.
- The complaint box rebuilds its suggestions on every complaint, so a
  repeated one picks up the viewer's current plan.
The user wants "for a few days" to be a Plus feature. Topic, source and
category timing in settings and Tune now use the cards session's
PlusDurationPicker: free viewers keep "Until I change it", while 3 days
and 1 week are locked with the Plus line, and a locked choice never
reaches the store. "Changes that end on their own" shows only for Plus;
rankingControls' isShown takes the plan, and the shown sections are
decided again when the plan changes.

Also drops a duplicate Duration import in plus.tsx that the merge of
58d4bd2 left behind and that stopped the stories from compiling.
The notice's message stretched to fill the panel, so the icon sat on
the divider and the button on the card's bottom border. Now icon, title,
message and button are one group with 12px gaps, padded like the rest
of the panel and centered below the divider, on grid and list cards.

Also: "for a week" counts as a temporary complaint, and the leave note
after Fewer like this names the lowered topic even when it lasts until
changed.
…f Plus icons

Leave notice (follows the spacing fix in 572fddc, which was already
shared with the settings branch, so this is a new commit rather than an
amend):
- Title: "You won't see this after a refresh".
- The message says only what you did: "You hid Tutorial posts.", "You
  blocked DEV.", "You stopped learning from #career.". The follow
  exception for hidden kinds moves to a tooltip.
- The button names the exact reverse: "Unhide Tutorials", "Unblock
  DEV", "Unblock #rust", "Learn #career again", "Set #career back to
  Auto", "Follow Fireship", and Undo for Fewer like this. All fit on one
  line at 375.

Plus section:
- plus.tsx PlusSection: the Plus badge on a divider, with one Get Plus
  link for free viewers; everything under it is Plus, locked for free
  viewers and unlocked for Plus, with no Plus icon on each control.
- The topic popover keeps the free levels on top and puts the exact
  boost slider (a dimmed, disabled bar with its value for free viewers)
  and How long under the section, replacing the pink upsell sentence.
- Fewer like this puts its timed choices under the section.
- PlusDurationPicker renders as a section, so the complaint box and the
  downvote fix card match; locked duration chips are dimmed without
  icons.
Topic and source rows now follow the card's topic popover: the free
levels come first for every viewer, then the boost as a chip that opens
a PlusSection with the exact boost and, once a level is set, How long.
Free viewers see the slider dimmed with its value and 3 days and 1 week
locked, under one Get Plus link; Plus viewers get the same controls
unlocked. The section opens on its own when a level is set, so How
long is never hidden, and the chip keeps a long list from carrying a
Plus section on every row.

The Plus banners at the top of Topics and Sources go, since each row
now names what Plus adds, and the two sections share one description
for both plans.
A downvote now opens the same overlay as Explain mode instead of a
separate fix card: the card head on the real card's pixels, the divider,
the reason line led by "You downvoted this.", and the same topic, source
and category rows. On these rows the Follow button becomes Show less,
which asks how long (until changed, or 3 days and a week in a Plus
section). Block and Hide stay as they are, so a change that drops the
post shows the same leave notice with its fix.

The footer keeps the Explain layout with Report, Don't ask again and
Explain my feed, and a close button takes the place of the position
number. Report shows a centered thank-you notice built from the same
piece as the leave notice.

Stop popular fill-ins and Just remove this post are gone from the
downvote card; Explain mode never offered them either.
…lus label

The downvote card's line read as two unrelated sentences ("You downvoted
this. You've read a few posts about #docker."). It now gives the policy's
reason as a cause, "We showed it because you read about #docker.", with
"You downvoted it. Change what brought it here:" under it, so the rows
read as the answer. Each case has its own cause: a followed topic or
source, a learned or boosted topic, and a popular fill-in ("We added it
because your topics ran short.").

A popular fill-in now leads its rows with a Popular fill-ins row whose
block button stops fill-ins, so that reason can be acted on too, in
Explain mode as well.

To fit the prompt line, the downvote card's rows sit one step closer and
its padding is a little tighter. A two-line reason still fits the
3-line-title grid cards and the phone list.

The Plus section now centers the Plus label on its rule, and free viewers
get a Get Plus button under the last Plus control instead of a link on
the rule. Plus viewers see the label only.
@vercel

vercel Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
daily-webapp Ready Ready Preview Oct 19, 2026 2:50pm UTC
storybook Ready Ready Preview Oct 19, 2026 2:50pm UTC

Request Review

@idoshamun
idoshamun enabled auto-merge (squash) October 19, 2026 14:47
@idoshamun
idoshamun merged commit 5a407fb into main Oct 19, 2026
13 checks passed
@idoshamun
idoshamun deleted the claude/settings-personalization-303eed branch October 19, 2026 14:55

This branch was successfully deployed

2 active deployments
Preview – daily-webapp — 004946fc Deployed Oct 19, 2026 by vercel[bot]
Preview – storybook — 004946fc Deployed Oct 19, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant