mirror of
https://github.com/jamjan05/AI-Vault-for-Obsidian.git
synced 2026-07-22 06:56:43 +00:00
1.0.2
This commit is contained in:
parent
091f2689a5
commit
9b209dea82
5 changed files with 80 additions and 45 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -4,3 +4,5 @@ main.js
|
|||
.DS_Store
|
||||
Thumbs.db
|
||||
data.json
|
||||
.codex/
|
||||
.agents/
|
||||
|
|
|
|||
|
|
@ -36,7 +36,9 @@ export class GPTSettingsTab extends PluginSettingTab {
|
|||
display(): void {
|
||||
const { containerEl } = this;
|
||||
containerEl.empty();
|
||||
containerEl.createEl("h2", { text: t("settings_title") });
|
||||
new Setting(containerEl)
|
||||
.setName(t("settings_title"))
|
||||
.setHeading();
|
||||
|
||||
this.renderLanguage(containerEl);
|
||||
this.renderKeyWarning(containerEl);
|
||||
|
|
@ -156,7 +158,9 @@ export class GPTSettingsTab extends PluginSettingTab {
|
|||
const keysStoredLocal = !keysInSync && extEnabled;
|
||||
const keysLocation = keysStoredLocal ? t("settings_key_local") : t("settings_key_sync");
|
||||
|
||||
el.createEl("h3", { text: t("settings_openai_title") });
|
||||
new Setting(el)
|
||||
.setName(t("settings_openai_title"))
|
||||
.setHeading();
|
||||
|
||||
new Setting(el)
|
||||
.setName(t("settings_openai_key_name"))
|
||||
|
|
@ -190,7 +194,9 @@ export class GPTSettingsTab extends PluginSettingTab {
|
|||
}
|
||||
|
||||
private renderOpenAISettings(el: HTMLElement): void {
|
||||
el.createEl("h3", { text: "⚙️ " + t("settings_openai_title") + " — " + t("settings_thinking_name") });
|
||||
new Setting(el)
|
||||
.setName("⚙️ " + t("settings_openai_title") + " — " + t("settings_thinking_name"))
|
||||
.setHeading();
|
||||
|
||||
new Setting(el)
|
||||
.setName(t("settings_thinking_name"))
|
||||
|
|
@ -205,7 +211,9 @@ export class GPTSettingsTab extends PluginSettingTab {
|
|||
}),
|
||||
);
|
||||
|
||||
el.createEl("h4", { text: t("settings_max_tokens_title") });
|
||||
new Setting(el)
|
||||
.setName(t("settings_max_tokens_title"))
|
||||
.setHeading();
|
||||
|
||||
new Setting(el)
|
||||
.setName(t("settings_max_tokens_fast_name"))
|
||||
|
|
@ -213,7 +221,7 @@ export class GPTSettingsTab extends PluginSettingTab {
|
|||
.addText(txt => {
|
||||
txt.inputEl.type = "number";
|
||||
txt.inputEl.min = "256";
|
||||
txt.inputEl.style.width = "90px";
|
||||
txt.inputEl.addClass("gpt-settings-input-compact");
|
||||
txt.setValue(String(this.plugin.settings.maxTokensFast ?? 4096))
|
||||
.onChange(async (v: string) => {
|
||||
const n = parseInt(v, 10);
|
||||
|
|
@ -230,7 +238,7 @@ export class GPTSettingsTab extends PluginSettingTab {
|
|||
.addText(txt => {
|
||||
txt.inputEl.type = "number";
|
||||
txt.inputEl.min = "256";
|
||||
txt.inputEl.style.width = "90px";
|
||||
txt.inputEl.addClass("gpt-settings-input-compact");
|
||||
txt.setValue(String(this.plugin.settings.maxTokensNormal ?? 8192))
|
||||
.onChange(async (v: string) => {
|
||||
const n = parseInt(v, 10);
|
||||
|
|
@ -247,7 +255,7 @@ export class GPTSettingsTab extends PluginSettingTab {
|
|||
.addText(txt => {
|
||||
txt.inputEl.type = "number";
|
||||
txt.inputEl.min = "256";
|
||||
txt.inputEl.style.width = "90px";
|
||||
txt.inputEl.addClass("gpt-settings-input-compact");
|
||||
txt.setValue(String(this.plugin.settings.maxTokensThink ?? 16000))
|
||||
.onChange(async (v: string) => {
|
||||
const n = parseInt(v, 10);
|
||||
|
|
@ -282,7 +290,9 @@ export class GPTSettingsTab extends PluginSettingTab {
|
|||
}
|
||||
|
||||
private renderContext(el: HTMLElement): void {
|
||||
el.createEl("h3", { text: "💬 " + t("settings_context_title") });
|
||||
new Setting(el)
|
||||
.setName("💬 " + t("settings_context_title"))
|
||||
.setHeading();
|
||||
|
||||
new Setting(el)
|
||||
.setName(t("settings_context_name"))
|
||||
|
|
@ -290,7 +300,7 @@ export class GPTSettingsTab extends PluginSettingTab {
|
|||
.addText(txt => {
|
||||
txt.inputEl.type = "number";
|
||||
txt.inputEl.min = "0";
|
||||
txt.inputEl.style.width = "90px";
|
||||
txt.inputEl.addClass("gpt-settings-input-compact");
|
||||
txt.setValue(String(this.plugin.settings.maxContextMessages ?? 0))
|
||||
.onChange(async (v: string) => {
|
||||
const n = parseInt(v, 10);
|
||||
|
|
@ -308,7 +318,9 @@ export class GPTSettingsTab extends PluginSettingTab {
|
|||
const keysStoredLocal = !keysInSync && extEnabled;
|
||||
const keysLocation = keysStoredLocal ? t("settings_key_local") : t("settings_key_sync");
|
||||
|
||||
el.createEl("h3", { text: t("settings_claude_title") });
|
||||
new Setting(el)
|
||||
.setName(t("settings_claude_title"))
|
||||
.setHeading();
|
||||
|
||||
new Setting(el)
|
||||
.setName(t("settings_claude_key_name"))
|
||||
|
|
@ -338,7 +350,9 @@ export class GPTSettingsTab extends PluginSettingTab {
|
|||
}
|
||||
|
||||
private renderRAG(el: HTMLElement): void {
|
||||
el.createEl("h3", { text: t("settings_rag_title") });
|
||||
new Setting(el)
|
||||
.setName(t("settings_rag_title"))
|
||||
.setHeading();
|
||||
|
||||
new Setting(el)
|
||||
.setName(t("settings_rag_enable_name"))
|
||||
|
|
@ -387,7 +401,9 @@ export class GPTSettingsTab extends PluginSettingTab {
|
|||
}
|
||||
|
||||
private renderStorage(el: HTMLElement): void {
|
||||
el.createEl("h3", { text: t("settings_storage_title") });
|
||||
new Setting(el)
|
||||
.setName(t("settings_storage_title"))
|
||||
.setHeading();
|
||||
|
||||
const isDesktop = this.plugin.externalStorage.isDesktop;
|
||||
const isActive = this.plugin.externalStorage.isEnabled;
|
||||
|
|
@ -408,8 +424,7 @@ export class GPTSettingsTab extends PluginSettingTab {
|
|||
info.createEl("strong", { text: "Location:" });
|
||||
info.createEl("br");
|
||||
const pathEl = info.createEl("code", { text: currentPath });
|
||||
pathEl.style.fontSize = "11px";
|
||||
pathEl.style.wordBreak = "break-all";
|
||||
pathEl.addClass("gpt-settings-storage-path");
|
||||
} else {
|
||||
this.renderSafeInlineMarkup(info, t("settings_storage_inactive_html"));
|
||||
}
|
||||
|
|
@ -438,7 +453,7 @@ export class GPTSettingsTab extends PluginSettingTab {
|
|||
txt.setPlaceholder("/path/to/folder (empty = auto)")
|
||||
.setValue(this.plugin.settings.externalStoragePath ?? "")
|
||||
.setDisabled(!isDesktop);
|
||||
txt.inputEl.style.width = "100%";
|
||||
txt.inputEl.addClass("gpt-settings-input-full");
|
||||
txt.onChange(async (v: string) => {
|
||||
this.plugin.settings.externalStoragePath = v.trim();
|
||||
await this.plugin.saveSettings();
|
||||
|
|
|
|||
|
|
@ -183,11 +183,11 @@ export class GPTChatView extends ItemView {
|
|||
if (!this.ragStatusEl) return;
|
||||
this.ragStatusEl.textContent = text;
|
||||
this.ragStatusEl.className = `gpt-rag-status gpt-rag-${state}`;
|
||||
this.ragStatusEl.style.display = "block";
|
||||
this.ragStatusEl.removeClass("gpt-ctx-hidden");
|
||||
}
|
||||
|
||||
private hideRagStatus(): void {
|
||||
if (this.ragStatusEl) this.ragStatusEl.style.display = "none";
|
||||
if (this.ragStatusEl) this.ragStatusEl.addClass("gpt-ctx-hidden");
|
||||
}
|
||||
|
||||
// ── Build UI ────────────────────────────────────────────────────────────────
|
||||
|
|
@ -265,8 +265,7 @@ export class GPTChatView extends ItemView {
|
|||
}
|
||||
|
||||
private buildRagStatus(root: HTMLElement): void {
|
||||
this.ragStatusEl = root.createEl("div", { cls: "gpt-rag-status" });
|
||||
this.ragStatusEl.style.display = "none";
|
||||
this.ragStatusEl = root.createEl("div", { cls: "gpt-rag-status gpt-ctx-hidden" });
|
||||
}
|
||||
|
||||
private buildManualBar(root: HTMLElement): void {
|
||||
|
|
@ -375,7 +374,7 @@ export class GPTChatView extends ItemView {
|
|||
const row = list.createEl("label", { cls: "gpt-modal-row" });
|
||||
const cb = row.createEl("input", { attr: { type: "checkbox" } }) as HTMLInputElement;
|
||||
cb.checked = selected.has(f.path);
|
||||
cb.style.accentColor = "var(--interactive-accent)";
|
||||
cb.setCssProps({ "accent-color": "var(--interactive-accent)" });
|
||||
cb.onchange = () => { selected.has(f.path) ? selected.delete(f.path) : selected.add(f.path); };
|
||||
const icon = f.extension === "canvas" ? "🗂️ " : "";
|
||||
row.createEl("span", { cls: "gpt-modal-row-label", text: icon + f.basename });
|
||||
|
|
@ -431,7 +430,11 @@ export class GPTChatView extends ItemView {
|
|||
updateRagBadge(): void {
|
||||
if (!this.ragBadge) return;
|
||||
this.ragBadge.textContent = this.settings.ragEnabled ? "RAG" : "";
|
||||
this.ragBadge.style.display = this.settings.ragEnabled ? "inline-block" : "none";
|
||||
if (this.settings.ragEnabled) {
|
||||
this.ragBadge.removeClass("gpt-ctx-hidden");
|
||||
} else {
|
||||
this.ragBadge.addClass("gpt-ctx-hidden");
|
||||
}
|
||||
}
|
||||
|
||||
updateProjectBar(): void {
|
||||
|
|
@ -446,8 +449,10 @@ export class GPTChatView extends ItemView {
|
|||
if (!proj) { this.projectBar.addClass("gpt-ctx-hidden"); return; }
|
||||
|
||||
this.projectBar.removeClass("gpt-ctx-hidden");
|
||||
this.projectBar.style.background = `color-mix(in srgb,${proj.color} 10%,var(--background-secondary))`;
|
||||
this.projectBar.style.borderBottomColor = `color-mix(in srgb,${proj.color} 25%,transparent)`;
|
||||
this.projectBar.setCssProps({
|
||||
background: `color-mix(in srgb,${proj.color} 10%,var(--background-secondary))`,
|
||||
"border-bottom-color": `color-mix(in srgb,${proj.color} 25%,transparent)`,
|
||||
});
|
||||
|
||||
const sessions = this.plugin.projects.getProjectSessions(proj.id);
|
||||
const promptBadge = proj.systemPrompt ? " " + t("projects_custom_prompt_badge") : "";
|
||||
|
|
@ -639,8 +644,10 @@ export class GPTChatView extends ItemView {
|
|||
// Attach to document.body — avoids CSS transform issues on Obsidian panels
|
||||
document.body.appendChild(picker);
|
||||
const rect = this.modelSelectorBtn.getBoundingClientRect();
|
||||
picker.style.top = `${rect.bottom + 4}px`;
|
||||
picker.style.left = `${rect.left}px`;
|
||||
picker.setCssProps({
|
||||
top: `${rect.bottom + 4}px`,
|
||||
left: `${rect.left}px`,
|
||||
});
|
||||
|
||||
// Close on click outside the picker
|
||||
this.pickerCloseHandler = (e: MouseEvent): void => {
|
||||
|
|
@ -978,11 +985,11 @@ export class GPTChatView extends ItemView {
|
|||
this.abortController?.abort();
|
||||
new Notice("⏹ Generation stopped");
|
||||
};
|
||||
this.sendBtn.style.display = "none";
|
||||
this.sendBtn.addClass("gpt-ctx-hidden");
|
||||
} else {
|
||||
this.stopBtn?.remove();
|
||||
this.stopBtn = null;
|
||||
this.sendBtn.style.display = "";
|
||||
this.sendBtn.removeClass("gpt-ctx-hidden");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,11 +98,10 @@ export class GPTProjectsView extends ItemView {
|
|||
if (!proj) return;
|
||||
|
||||
const bar = root.createEl("div", { cls: "gpt-projects-active-bar" });
|
||||
bar.style.background = `color-mix(in srgb,${proj.color} 12%,var(--background-secondary))`;
|
||||
bar.style.borderBottomColor = `color-mix(in srgb,${proj.color} 25%,transparent)`;
|
||||
bar.setCssProps({ "--gpt-project-color": proj.color });
|
||||
|
||||
const dot = bar.createEl("span", { cls: "gpt-projects-active-dot" });
|
||||
dot.style.background = proj.color;
|
||||
dot.setCssProps({ "--gpt-project-color": proj.color });
|
||||
|
||||
bar.createEl("span", {
|
||||
cls: "gpt-projects-active-name",
|
||||
|
|
@ -137,16 +136,16 @@ export class GPTProjectsView extends ItemView {
|
|||
const isActive = this.plugin.activeProjectId === proj.id;
|
||||
|
||||
const card = list.createEl("div", { cls: "gpt-projects-card" });
|
||||
card.setCssProps({ "--gpt-project-color": proj.color });
|
||||
if (isActive) {
|
||||
card.style.borderColor = proj.color;
|
||||
card.style.background = `color-mix(in srgb,${proj.color} 8%,var(--background-secondary))`;
|
||||
card.addClass("gpt-projects-card--active");
|
||||
}
|
||||
|
||||
// ── Card header ─────────────────────────────────────────────────────────
|
||||
const top = card.createEl("div", { cls: "gpt-projects-card-top" });
|
||||
|
||||
const dot = top.createEl("span", { cls: "gpt-projects-card-dot" });
|
||||
dot.style.background = proj.color;
|
||||
dot.setCssProps({ "--gpt-project-color": proj.color });
|
||||
|
||||
top.createEl("span", { cls: "gpt-projects-card-name", text: proj.name });
|
||||
|
||||
|
|
@ -154,8 +153,7 @@ export class GPTProjectsView extends ItemView {
|
|||
cls: "gpt-projects-card-badge",
|
||||
text: t("projects_chat_count", sessions.length),
|
||||
});
|
||||
badge.style.background = `color-mix(in srgb,${proj.color} 15%,var(--background-primary))`;
|
||||
badge.style.color = proj.color;
|
||||
badge.setCssProps({ "--gpt-project-color": proj.color });
|
||||
|
||||
// Edit button
|
||||
const editBtn = top.createEl("button", {
|
||||
|
|
@ -182,9 +180,7 @@ export class GPTProjectsView extends ItemView {
|
|||
// Custom prompt — badge
|
||||
if (proj.systemPrompt) {
|
||||
const tag = card.createEl("div", { cls: "gpt-projects-card-prompt-tag" });
|
||||
tag.style.background = `color-mix(in srgb,${proj.color} 10%,var(--background-primary))`;
|
||||
tag.style.color = proj.color;
|
||||
tag.style.borderColor = `color-mix(in srgb,${proj.color} 20%,transparent)`;
|
||||
tag.setCssProps({ "--gpt-project-color": proj.color });
|
||||
this.setIconText(tag, "pencil", t("projects_own_prompt_btn"));
|
||||
}
|
||||
|
||||
|
|
@ -272,8 +268,9 @@ export class GPTProjectsView extends ItemView {
|
|||
cls: "gpt-modal-ok",
|
||||
text: isEdit ? "Zapisz" : t("projects_create_btn"),
|
||||
});
|
||||
ok.onclick = async () => { const name = nameInput.value.trim();
|
||||
if (!name) { nameInput.style.borderColor = "var(--color-red)"; return; }
|
||||
ok.onclick = async () => {
|
||||
const name = nameInput.value.trim();
|
||||
if (!name) { nameInput.addClass("gpt-modal-input-error"); return; }
|
||||
|
||||
if (isEdit) {
|
||||
await this.plugin.projects.updateProject(editProject!.id, {
|
||||
|
|
@ -299,6 +296,7 @@ export class GPTProjectsView extends ItemView {
|
|||
nameInput.addEventListener("keydown", (e: KeyboardEvent) => {
|
||||
if (e.key === "Enter") void (ok.onclick as (() => Promise<void>) | null)?.();
|
||||
});
|
||||
nameInput.addEventListener("input", () => nameInput.removeClass("gpt-modal-input-error"));
|
||||
|
||||
overlay.appendChild(box);
|
||||
this.containerEl.appendChild(overlay);
|
||||
|
|
|
|||
23
styles.css
23
styles.css
|
|
@ -425,6 +425,7 @@
|
|||
font-size: 13px; outline: none;
|
||||
}
|
||||
.gpt-modal-input:focus { border-color: var(--gpt-color-openai); }
|
||||
.gpt-modal-input.gpt-modal-input-error { border-color: var(--color-red, var(--gpt-color-error)); }
|
||||
.gpt-modal-list {
|
||||
max-height: 260px; overflow-y: auto;
|
||||
display: flex; flex-direction: column; gap: 3px;
|
||||
|
|
@ -551,19 +552,20 @@
|
|||
|
||||
/* ─── Projects view ──────────────────────────────────────────────────────────── */
|
||||
.gpt-projects-list { flex: 1; overflow-y: auto; padding: 8px; display: flex; flex-direction: column; gap: 6px; scrollbar-width: thin; }
|
||||
.gpt-projects-active-bar { display: flex; align-items: center; gap: 8px; padding: 8px 14px; border-bottom: 1px solid; flex-shrink: 0; font-size: 11px; }
|
||||
.gpt-projects-active-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
|
||||
.gpt-projects-active-bar { display: flex; align-items: center; gap: 8px; padding: 8px 14px; border-bottom: 1px solid color-mix(in srgb, var(--gpt-project-color, var(--interactive-accent)) 25%, transparent); background: color-mix(in srgb, var(--gpt-project-color, var(--interactive-accent)) 12%, var(--background-secondary)); flex-shrink: 0; font-size: 11px; }
|
||||
.gpt-projects-active-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: var(--gpt-project-color, var(--interactive-accent)); }
|
||||
.gpt-projects-active-name { font-size: 11px; font-weight: 600; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.gpt-projects-empty { color: var(--text-muted); font-size: 12px; text-align: center; margin-top: 24px; padding: 0 12px; line-height: 1.6; }
|
||||
.gpt-projects-empty-hint { font-size: 11px; opacity: .7; margin-top: 4px; }
|
||||
.gpt-projects-card { padding: 11px 13px; border-radius: 10px; cursor: pointer; border: 2px solid transparent; background: var(--background-secondary); transition: all .15s; }
|
||||
.gpt-projects-card:hover { background: var(--background-modifier-hover); }
|
||||
.gpt-projects-card--active { border-color: var(--gpt-project-color, var(--interactive-accent)); background: color-mix(in srgb, var(--gpt-project-color, var(--interactive-accent)) 8%, var(--background-secondary)); }
|
||||
.gpt-projects-card-top { display: flex; align-items: center; gap: 8px; }
|
||||
.gpt-projects-card-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
|
||||
.gpt-projects-card-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; background: var(--gpt-project-color, var(--interactive-accent)); }
|
||||
.gpt-projects-card-name { font-size: 12px; font-weight: 700; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-normal); }
|
||||
.gpt-projects-card-badge { font-size: 10px; padding: 1px 7px; border-radius: 10px; font-weight: 600; flex-shrink: 0; }
|
||||
.gpt-projects-card-badge { font-size: 10px; padding: 1px 7px; border-radius: 10px; font-weight: 600; flex-shrink: 0; background: color-mix(in srgb, var(--gpt-project-color, var(--interactive-accent)) 15%, var(--background-primary)); color: var(--gpt-project-color, var(--interactive-accent)); }
|
||||
.gpt-projects-card-desc { font-size: 11px; color: var(--text-muted); margin-top: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.gpt-projects-card-prompt-tag { display: inline-flex; align-items: center; gap: 4px; margin-top: 4px; padding: 2px 8px; border-radius: 10px; font-size: 10px; font-weight: 600; border: 1px solid; }
|
||||
.gpt-projects-card-prompt-tag { display: inline-flex; align-items: center; gap: 4px; margin-top: 4px; padding: 2px 8px; border-radius: 10px; font-size: 10px; font-weight: 600; border: 1px solid color-mix(in srgb, var(--gpt-project-color, var(--interactive-accent)) 20%, transparent); background: color-mix(in srgb, var(--gpt-project-color, var(--interactive-accent)) 10%, var(--background-primary)); color: var(--gpt-project-color, var(--interactive-accent)); }
|
||||
.gpt-projects-card-chats { margin-top: 8px; display: flex; flex-direction: column; gap: 3px; }
|
||||
.gpt-projects-card-chat { display: flex; align-items: center; gap: 6px; padding: 4px 8px; border-radius: 6px; font-size: 11px; color: var(--text-muted); cursor: pointer; transition: background .1s; }
|
||||
.gpt-projects-card-chat:hover { background: var(--background-modifier-hover); }
|
||||
|
|
@ -625,3 +627,14 @@
|
|||
font-size: 12px; line-height: 1.6;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
.gpt-settings-input-compact {
|
||||
width: 90px;
|
||||
max-width: 100%;
|
||||
}
|
||||
.gpt-settings-input-full {
|
||||
width: 100%;
|
||||
}
|
||||
.gpt-settings-storage-path {
|
||||
font-size: 11px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue