Commit Graph
4 Commits
Author SHA1 Message Date
tomdebone e4bcfbfa83 fix(tauri-app): wrap profile methods in PdsHttpClient impl block
The profile.get_record / set_profile methods landed in the WIP
outside any `impl PdsHttpClient { … }` block, with a stray
`&self` parameter that the parser correctly rejected. Wrap them
in a fresh impl block and add the missing closing brace — no
behaviour change, just a structural fix so the binary builds.

---

feat(tauri-app): X-style profile page with banner / avatar overlap / tabs

Replace the existing UserProfileView with a new ProfileView that
follows the X (Twitter) profile layout but stays in our
monospace / orange-on-black terminal aesthetic:

* Banner (140 px) at the top. The user's `banner_cid` (when
  present) is fetched via the existing `fetchBlob` Tauri
  command and set as a background-image. When the profile has no
  banner we render a subtle orange-tinted grid placeholder so the
  page never looks bare.
* 96 px circular avatar that overlaps the bottom of the banner by
  ~44 px, with a 4 px border in `var(--bg)` so the cutout reads
  cleanly against any banner colour.
* Identity row: large bold display name, dim handle below.
* Bio, DID meta line, and the posts / followers / following count
  dl — all monospace, all using our spacing / colour tokens.
* Tab row with the existing 'posts' tab active and
  'replies' / 'likes' rendered disabled (placeholder for future
  work).
* Edit form (gated on `current_user_did === profile.did`) with
  display-name, description, and avatar upload fields.

App.svelte refactor: the 'profile' view (current user) and the
'user' view (someone else) now both render `<ProfileView>`. The
duplicated edit state (`editingProfile`, `editProfileName`,
`editProfileDesc`, `editProfileAvatarCid`, `savingProfile`),
the duplicate `pickAndUploadAvatar` / `saveProfile` /
`refreshProfile` functions, and the unused `displayHandle` /
`fetchProfile` / `pickAndUploadImage` / `setMyProfile` imports
are gone. ProfileView handles its own fetch + edit state
internally, so the App.svelte section collapses from ~145 lines
of inline JSX to ~12.

The legacy .profile__head / .profile__bio / .counts style
classes that the new component no longer references are also
removed.
2026-07-18 18:35:35 +02:00
tomdebone ffee5c6685 feat(tauri-app): profile view, Avatar component, handle navigation
UI half of the profile feature. Mirrors the previous three commits
so the user can browse and edit profiles.

* `<Avatar did cid name size>` — reusable avatar component.
  Falls back to an initial-letter (or "?" when name is empty) circle
  when `cid` is null. Resolves the blob through the standard PDS
  fetch path so it works for any author whose PDS the client can
  reach.
* `<UserProfileView handle on_thread_click current_user_did>` —
  public profile page. Fetches `GET /api/profile/<handle>` on
  mount, renders the avatar / display name / bio / counts /
  posts. The "edit profile" button is gated on
  `current_user_did === profile.did` so a user browsing
  someone else's profile can't issue an unintended `setMyProfile`
  against their own DID.
* `PostCard` now renders an inline `<Avatar>` + clickable handle
  button that calls a new `on_handle_click` prop. The clickable
  area replaces the previous dead `<a href>` (Tauri webviews
  have no router).
* `App.svelte` adds an `openUserProfile(handle)` handler that
  sets `selectedHandle` + `view = "user"` and mounts
  `<UserProfileView>`.
* New Tauri commands `profile_get_record` / `profile_set` in
  `lib.rs` + matching client helpers `getMyProfile` /
  `setMyProfile` in `client.ts`. The set command sends camelCase
  field names; the PDS endpoint (previous commit) round-trips them
  through `#[serde(rename_all = "camelCase")]`.
* Empty-state UX for users with no profile yet (new account, or a
  third-party-PDS author whose profile the AppView hasn't indexed
  yet): both the current-user "profile" view and the public
  "user" view render a hint ("// no profile yet — click 'edit
  profile' to set one up." / "// no profile yet.") instead of a
  blank bio box.
* NavRail / NavRailHarness `View` union extended with "user"
  so the navigation prop type accepts the new view.
2026-07-18 17:57:15 +02:00
tomdebone b912132a05 tauri-app: 8a review fixes
- fetchBlob cache keyed by (did, cid), not just cid.
  Security: future per-DID access control on getBlob would
  otherwise leak the first responder's bytes to subsequent
  viewers.
- EmbedImage: pass did to releaseBlob, release previous cid
  on cid change (no leaked URLs).
- ComposeBox: releaseBlob called with both did and cid.
- pds-server: rename test
  get_blob_after_upload_with_different_did ->
  get_blob_returns_404_for_cross_did_cid_lookup. The
  docstring was misleading — the test only verifies the
  (did,cid) PK on the PDS row, not auth. The renamed name
  matches what the test actually checks.
- vitest: update releaseBlob call sites to the new
  (did, cid) signature.
2026-07-06 18:53:09 +02:00
tomdebone c586fd39c9 maarcadetweet: initial commit
AT Protocol PDS + AppView + Tauri Desktop Client, 160-char post limit.

- PDS (Rust + axum + sqlx)
  - Auth: createAccount, createSession, refreshSession
  - Records: createRecord, deleteRecord (race-safe via SELECT FOR UPDATE)
  - Feed: feed.like.create, feed.repost.create
  - Sync: getRepo, getBlocks, getLatestCommit, getRecord (with MST proof), listRepos
  - Identity: resolveHandle
  - MST: spec-conformant (at-mst crate, 27 tests)
  - Repo: signed commits, TID counter (monotonic, 4096 wrap safe)

- AppView (Rust + axum + sqlx)
  - Jetstream consumer (WebSocket, exponential backoff, 38k+ events indexed)
  - REST API: timeline/home (graph-aware), profile, search, post (with thread hydration)
  - Handle-sync worker (did:plc + did:web)
  - JSONB embed storage + thread columns (migration 0003)
  - Like/repost counter cache (migration 0004)

- Tauri 2 + Svelte 5 Desktop Client
  - System tray (Show/Compose/Quit menu)
  - OS notifications (tauri-plugin-notification)
  - Auto-update (tauri-plugin-updater, placeholder endpoint)
  - Window-state (tauri-plugin-window-state)
  - 160-char compose with live counter
  - Image/Link embed rendering
  - LocalStorage-persisted like state
  - Timeline with poll (prepend new posts)
  - Custom TitleBar (transparent, no decorations)
  - Orange/IBM Plex Mono maarcade design

Tests: 231 Rust + 9 vitest = 240 passed.
2026-07-05 20:01:31 +02:00