diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index d357eb9..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,39 +0,0 @@ -# Changelog - -## [Unreleased] - -Target release: `v1.0.0`. - -### 2026-06-09 - -#### Added - -- PGlite-backed local cache/search foundation with WASM build support. - - Transactional schema migrations for accounts, cached records, collection - sync state, and record search. -- Ubuntu-purple boot splash that initializes PGlite, runs migrations, and offers - recovery actions. -- Cache-aware AT Protocol browsing: live record fetches populate PGlite and offline - failures can fall back to cached collections/records. -- Full-text cache search in the Nautilus-style collection browser. -- Atmosphere app logo mapping for known AT Protocol collection namespaces. -- Cursor-based record pagination with a generator-backed “Load more records” flow. - -#### Changed - -- Grouped Nautilus collections by top-level namespace folders. - -### 2026-06-08 - -#### Added - -- Ubuntu 8.10 / GNOME 2-inspired desktop shell, panel, wallpaper, windows, and Humanity - icon styling. -- First-run AT Protocol account setup flow with handle resolution and persisted account - identity. -- Nautilus-style collection browser backed by live AT Protocol repository collection and - record loading. -- gedit-style JSON record viewer opened from selected records. -- Window management basics including movable, resizable, minimizable, maximizable, and - closable windows. -- About Computer dialog, desktop icons, sticky note, and Tangled project links. diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 120000 index 0000000..103de7f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1 @@ +src/routes/docs/CHANGELOG.md \ No newline at end of file diff --git a/package.json b/package.json index 60a761b..d5f312e 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "eslint-config-prettier": "^10.1.8", "eslint-plugin-svelte": "^3.17.0", "globals": "^17.4.0", + "mdsvex": "^0.12.7", "playwright": "^1.60.0", "prettier": "^3.8.1", "prettier-plugin-svelte": "^3.5.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 68c9d6f..f36569f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -72,6 +72,9 @@ importers: globals: specifier: ^17.4.0 version: 17.6.0 + mdsvex: + specifier: ^0.12.7 + version: 0.12.7(svelte@5.56.3(@typescript-eslint/types@8.61.0)) playwright: specifier: ^1.60.0 version: 1.60.0 @@ -450,6 +453,9 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} @@ -957,6 +963,11 @@ packages: mdast-util-to-hast@13.2.1: resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + mdsvex@0.12.7: + resolution: {integrity: sha512-gx4bReLCUvq+MPErHXYeyX+TEq1hsS2KfiZtEOMNTcbibSouFy8AHc5h04KbGCl+g5tLuo4/lbgRVYRnc7bJZw==} + peerDependencies: + svelte: ^3.56.0 || ^4.0.0 || ^5.0.0-next.120 + micromark-util-character@2.1.1: resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} @@ -1096,6 +1107,13 @@ packages: engines: {node: '>=14'} hasBin: true + prism-svelte@0.4.7: + resolution: {integrity: sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ==} + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + property-information@7.2.0: resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} @@ -1242,18 +1260,30 @@ packages: unicode-segmenter@0.14.5: resolution: {integrity: sha512-jHGmj2LUuqDcX3hqY12Ql+uhUTn8huuxNZGq7GvtF6bSybzH3aFgedYu/KTzQStEgt1Ra2F3HxadNXsNjb3m3g==} + unist-util-is@4.1.0: + resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==} + unist-util-is@6.0.1: resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} unist-util-position@5.0.0: resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + unist-util-stringify-position@2.0.3: + resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} + unist-util-stringify-position@4.0.0: resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + unist-util-visit-parents@3.1.1: + resolution: {integrity: sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==} + unist-util-visit-parents@6.0.2: resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + unist-util-visit@2.0.3: + resolution: {integrity: sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==} + unist-util-visit@5.1.0: resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} @@ -1271,6 +1301,9 @@ packages: typescript: optional: true + vfile-message@2.0.4: + resolution: {integrity: sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==} + vfile-message@4.0.3: resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} @@ -1727,6 +1760,8 @@ snapshots: '@types/trusted-types@2.0.7': {} + '@types/unist@2.0.11': {} + '@types/unist@3.0.3': {} '@typescript-eslint/eslint-plugin@8.61.0(@typescript-eslint/parser@8.61.0(eslint@10.4.1)(typescript@6.0.3))(eslint@10.4.1)(typescript@6.0.3)': @@ -2251,6 +2286,16 @@ snapshots: unist-util-visit: 5.1.0 vfile: 6.0.3 + mdsvex@0.12.7(svelte@5.56.3(@typescript-eslint/types@8.61.0)): + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 2.0.11 + prism-svelte: 0.4.7 + prismjs: 1.30.0 + svelte: 5.56.3(@typescript-eslint/types@8.61.0) + unist-util-visit: 2.0.3 + vfile-message: 2.0.4 + micromark-util-character@2.1.1: dependencies: micromark-util-symbol: 2.0.1 @@ -2364,6 +2409,10 @@ snapshots: prettier@3.8.3: {} + prism-svelte@0.4.7: {} + + prismjs@1.30.0: {} + property-information@7.2.0: {} punycode@2.3.1: {} @@ -2536,6 +2585,8 @@ snapshots: unicode-segmenter@0.14.5: {} + unist-util-is@4.1.0: {} + unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 @@ -2544,15 +2595,30 @@ snapshots: dependencies: '@types/unist': 3.0.3 + unist-util-stringify-position@2.0.3: + dependencies: + '@types/unist': 2.0.11 + unist-util-stringify-position@4.0.0: dependencies: '@types/unist': 3.0.3 + unist-util-visit-parents@3.1.1: + dependencies: + '@types/unist': 2.0.11 + unist-util-is: 4.1.0 + unist-util-visit-parents@6.0.2: dependencies: '@types/unist': 3.0.3 unist-util-is: 6.0.1 + unist-util-visit@2.0.3: + dependencies: + '@types/unist': 2.0.11 + unist-util-is: 4.1.0 + unist-util-visit-parents: 3.1.1 + unist-util-visit@5.1.0: dependencies: '@types/unist': 3.0.3 @@ -2569,6 +2635,11 @@ snapshots: optionalDependencies: typescript: 6.0.3 + vfile-message@2.0.4: + dependencies: + '@types/unist': 2.0.11 + unist-util-stringify-position: 2.0.3 + vfile-message@4.0.3: dependencies: '@types/unist': 3.0.3 diff --git a/src/lib/atproto/repo.svelte.ts b/src/lib/atproto/repo.svelte.ts index 5d667b6..fc3e3d3 100644 --- a/src/lib/atproto/repo.svelte.ts +++ b/src/lib/atproto/repo.svelte.ts @@ -1,26 +1,12 @@ import { Client, ok, simpleFetchHandler } from '@atcute/client'; import type { ActorIdentifier } from '@atcute/lexicons/syntax'; import type {} from '@atcute/atproto'; -import { - cacheFetchedRecords, - getDatabase, - listCachedCollections, - listCachedRecords, - searchCachedRecords, - updateCollectionSyncState, - type CachedRecord, - type CachedRecordInput -} from '$lib/db'; +import type { CachedRecord, CachedRecordInput } from '$lib/db'; import { errorMessage } from '$lib/utils/errors'; import { appLabelForCollection, collectionIconMatch } from './collection-icons'; import { listRecordPages, type RecordPage } from './pagination'; -import { - isRecordValue, - type AccountIdentity, - type CollectionSummary, - type RepoRecordSummary, - type UnknownRecord -} from './types'; +import { isRecordValue } from './types'; +import type { AccountIdentity, CollectionSummary, RepoRecordSummary, UnknownRecord } from './types'; export type { CollectionSummary, RepoRecordSummary } from './types'; @@ -125,12 +111,15 @@ class RepoBrowserState { async loadCollectionsFromCache(identity: AccountIdentity) { try { + const { getDatabase, listCachedCollections } = await import('$lib/db'); const db = await getDatabase(); const collections = await listCachedCollections(db, identity.did); if (collections.length === 0) return false; - this.collections = collections.map((collection) => collectionSummaryForName(collection.name, collection.loadedCount)); + this.collections = collections.map((collection) => + collectionSummaryForName(collection.name, collection.loadedCount) + ); this.selectedCollection = preferredCollection(this.collections.map((collection) => collection.name)); if (this.selectedCollection) { @@ -160,6 +149,7 @@ class RepoBrowserState { this.error = null; try { + const { getDatabase, searchCachedRecords } = await import('$lib/db'); const db = await getDatabase(); const results = await searchCachedRecords(db, normalizedQuery, { repoDid: identity.did, @@ -168,7 +158,7 @@ class RepoBrowserState { this.records = results.map((record) => summarizeCachedRecord(record, identity.handle)); } catch (searchError) { this.records = []; - this.error = errorMessage(searchError, 'Could not search cached records.'); + this.error = errorMessage(searchError, 'Could not search records.'); } finally { this.isSearching = false; } @@ -176,6 +166,7 @@ class RepoBrowserState { async loadRecordsFromCache(identity: AccountIdentity, collectionName: string) { try { + const { getDatabase, listCachedRecords } = await import('$lib/db'); const db = await getDatabase(); const records = await listCachedRecords(db, { repoDid: identity.did, collection: collectionName, limit: 25 }); @@ -269,6 +260,7 @@ async function cacheLiveRecords( cursor: string | null ) { try { + const { cacheFetchedRecords, getDatabase, updateCollectionSyncState } = await import('$lib/db'); const db = await getDatabase(); await cacheFetchedRecords( db, diff --git a/src/lib/components/CollectionBrowser.svelte b/src/lib/components/CollectionBrowser.svelte index 67e746a..f51a996 100644 --- a/src/lib/components/CollectionBrowser.svelte +++ b/src/lib/components/CollectionBrowser.svelte @@ -149,12 +149,12 @@ event.preventDefault(); searchRecords(); }}> - +
Document Viewer could not open “{slug}”.
+