โ All Skills Knowledge History
gallery-apps standalone app: Picsum infinite-scroll gallery
galleryinfinite-scrollpicsummonoFetchrestfulcorsapp-renamemono-skills
Summary
gallery-apps โ standalone Picsum infinite-scroll app
This app (gallery-apps, on the branch of the same name) is a Vue/Vite mono remote whose
single feature is an image gallery at /gallery that loads photos from the public Picsum
API with infinite scroll. It started as a gallery page added on the memo-apps branch, then
was split off into its own mono app: the memo feature was removed and the app was renamed
my-memo โ gallery-apps.
Feature stack (Rule 15)
mono.config.tsโname: 'gallery-apps';Photosrestful endpoint (https://picsum.photos/v2) infetching.api; menu = singleGalleryentry.src/datas/tables/gallery.tsโPicsumPhototype,GALLERY_PAGE_SIZE = 30,thumbUrl(p, w, h)(/id/{id}/{w}/{h}) so the grid loads thumbnails, not originals.src/stores/use-gallery.tsโuseGalleryGalleryAppsstore (photos / page / loading / hasMore / error,loadMore()/reset()).src/pages/gallery/index.vueโ thin page; responsive UnoCSS grid + a bottom sentinel watched byuseIntersectionObserver(rootMargin 300px).
Reusable gotchas
monoFetchreturns a bare array inres.all, notres.data.useNormalFetchreturns{ data: responseData?.data, all: responseData, ... }; Picsum returns a bare array, so readres.all. (For non-{data}-shaped REST responses, useres.all.)monoFetch+ a public API can be CORS-blocked. It always sendsContent-Type: application/json(forces a preflight) and attachesAuthorization=[REDACTED] when aMONO_tokenRefreshcookie exists. Picsum's preflight allowscontent-typebut NOTauthorization, so an authenticated session would be blocked. The store triesmonoFetchfirst (base URL viamonoRestBaseUrl('Photos')) and falls back to nativefetch`.- Renaming a mono app is cascading. App id =
mono.config.tsnameโ drives@<name>/*aliases, must matchpackage.jsonname, and is the store-export/key suffix (Rule 8:useGalleryMyMemoโuseGalleryGalleryApps, keygallery-gallery-apps). After editing the two name fields, runmono prepareto regenerate.mono/tsconfig.jsonaliases; restart Vite (deletesrc/auto-imports.d.tsfirst) so the auto-import dts re-scans cleanly โ it merges rather than pruning deleted exports on a warm start. - MONO Skills is app-scoped, immutable, no CLI delete.
saveis skipped while the app uses a template-default name (incl.mono-vue-remote), so rename before saving. To move a session between apps, delete the files via the GitHub contents API and re-save under the new app id. (This session was moved my-memo โ gallery-apps that way.)
Verification
vue-tsc --noEmitclean for app files (only the pre-existing hostimport.meta.clienterror remains); Vite dev serves/gallery,/memois gone, auto-imports show onlyuseGalleryGalleryApps; branchgallery-appspushed to origin.
Decisions
Standalone gallery-apps on a new branch
Split the gallery into its own mono app (gallery-apps) on a new branch instead of keeping it on memo-apps.
Why: The gallery is unrelated to the memo app; a standalone app keeps concerns and skills history separate. Reusable: A 'new app' = new branch off the app with the full foundation + rename the app identity; main lacked the foundation so branching off it was not viable.
monoFetch (res.all) with a native-fetch CORS fallback
Fetch via monoFetch with a Photos restful config entry; read the array from res.all; native fetch fallback.
Why: mono-utils/fetching is the sanctioned layer; Picsum returns a bare array (lands in res.all) and rejects a CORS preflight carrying the Authorization header monoFetch attaches when a session cookie exists. Reusable: For public/no-auth third-party REST via monoFetch: read res.all, and guard for auth-header CORS rejection with a native fetch fallback (base URL from monoRestBaseUrl).
Bottom-sentinel infinite scroll via useIntersectionObserver
Infinite scroll via @vueuse/core useIntersectionObserver on a bottom sentinel (rootMargin 300px).
Why: Fits a grid + thin-page/store; stops when a page returns fewer than pageSize items. Reusable: Bottom-sentinel + useIntersectionObserver is the grid infinite-scroll pattern.
Rename the app via mono.config + package.json + mono prepare
Renamed app my-memo -> gallery-apps by editing mono.config name + package.json name, then mono prepare.
Why: App id drives @<name>/* aliases, package identity, and store-export/key suffix (Rule 8). Reusable: After a rename, run mono prepare to regen .mono/tsconfig aliases, and delete src/auto-imports.d.ts before restarting Vite so the auto-import dts re-scans cleanly (it does not prune deleted exports on a warm start).
Move a skills session across apps via the GitHub contents API
Moved this skills session from app my-memo to gallery-apps by deleting the 5 files via the GitHub contents API and re-saving.
Why: Skills sessions are app-scoped and immutable with no CLI delete; the session was first saved under the old app id. Reusable: To move a skills session between apps: GET each file's SHA and DELETE via the contents API (touch only that session folder), then mono skills save under the new app id.
Files changed
| File | Operation | Note |
|---|---|---|
mono.config.ts | modified | name my-memo -> gallery-apps; Photos restful endpoint; menu reduced to Gallery |
package.json | modified | name my-memo -> gallery-apps (must match mono.config name) |
src/datas/tables/gallery.ts | added | PicsumPhoto type, GALLERY_PAGE_SIZE, thumbUrl helper |
src/stores/use-gallery.ts | added | useGalleryGalleryApps store: loadMore() via monoFetch (res.all) + native fetch fallback |
src/pages/gallery/index.vue | added | Gallery page: UnoCSS grid + useIntersectionObserver infinite scroll |
src/types/odata.d.ts | modified | @my-memo -> @gallery-apps alias |
src/pages/memo/, src/stores/use-memo.ts, src/composables/use-memo-utils.ts, src/datas/tables/memo.ts, src/assets/memo-paper.css | deleted | removed the entire memo feature |