Compare commits

...

2 Commits

Author SHA1 Message Date
Laan Tungir
7ce913997a This is a meaningful git commit message 2026-04-28 12:33:29 -04:00
Laan Tungir
63f5097a6d This is a meaningful git commit message 2026-04-28 10:44:22 -04:00
2 changed files with 130 additions and 18 deletions

View File

@@ -334,6 +334,44 @@
display: none;
}
.docPreviewMeta {
border: 1px solid var(--muted-color);
border-radius: 8px;
padding: 10px;
margin-bottom: 10px;
display: flex;
flex-direction: column;
gap: 6px;
background: color-mix(in srgb, var(--secondary-color) 88%, var(--muted-color) 12%);
}
.docPreviewMetaRow {
font-size: 84%;
line-height: 1.4;
word-break: break-word;
}
.docPreviewMetaLabel {
font-weight: 700;
color: var(--primary-color);
}
.docPreviewImageWrap {
margin-top: 6px;
}
.docPreviewImage {
max-width: 100%;
height: auto;
border-radius: 8px;
border: 1px solid var(--muted-color);
display: block;
}
.docPreviewContent {
min-height: 40px;
}
#divDocumentInfo {
font-size: 72%;
color: var(--muted-color);
@@ -1215,12 +1253,47 @@ user:
return window.DOMPurify ? window.DOMPurify.sanitize(html) : html;
}
function normalizePreviewImageUrl(rawUrl) {
const value = String(rawUrl || '').trim();
if (!value) return '';
try {
const parsed = new URL(value, window.location.origin);
if (parsed.protocol === 'http:' || parsed.protocol === 'https:') {
return parsed.href;
}
} catch (_error) {
// ignore invalid urls
}
return '';
}
function renderDocumentMetaPreview() {
const title = String(inpDocumentTitle?.value || '').trim();
const summary = String(inpDocumentSummary?.value || '').trim();
const tags = String(inpDocumentTags?.value || '').trim();
const imageUrl = normalizePreviewImageUrl(inpDocumentImage?.value || '');
const imageBlock = imageUrl
? `<div class="docPreviewImageWrap"><img class="docPreviewImage" src="${escapeHtml(imageUrl)}" alt="Document image" loading="lazy" /></div>`
: '';
return `
<div class="docPreviewMeta">
<div class="docPreviewMetaRow"><span class="docPreviewMetaLabel">Title:</span> ${escapeHtml(title || '—')}</div>
<div class="docPreviewMetaRow"><span class="docPreviewMetaLabel">Summary:</span> ${escapeHtml(summary || '—')}</div>
<div class="docPreviewMetaRow"><span class="docPreviewMetaLabel">Tags:</span> ${escapeHtml(tags || '—')}</div>
${imageBlock}
</div>
`;
}
function updateDocumentView() {
if (!taDocument || !divDocumentPreview) return;
if (documentViewMode === 'markdown') {
taDocument.style.display = 'none';
divDocumentPreview.style.display = 'block';
divDocumentPreview.innerHTML = renderDocumentPreview(taDocument.value || '');
const metaHtml = renderDocumentMetaPreview();
const bodyHtml = renderDocumentPreview(taDocument.value || '');
divDocumentPreview.innerHTML = `${metaHtml}<div class="docPreviewContent">${bodyHtml}</div>`;
return;
}
taDocument.style.display = 'block';
@@ -1803,13 +1876,21 @@ user:
}
function enforceDefaultSkillSelection() {
const convo = getCurrentConversation();
if (!convo) return;
const defaultKey = getDefaultDocumentSkillKey();
if (!defaultKey) return;
const hasDefaultSkill = skills.some((s) => s.key === defaultKey);
if (!hasDefaultSkill) return;
const convo = getCurrentConversation();
if (!convo) {
if (!selectedSkillKeys.includes(defaultKey)) {
selectedSkillKeys = [...selectedSkillKeys, defaultKey];
renderSkillsList();
renderSkillsEditor();
}
return;
}
const removed = new Set(getConversationRemovedSkillKeys(convo));
const selected = new Set(getConversationSkillKeys(convo));
if (!removed.has(defaultKey) && !selected.has(defaultKey)) {
@@ -3518,6 +3599,7 @@ user:
inputEl.addEventListener('input', () => {
if (CURRENT_NOTE) setDocumentInfo(`Editing draft • d:${CURRENT_NOTE} • UNSAVED`);
scheduleDocumentAutosave();
updateDocumentView();
renderCurrentConversation();
});
inputEl.addEventListener('blur', () => {
@@ -4061,15 +4143,40 @@ user:
});
}
function upsertDefaultDocumentSkillDraft() {
if (!currentPubkey) return;
const key = getDefaultDocumentSkillKey();
if (!key) return;
if (skills.some((s) => s.key === key)) return;
const llm = String(aiConfig.model || 'default').trim() || 'default';
const temperature = Number(aiConfig.temperature ?? 0);
const maxTokens = Math.max(1, Math.floor(Number(aiConfig.max_tokens ?? 10000)));
const evt = {
kind: 31123,
created_at: Math.floor(Date.now() / 1000),
pubkey: currentPubkey,
id: uid(),
tags: [
['d', DEFAULT_DOCUMENT_SKILL_SLUG],
['description', DEFAULT_DOCUMENT_SKILL_DESCRIPTION],
['llm', llm],
['temperature', String(temperature)],
['max_tokens', String(maxTokens)]
],
content: DEFAULT_DOCUMENT_SKILL_TEMPLATE
};
upsertSkillFromEvent(evt);
}
async function ensureDefaultDocumentSkillExists() {
if (!currentPubkey) return;
const slug = DEFAULT_DOCUMENT_SKILL_SLUG;
const key = getDefaultDocumentSkillKey();
const existingInMemory = skills.find((s) => s.key === key);
if (existingInMemory) {
enforceDefaultSkillSelection();
return;
}
// Ensure visibility/editability immediately, even before network round-trips.
upsertDefaultDocumentSkillDraft();
enforceDefaultSkillSelection();
const filter = {
kinds: [31123],
@@ -4128,13 +4235,18 @@ user:
};
const skillEvent = buildSkillEventFromEditor(draftSkill);
await publishEvent(skillEvent);
upsertSkillFromEvent({
...skillEvent,
pubkey: currentPubkey,
id: uid()
});
setStatus('Created default-document-skill.');
try {
await publishEvent(skillEvent);
upsertSkillFromEvent({
...skillEvent,
pubkey: currentPubkey,
id: uid()
});
setStatus('Created default-document-skill.');
} catch (error) {
console.warn('[document.html] failed to publish default-document-skill, keeping local draft:', error);
setStatus('Default document skill loaded locally (publish pending).');
}
enforceDefaultSkillSelection();
}

View File

@@ -1,5 +1,5 @@
{
"VERSION": "v0.7.8",
"VERSION_NUMBER": "0.7.8",
"BUILD_DATE": "2026-04-28T14:39:51.733Z"
"VERSION": "v0.7.10",
"VERSION_NUMBER": "0.7.10",
"BUILD_DATE": "2026-04-28T16:33:28.943Z"
}