Skip to content

feat(sharing): per-note Share button, dialog, and visibility menu#762

Merged
gabrielste1n merged 4 commits into
mainfrom
feat/note-sharing
May 12, 2026
Merged

feat(sharing): per-note Share button, dialog, and visibility menu#762
gabrielste1n merged 4 commits into
mainfrom
feat/note-sharing

Conversation

@gabrielste1n
Copy link
Copy Markdown
Collaborator

Summary

Desktop UI for the Note Sharing feature (paired with OpenWhispr/openwhispr-api#63).

  • Share button in the NoteEditor header, immediately left of the Download button — icon picks up a subtle blue accent when the note isn't private
  • ShareNoteDialog (Radix-based): visibility selector with three options (Anyone with the link, Everyone at {domain} with the link, Only people invited), email-input invite flow, owner row, pending invitation rows with Resend/Revoke
  • "Everyone at {domain}" hidden entirely when the owner's email is on a personal-email provider (gmail/outlook/yahoo/etc.)
  • "Remember last-used visibility" persisted in user-scoped localStorage; first-ever open defaults to invited (safer)
  • Read-only mode of the dialog when the viewer isn't the note owner (workspace admins can still read but not change sharing)
  • Optimistic visibility updates for snappy UI
  • New i18n namespace noteEditor.share.* across all 10 locales

Files

  • New: ShareNoteDialog.tsx, ShareVisibilityMenu.tsx, NoteSharingService.ts, personalEmailDomains.ts
  • Modified: NoteEditor.tsx (Share button + dialog mount), noteStore.ts (shareByCloudId cache), electron.ts (ShareVisibility, ShareSettings, NoteShareInvitation), all 10 translation.json

States covered

  • Default, hover, active/pressed, focused, disabled, loading (inline spinner inside Share button), empty (collapses to compact dialog), error (inline red helper text), permission-restricted (read-only dialog), copy-link → "Copied" swap for 1.5s
  • Esc closes; Cmd+Enter from email input submits invite
  • First focusable element on open is the email input

Test plan

  • Open Share dialog → confirm default visibility is invited on first ever open
  • Switch to link → click Copy link → button shows "Copied" then reverts
  • Invite a teammate by email → confirm Resend appears under their row, 60s cooldown enforced
  • Switch to domain → confirm domain auto-derived from owner email; not visible for personal-email owners
  • Try inviting yourself or an already-invited email → inline error
  • As a non-owner, open dialog → confirm read-only mode with helper text
  • All 10 locales render correctly

@gabrielste1n gabrielste1n force-pushed the feat/note-sharing branch 3 times, most recently from f0c220c to 362f5e7 Compare May 12, 2026 03:41
- types/electron.ts: ShareVisibility, ShareSettings, NoteShareInvitation.
- utils/personalEmailDomains.ts: gmail/outlook/yahoo etc. — used by the
  share dialog to hide the 'Everyone at {domain}' option when the
  owner's email belongs to a personal-email provider.
- stores/noteStore.ts: per-cloud-id share cache (settings + invitations
  + raw token kept in-memory for the active dialog session).
- services/NoteSharingService.ts: wraps cloudApi for share state,
  visibility/domain updates, token rotation, and invitations CRUD.
- NoteEditor: subtle Share icon button left of the Download button.
  Tints blue when the note has any non-private visibility.
- ShareNoteDialog: Notion/Granola-style share UI with email invite,
  optimistic visibility toggle, copy-link, member list with resend +
  revoke actions, and read-only fallback when the viewer isn't owner.
- ShareVisibilityMenu: dropdown for invited / link / domain. Hides the
  'Everyone at {domain}' option when the owner's domain is a personal
  provider. Stores last-used visibility in user-scoped localStorage so
  reopening pre-selects the previous choice; first-ever open uses the
  safer 'invited' default.
Adds button, dialog title/labels/actions, visibility option strings
(with {{domain}} interpolation), error messages, and pending/accepted
member states for the share dialog in en/de/es/fr/it/ja/pt/ru/zh-CN/
zh-TW.
The Share button only renders for synced notes (cloud_id present),
so the dialog's not-yet-synced branch is unreachable. Replace it
with a type-narrowing early return and remove the dead key across
all locales.
@gabrielste1n gabrielste1n merged commit 2c51068 into main May 12, 2026
6 checks passed
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