feat(blog): sync loaders, types, and draft lifecycle with deco-cx/apps - #94
Open
aka-sacci-ccr wants to merge 2 commits into
Open
feat(blog): sync loaders, types, and draft lifecycle with deco-cx/apps#94aka-sacci-ccr wants to merge 2 commits into
aka-sacci-ccr wants to merge 2 commits into
Conversation
Ports the recent deco-cx/apps blog work (up to #1658) to the TanStack
Start port. The loaders here are sync and have no ctx, so each change is
adapted rather than copied.
Types:
- PostStatus + isPublishedStatus() — an allowlist, so a status this app
does not recognize is treated as not ready and never leaks into a
listing. An absent status stays published: the field was added long
after the first posts, so requiring it would empty every live blog.
- BlogPost.status / .dateModified, Author.type, Category.description /
.sections, BlogPostListingPage.category / .categories, Publisher.
Core:
- dateToTime() compares full ISO timestamps and pins offset-less values
to UTC, so ordering no longer depends on the machine timezone. The
previous `${date}T00:00:00` produced NaN for any date carrying a time.
- filterRoutablePosts() drops slugless and unpublished posts before
slicePosts, so `count` still yields `count` renderable posts.
- getRecordsByPath skips blocks with no string `name` instead of
emitting a record with `id: undefined`.
Loaders:
- BlogPostItem / BlogPostPage still serve an unpublished post — that page
is the CMS preview — but force noIndexing so it cannot be indexed.
- BlogpostListing always returns the category list and resolves the
active category from the collection (so it carries description and
sections), falling back to the copy inlined on a post.
- GetCategories filters categories missing a name or slug before sorting;
the guard is shared with BlogpostListing as isValidCategory.
- New BlogpostList loader. The loader map pointed
blog/loaders/BlogpostList at BlogpostListing, which returns a
BlogPostListingPage rather than the BlogPost[] callers expect.
The manifest generator did not list blog, so blog/manifest.gen.ts was
stale and missing BlogPostItem. Added and regenerated.
Sections, actions, db/schema and the ratings/reviews/views extensions are
deliberately left out: they are Preact components or depend on drizzle
and ctx.invoke.records, neither of which exists in this port.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The file was renamed to loaderMap.ts, but package.json kept exporting the old path, so the subpath resolved to a file that no longer exists. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Objetivo
Sincronizar o app
blogdoapps-startcom o estado atual dedeco-cx/apps@main(blog/na v0.161.1, incluindo o #1658 — draft/published lifecycle), portando o que faz sentido no runtime TanStack Start.O que foi portado
Ciclo de vida draft/published (paridade com deco-cx/apps#1658)
PostStatus(draft | published | archived | generating | awaiting_review) eisPublishedStatus()emblog/types.ts, com allowlist: status desconhecido = post que o CMS não considera pronto, logo fora das listagens.publishedexplícito esvaziaria os blogs em produção no bump.filterRoutablePosts()roda antes doslicePosts, entãocountcontinua entregandocountposts renderizáveis. Também derruba posts semslug(não têm rota).BlogPostPageeBlogPostItemcontinuam servindo post não publicado — aquela página é o preview do CMS — mas forçamseo.noIndexing.Loaders novos
blog/loaders/BlogpostList.ts—BlogPost[]puro, sem wrapper depageInfo/seo(diferente doBlogpostListing).blog/loaders/BlogPostItem.ts— post único por slug, retornandoBlogPostdireto.loaderMap.ts(chaves com e sem.ts, casando os__resolveTypedo app Deno) e nomanifest.gen.ts.Ajustes de fidelidade
handlePosts/sortPosts: parse de data pinado em UTC (ISO_WITHOUT_TIMEZONE), fallback0em data inválida para não vazarNaNno comparador,VALID_SORT_ORDERSvalidado.BlogpostListing: categorias sempre retornadas (menus, chips) e falha na leitura delas não derruba a listagem; categoria ativa vem da collection, com a cópia inline do post como fallback.GetCategories:isValidCategoryextraído e reutilizado peloBlogpostListing— categoria semname/slugnão é linkável e quebraria olocaleCompare.blogadicionado aoscripts/generate-manifests.ts, então o manifest agora é gerado e não editado à mão.package.json:./blog/commerceLoadersapontava parablog/commerceLoaders.ts, arquivo já renomeado paraloaderMap.ts— subpath quebrado. Agora aponta para o arquivo certo e o nome atual (./blog/loaderMap) também está exportado.filterRoutablePosts,isPublishedStatus,PostStatus,Publisher.O que ficou de fora (de propósito)
view_asc/view_desc) e todo o resto que depende de Deco Records/Drizzle:actions/submit{Rating,Review,View},loaders/extensions/*(ratings/reviews),db/schema.ts. Sem Drizzle nesse runtime;SortBynão expõe as opções de view e umsortBy=view_*vindo da URL cai no default por data.sections/*(Template, blocos de conteúdo, SEO JSON-LD) — o port é loaders-only; renderização fica no storefront.imageCarouselemBlogPost— campo puramente de conteúdo, sem nenhuma section aqui para consumir.Testes
blog/__tests__/handlePosts.test.tseblog/__tests__/loaders.test.tscobrem sort/filter/slice, o lifecycle de status, paginação, fallback de categoria e os dois loaders novos.