Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
262 changes: 204 additions & 58 deletions app.go

Large diffs are not rendered by default.

69 changes: 69 additions & 0 deletions docs/obsidian-integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Obsidian Integration

## Goal

When the Obsidian extension is installed, Yap appends every successful transcription to an Obsidian daily note while preserving the normal Yap flow: history, audio archive, stats, clipboard, and auto-paste.

## Integration Strategy

Use direct Markdown file writes into the selected Obsidian vault. Obsidian vaults are local folders of Markdown files and Obsidian watches filesystem changes automatically. This avoids requiring Obsidian to be open and avoids mandatory community plugin dependencies.

Alternatives considered:

- Native `obsidian://` URIs can open vaults and notes, but native append support is limited.
- Advanced URI and Actions URI can append content, but require community plugins.
- Local REST API is powerful, but requires a community plugin, API key, local server, and certificate handling.

## Note Layout

Yap writes to a dedicated `Yap` folder in the configured vault. The note name is configurable, and defaults to a daily note:

```text
<Vault>/Yap/Transcriptions YYYY-MM-DD.md
```

The default note name template is `Transcriptions {{date}}`, where `{{date}}` expands to `YYYY-MM-DD`. A static name such as `Inbox` writes to `<Vault>/Yap/Inbox.md`.

Example:

```text
~/Documents/Obsidian/MainVault/Yap/Transcriptions 2026-06-04.md
```

New daily note content:

```md
---
source: yap
type: transcriptions
date: 2026-06-04
---

# Transcriptions 2026-06-04

## 14:32

Transcribed text goes here.
```

Subsequent captures append to the same daily note:

```md
## 16:08

Another capture goes here.
```

## Implemented Behavior

- The Obsidian extension is installed and uninstalled from the Extensions page.
- The extension stores an enabled flag, the selected Obsidian vault path, and the configured note name.
- The note name always resolves to a Markdown file inside the `Yap` folder.
- When installed, every successful transcription must be written to Obsidian.
- Normal Yap behavior remains active: history, audio saving, stats, clipboard, and auto-paste still run after a successful Obsidian write.
- If Obsidian writing fails after transcription, Yap surfaces the error and keeps the transcript in app state.
- Uninstalling the extension disables Obsidian writes and clears the vault path.

## First Version Scope

Ship plugin-free direct vault writing. REST API and URI-based integrations can be added later if users need remote vault operations, command execution, or richer Obsidian automation.
4 changes: 2 additions & 2 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json.md5
Original file line number Diff line number Diff line change
@@ -1 +1 @@
a93b9b9ee0731e091d302c100808c109
5ed087423043b58e5b2fc9dd9c3156b1
163 changes: 163 additions & 0 deletions frontend/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,136 @@ body {
margin-bottom: 16px;
}

/* Extensions Page */
.extensions-page {
flex: 1;
padding: 32px;
overflow-y: auto;
}

.extensions-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
gap: 16px;
margin-bottom: 32px;
}

.extension-card {
display: grid;
grid-template-columns: 56px 1fr auto;
align-items: center;
gap: 16px;
padding: 18px;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 16px;
}

.extension-icon {
width: 56px;
height: 56px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 14px;
background: var(--bg-dark);
}

.extension-icon img {
width: 42px;
height: 42px;
}

.obsidian-icon {
background: radial-gradient(circle at 30% 20%, rgba(161, 139, 255, 0.25), rgba(79, 44, 170, 0.12));
}

.extension-content h2 {
font-size: 17px;
font-weight: 600;
color: var(--text-primary);
}

.extension-content p {
margin-top: 6px;
max-width: 440px;
color: var(--text-muted);
font-size: 13px;
line-height: 1.45;
}

.extension-title-row {
display: flex;
align-items: center;
gap: 10px;
}

.extension-status {
padding: 3px 8px;
border-radius: 999px;
background: var(--bg-dark);
color: var(--text-muted);
font-size: 11px;
font-weight: 600;
}

.extension-status.installed {
background: rgba(48, 209, 88, 0.16);
color: var(--success);
}

.extension-actions {
display: flex;
gap: 8px;
}

.primary-button,
.secondary-button,
.danger-button {
padding: 9px 14px;
border: none;
border-radius: 8px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: all 0.15s;
}

.primary-button {
background: var(--accent);
color: #000;
}

.secondary-button {
background: var(--bg-dark);
color: var(--text-primary);
border: 1px solid var(--border);
}

.extension-actions .secondary-button {
border: 1px solid rgba(255, 255, 255, 0.28);
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
}

.extension-actions .secondary-button:hover {
border-color: var(--accent);
}

.danger-button {
background: rgba(255, 69, 58, 0.14);
color: var(--danger);
}

.primary-button:hover,
.secondary-button:hover,
.danger-button:hover {
transform: translateY(-1px);
}

.extension-settings {
max-width: 900px;
}

.setting-row {
display: flex;
justify-content: space-between;
Expand Down Expand Up @@ -846,6 +976,39 @@ body {
width: 200px;
}

.api-key-input.vault-path-input input {
width: 360px;
}

.hotkey-actions {
display: flex;
align-items: center;
gap: 8px;
}

.clear-hotkey-btn {
padding: 10px 14px;
background: var(--bg-dark);
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text-secondary);
font-size: 14px;
cursor: pointer;
}

.clear-hotkey-btn:hover {
border-color: var(--text-secondary);
color: var(--text-primary);
}

.destination-preview {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}

.braincache-hint {
margin-top: 8px;
}

.api-key-input input:focus {
outline: none;
border-color: var(--accent);
Expand Down
Loading