@qnote/q-ai-note 1.0.22 → 1.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server/api/images.d.ts +3 -0
- package/dist/server/api/images.d.ts.map +1 -0
- package/dist/server/api/images.js +89 -0
- package/dist/server/api/images.js.map +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +5 -1
- package/dist/server/index.js.map +1 -1
- package/dist/web/app.js +203 -1
- package/dist/web/styles.css +62 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"images.d.ts","sourceRoot":"","sources":["../../../src/server/api/images.ts"],"names":[],"mappings":"AAOA,QAAA,MAAM,MAAM,4CAAW,CAAC;AA0FxB,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { Router } from 'express';
|
|
4
|
+
import { randomUUID } from 'crypto';
|
|
5
|
+
import { getResolvedDbPath } from '../db.js';
|
|
6
|
+
import { forbid, getAccessContextFromResponse } from './accessHelpers.js';
|
|
7
|
+
const router = Router();
|
|
8
|
+
const MAX_IMAGE_SIZE_BYTES = 20 * 1024 * 1024;
|
|
9
|
+
const IMAGE_EXT_BY_MIME = {
|
|
10
|
+
'image/png': 'png',
|
|
11
|
+
'image/jpeg': 'jpg',
|
|
12
|
+
'image/jpg': 'jpg',
|
|
13
|
+
'image/webp': 'webp',
|
|
14
|
+
'image/gif': 'gif',
|
|
15
|
+
};
|
|
16
|
+
function ensureDir(dirPath) {
|
|
17
|
+
if (!fs.existsSync(dirPath)) {
|
|
18
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function normalizeBase64(input) {
|
|
22
|
+
const raw = String(input || '').trim();
|
|
23
|
+
if (!raw)
|
|
24
|
+
return '';
|
|
25
|
+
const marker = ';base64,';
|
|
26
|
+
const markerIdx = raw.indexOf(marker);
|
|
27
|
+
if (raw.startsWith('data:') && markerIdx >= 0) {
|
|
28
|
+
return raw.slice(markerIdx + marker.length).trim();
|
|
29
|
+
}
|
|
30
|
+
return raw;
|
|
31
|
+
}
|
|
32
|
+
function pickExtension(mimeType, filename = '') {
|
|
33
|
+
const mime = String(mimeType || '').trim().toLowerCase();
|
|
34
|
+
if (IMAGE_EXT_BY_MIME[mime])
|
|
35
|
+
return IMAGE_EXT_BY_MIME[mime];
|
|
36
|
+
const ext = path.extname(String(filename || '').trim()).replace('.', '').toLowerCase();
|
|
37
|
+
if (ext && ['png', 'jpg', 'jpeg', 'webp', 'gif'].includes(ext)) {
|
|
38
|
+
return ext === 'jpeg' ? 'jpg' : ext;
|
|
39
|
+
}
|
|
40
|
+
return '';
|
|
41
|
+
}
|
|
42
|
+
router.post('/', (req, res) => {
|
|
43
|
+
try {
|
|
44
|
+
const access = getAccessContextFromResponse(res);
|
|
45
|
+
const hasWritablePage = Boolean(access.full_access
|
|
46
|
+
|| access.page_access?.sandboxes
|
|
47
|
+
|| access.page_access?.diaries
|
|
48
|
+
|| access.page_access?.ai_engineering);
|
|
49
|
+
if (!hasWritablePage) {
|
|
50
|
+
return forbid(res, 'No permission to upload images');
|
|
51
|
+
}
|
|
52
|
+
const mimeType = String(req.body?.mime_type || '').trim().toLowerCase();
|
|
53
|
+
const filename = String(req.body?.filename || '').trim();
|
|
54
|
+
const dataBase64 = normalizeBase64(String(req.body?.data_base64 || ''));
|
|
55
|
+
if (!dataBase64) {
|
|
56
|
+
return res.status(400).json({ success: false, error: 'data_base64 is required' });
|
|
57
|
+
}
|
|
58
|
+
const extension = pickExtension(mimeType, filename);
|
|
59
|
+
if (!extension) {
|
|
60
|
+
return res.status(400).json({ success: false, error: 'Unsupported image type' });
|
|
61
|
+
}
|
|
62
|
+
const buffer = Buffer.from(dataBase64, 'base64');
|
|
63
|
+
if (!buffer.length) {
|
|
64
|
+
return res.status(400).json({ success: false, error: 'Invalid image payload' });
|
|
65
|
+
}
|
|
66
|
+
if (buffer.length > MAX_IMAGE_SIZE_BYTES) {
|
|
67
|
+
return res.status(413).json({ success: false, error: 'Image too large (max 20MB)' });
|
|
68
|
+
}
|
|
69
|
+
const dataDir = getResolvedDbPath();
|
|
70
|
+
const imagesDir = path.join(dataDir, 'images');
|
|
71
|
+
ensureDir(imagesDir);
|
|
72
|
+
const savedFileName = `${Date.now()}-${randomUUID()}.${extension}`;
|
|
73
|
+
const outputPath = path.join(imagesDir, savedFileName);
|
|
74
|
+
fs.writeFileSync(outputPath, buffer);
|
|
75
|
+
return res.status(201).json({
|
|
76
|
+
success: true,
|
|
77
|
+
data: {
|
|
78
|
+
url: `/images/${savedFileName}`,
|
|
79
|
+
file_name: savedFileName,
|
|
80
|
+
size_bytes: buffer.length,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
return res.status(500).json({ success: false, error: String(error) });
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
export default router;
|
|
89
|
+
//# sourceMappingURL=images.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"images.js","sourceRoot":"","sources":["../../../src/server/api/images.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AA6BxC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAkBD,wBAAgB,eAAe,CAC7B,EAAE,EAAE,MAAM,EACV,WAAW,GAAE,OAAO,GAAG,YAAoB,EAC3C,UAAU,GAAE,GAAG,CAAC,MAAM,CAAqB,EAC3C,mBAAmB,GAAE,GAAG,CAAC,MAAM,CAAqB,GACnD,OAAO,CAOT;AAED,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,MAAM,EACV,WAAW,GAAE,OAAO,GAAG,YAAoB,EAC3C,UAAU,GAAE,GAAG,CAAC,MAAM,CAAqB,GAC1C,OAAO,CAKT;AAYD,wBAAgB,SAAS,CAAC,WAAW,GAAE,OAAO,GAAG,YAAuB,+CA0EvE;AAED,wBAAgB,WAAW,CACzB,IAAI,SAAO,EACX,IAAI,SAAO,EACX,WAAW,GAAE,OAAO,GAAG,YAAuE,GAC7F,MAAM,CAmBR;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAkBhD"}
|
package/dist/server/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import path from 'path';
|
|
|
3
3
|
import os from 'os';
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
5
5
|
import { initDb, closeDb } from './db.js';
|
|
6
|
+
import { getResolvedDbPath } from './db.js';
|
|
6
7
|
import sandboxRouter from './api/sandbox.js';
|
|
7
8
|
import workItemRouter from './api/workItem.js';
|
|
8
9
|
import diaryRouter from './api/diary.js';
|
|
@@ -11,6 +12,7 @@ import settingsRouter from './api/settings.js';
|
|
|
11
12
|
import nodeEntitiesRouter from './api/nodeEntities.js';
|
|
12
13
|
import projectSettingsRouter from './api/projectSettings.js';
|
|
13
14
|
import aserRuntimeRouter from './api/aserRuntime.js';
|
|
15
|
+
import imagesRouter from './api/images.js';
|
|
14
16
|
import { getAccessContext, normalizeIpAddress as normalizeIpAddressFromAccess, } from './accessControl.js';
|
|
15
17
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
16
18
|
const PORT = Number(process.env.PORT || 3000);
|
|
@@ -72,9 +74,10 @@ export function createApp(inputPolicy = READONLY) {
|
|
|
72
74
|
localIpSet,
|
|
73
75
|
});
|
|
74
76
|
const app = express();
|
|
75
|
-
app.use(express.json());
|
|
77
|
+
app.use(express.json({ limit: '25mb' }));
|
|
76
78
|
app.use('/node_modules', express.static(path.join(__dirname, '../../node_modules')));
|
|
77
79
|
app.use(express.static(path.join(__dirname, '../web')));
|
|
80
|
+
app.use('/images', express.static(path.join(getResolvedDbPath(), 'images')));
|
|
78
81
|
app.get('/api/runtime', (req, res) => {
|
|
79
82
|
const access = getRequestAccessContext(req);
|
|
80
83
|
res.json({
|
|
@@ -119,6 +122,7 @@ export function createApp(inputPolicy = READONLY) {
|
|
|
119
122
|
app.use('/api/items', workItemRouter);
|
|
120
123
|
app.use('/api/diaries', diaryRouter);
|
|
121
124
|
app.use('/api/chats', chatRouter);
|
|
125
|
+
app.use('/api/images', imagesRouter);
|
|
122
126
|
app.use('/api/settings', settingsRouter);
|
|
123
127
|
app.use('/api/project-settings', projectSettingsRouter);
|
|
124
128
|
app.use('/api/sandboxes/:sandboxId/entities', nodeEntitiesRouter);
|
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
|
package/dist/web/app.js
CHANGED
|
@@ -1592,10 +1592,15 @@ function renderMarkdownSnippet(text, options = {}) {
|
|
|
1592
1592
|
|
|
1593
1593
|
const renderInline = (raw) => {
|
|
1594
1594
|
let html = safeText(String(raw || ''));
|
|
1595
|
+
html = html.replace(/!\[([^\]]*)\]\(((?:https?:\/\/|\/)[^\s)]+)\)/g, (_m, alt, url) => {
|
|
1596
|
+
const safeUrl = safeText(url);
|
|
1597
|
+
const safeAlt = safeText(alt || 'image');
|
|
1598
|
+
return `<img src="${safeUrl}" alt="${safeAlt}" loading="lazy">`;
|
|
1599
|
+
});
|
|
1595
1600
|
html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
|
|
1596
1601
|
html = html.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
|
1597
1602
|
html = html.replace(/\*([^*]+)\*/g, '<em>$1</em>');
|
|
1598
|
-
html = html.replace(/\[([^\]]+)\]\((https
|
|
1603
|
+
html = html.replace(/\[([^\]]+)\]\(((?:https?:\/\/|\/)[^\s)]+)\)/g, (_m, label, url) => {
|
|
1599
1604
|
const safeUrl = safeText(url);
|
|
1600
1605
|
const safeLabel = safeText(label);
|
|
1601
1606
|
return `<a href="${safeUrl}" target="_blank" rel="noopener noreferrer">${safeLabel}</a>`;
|
|
@@ -3734,8 +3739,204 @@ function editWorkItem(id) {
|
|
|
3734
3739
|
document.getElementById('item-dialog').showModal();
|
|
3735
3740
|
}
|
|
3736
3741
|
|
|
3742
|
+
const MARKDOWN_PASTE_TEXTAREA_IDS = [
|
|
3743
|
+
'diary-content',
|
|
3744
|
+
'diary-edit-content',
|
|
3745
|
+
'entity-content-input',
|
|
3746
|
+
'drawer-diary-content',
|
|
3747
|
+
'drawer-work-item-description',
|
|
3748
|
+
'new-item-desc',
|
|
3749
|
+
];
|
|
3750
|
+
|
|
3751
|
+
function readFileAsDataUrl(file) {
|
|
3752
|
+
return new Promise((resolve, reject) => {
|
|
3753
|
+
const reader = new FileReader();
|
|
3754
|
+
reader.onload = () => resolve(String(reader.result || ''));
|
|
3755
|
+
reader.onerror = () => reject(new Error('读取图片失败'));
|
|
3756
|
+
reader.readAsDataURL(file);
|
|
3757
|
+
});
|
|
3758
|
+
}
|
|
3759
|
+
|
|
3760
|
+
function isStandaloneHttpUrl(text) {
|
|
3761
|
+
const value = String(text || '').trim();
|
|
3762
|
+
if (!value || /\s/.test(value)) return false;
|
|
3763
|
+
return /^https?:\/\/[^\s]+$/i.test(value);
|
|
3764
|
+
}
|
|
3765
|
+
|
|
3766
|
+
function deriveMarkdownLinkName(urlText) {
|
|
3767
|
+
try {
|
|
3768
|
+
const parsed = new URL(String(urlText || '').trim());
|
|
3769
|
+
const segments = String(parsed.pathname || '')
|
|
3770
|
+
.split('/')
|
|
3771
|
+
.map((segment) => segment.trim())
|
|
3772
|
+
.filter((segment) => Boolean(segment));
|
|
3773
|
+
if (!segments.length) return '链接';
|
|
3774
|
+
const lastSegment = decodeURIComponent(segments[segments.length - 1] || '').trim();
|
|
3775
|
+
if (!lastSegment) return '链接';
|
|
3776
|
+
const withoutExt = lastSegment
|
|
3777
|
+
.replace(/\.(?:html?|xhtml|shtml|php|asp|aspx|jsp)$/i, '')
|
|
3778
|
+
.trim();
|
|
3779
|
+
const normalized = withoutExt
|
|
3780
|
+
.replace(/[-_]+/g, ' ')
|
|
3781
|
+
.replace(/\s+/g, ' ')
|
|
3782
|
+
.trim();
|
|
3783
|
+
return normalized || '链接';
|
|
3784
|
+
} catch {
|
|
3785
|
+
return '链接';
|
|
3786
|
+
}
|
|
3787
|
+
}
|
|
3788
|
+
|
|
3789
|
+
function insertTextAtCursor(textarea, text) {
|
|
3790
|
+
const start = Number(textarea.selectionStart || 0);
|
|
3791
|
+
const end = Number(textarea.selectionEnd || 0);
|
|
3792
|
+
const value = String(textarea.value || '');
|
|
3793
|
+
const prefix = value.slice(0, start);
|
|
3794
|
+
const suffix = value.slice(end);
|
|
3795
|
+
const prefixBreak = prefix.length > 0 && !prefix.endsWith('\n') ? '\n' : '';
|
|
3796
|
+
const suffixBreak = suffix.length > 0 && !suffix.startsWith('\n') ? '\n' : '';
|
|
3797
|
+
const inserted = `${prefixBreak}${text}${suffixBreak}`;
|
|
3798
|
+
textarea.value = `${prefix}${inserted}${suffix}`;
|
|
3799
|
+
const nextCaret = prefix.length + inserted.length;
|
|
3800
|
+
textarea.selectionStart = nextCaret;
|
|
3801
|
+
textarea.selectionEnd = nextCaret;
|
|
3802
|
+
textarea.dispatchEvent(new Event('input', { bubbles: true }));
|
|
3803
|
+
}
|
|
3804
|
+
|
|
3805
|
+
async function uploadPastedImage(file) {
|
|
3806
|
+
const dataUrl = await readFileAsDataUrl(file);
|
|
3807
|
+
const marker = ';base64,';
|
|
3808
|
+
const markerIdx = dataUrl.indexOf(marker);
|
|
3809
|
+
if (markerIdx < 0) {
|
|
3810
|
+
throw new Error('无法解析图片数据');
|
|
3811
|
+
}
|
|
3812
|
+
const dataBase64 = dataUrl.slice(markerIdx + marker.length).trim();
|
|
3813
|
+
const response = await fetch(`${API_BASE}/images`, {
|
|
3814
|
+
method: 'POST',
|
|
3815
|
+
headers: { 'Content-Type': 'application/json' },
|
|
3816
|
+
body: JSON.stringify({
|
|
3817
|
+
filename: file.name || '',
|
|
3818
|
+
mime_type: file.type || '',
|
|
3819
|
+
data_base64: dataBase64,
|
|
3820
|
+
}),
|
|
3821
|
+
});
|
|
3822
|
+
const result = await response.json();
|
|
3823
|
+
if (!response.ok || !result?.success || !result?.data?.url) {
|
|
3824
|
+
throw new Error(result?.error || '图片上传失败');
|
|
3825
|
+
}
|
|
3826
|
+
return String(result.data.url);
|
|
3827
|
+
}
|
|
3828
|
+
|
|
3829
|
+
function bindMarkdownPasteForTextarea(textarea) {
|
|
3830
|
+
if (!(textarea instanceof HTMLTextAreaElement)) return;
|
|
3831
|
+
if (textarea.dataset.mdPasteImageBound === '1') return;
|
|
3832
|
+
textarea.dataset.mdPasteImageBound = '1';
|
|
3833
|
+
textarea.addEventListener('paste', async (event) => {
|
|
3834
|
+
const items = Array.from(event.clipboardData?.items || []);
|
|
3835
|
+
const imageFiles = items
|
|
3836
|
+
.filter((item) => item.kind === 'file' && String(item.type || '').startsWith('image/'))
|
|
3837
|
+
.map((item) => item.getAsFile())
|
|
3838
|
+
.filter((file) => Boolean(file));
|
|
3839
|
+
if (imageFiles.length) {
|
|
3840
|
+
event.preventDefault();
|
|
3841
|
+
const errors = [];
|
|
3842
|
+
for (const file of imageFiles) {
|
|
3843
|
+
try {
|
|
3844
|
+
const imageUrl = await uploadPastedImage(file);
|
|
3845
|
+
insertTextAtCursor(textarea, ``);
|
|
3846
|
+
} catch (error) {
|
|
3847
|
+
errors.push(error);
|
|
3848
|
+
}
|
|
3849
|
+
}
|
|
3850
|
+
if (errors.length) {
|
|
3851
|
+
alert(`粘贴图片失败:${String(errors[0]?.message || errors[0])}`);
|
|
3852
|
+
}
|
|
3853
|
+
return;
|
|
3854
|
+
}
|
|
3855
|
+
const plainText = String(event.clipboardData?.getData('text/plain') || '').trim();
|
|
3856
|
+
if (!isStandaloneHttpUrl(plainText)) return;
|
|
3857
|
+
const linkName = deriveMarkdownLinkName(plainText);
|
|
3858
|
+
event.preventDefault();
|
|
3859
|
+
insertTextAtCursor(textarea, `[${linkName}](${plainText})`);
|
|
3860
|
+
if (typeof textarea.focus === 'function') {
|
|
3861
|
+
textarea.focus();
|
|
3862
|
+
}
|
|
3863
|
+
});
|
|
3864
|
+
}
|
|
3865
|
+
|
|
3866
|
+
function initMarkdownImagePasteSupport() {
|
|
3867
|
+
MARKDOWN_PASTE_TEXTAREA_IDS.forEach((id) => {
|
|
3868
|
+
const el = document.getElementById(id);
|
|
3869
|
+
if (el instanceof HTMLTextAreaElement) {
|
|
3870
|
+
bindMarkdownPasteForTextarea(el);
|
|
3871
|
+
}
|
|
3872
|
+
});
|
|
3873
|
+
}
|
|
3874
|
+
|
|
3875
|
+
let markdownImageLightboxEl = null;
|
|
3876
|
+
|
|
3877
|
+
function ensureMarkdownImageLightbox() {
|
|
3878
|
+
if (markdownImageLightboxEl instanceof HTMLElement) {
|
|
3879
|
+
return markdownImageLightboxEl;
|
|
3880
|
+
}
|
|
3881
|
+
const overlay = document.createElement('div');
|
|
3882
|
+
overlay.className = 'image-lightbox hidden';
|
|
3883
|
+
overlay.id = 'image-lightbox';
|
|
3884
|
+
overlay.innerHTML = `
|
|
3885
|
+
<div class="image-lightbox-backdrop" data-action="close"></div>
|
|
3886
|
+
<div class="image-lightbox-content">
|
|
3887
|
+
<img id="image-lightbox-img" alt="preview image">
|
|
3888
|
+
</div>
|
|
3889
|
+
`;
|
|
3890
|
+
document.body.appendChild(overlay);
|
|
3891
|
+
overlay.addEventListener('click', (event) => {
|
|
3892
|
+
const target = event.target;
|
|
3893
|
+
if (target instanceof HTMLElement && target.dataset.action === 'close') {
|
|
3894
|
+
event.preventDefault();
|
|
3895
|
+
event.stopPropagation();
|
|
3896
|
+
overlay.classList.add('hidden');
|
|
3897
|
+
overlay.setAttribute('aria-hidden', 'true');
|
|
3898
|
+
}
|
|
3899
|
+
});
|
|
3900
|
+
markdownImageLightboxEl = overlay;
|
|
3901
|
+
return overlay;
|
|
3902
|
+
}
|
|
3903
|
+
|
|
3904
|
+
function openMarkdownImageLightbox(src, alt = '') {
|
|
3905
|
+
const overlay = ensureMarkdownImageLightbox();
|
|
3906
|
+
const img = overlay.querySelector('#image-lightbox-img');
|
|
3907
|
+
if (!(img instanceof HTMLImageElement)) return;
|
|
3908
|
+
img.src = String(src || '');
|
|
3909
|
+
img.alt = String(alt || 'preview image');
|
|
3910
|
+
overlay.classList.remove('hidden');
|
|
3911
|
+
overlay.setAttribute('aria-hidden', 'false');
|
|
3912
|
+
}
|
|
3913
|
+
|
|
3914
|
+
function initMarkdownImageLightboxSupport() {
|
|
3915
|
+
document.addEventListener('click', (event) => {
|
|
3916
|
+
const target = event.target;
|
|
3917
|
+
if (!(target instanceof HTMLImageElement)) return;
|
|
3918
|
+
if (!target.closest('.diary-content, .entity-content, .chat-message.assistant')) return;
|
|
3919
|
+
const src = String(target.getAttribute('src') || '').trim();
|
|
3920
|
+
if (!src) return;
|
|
3921
|
+
event.preventDefault();
|
|
3922
|
+
openMarkdownImageLightbox(src, String(target.getAttribute('alt') || ''));
|
|
3923
|
+
});
|
|
3924
|
+
document.addEventListener('keydown', (event) => {
|
|
3925
|
+
if (event.key !== 'Escape') return;
|
|
3926
|
+
const overlay = markdownImageLightboxEl;
|
|
3927
|
+
if (!(overlay instanceof HTMLElement)) return;
|
|
3928
|
+
if (overlay.classList.contains('hidden')) return;
|
|
3929
|
+
event.preventDefault();
|
|
3930
|
+
event.stopPropagation();
|
|
3931
|
+
overlay.classList.add('hidden');
|
|
3932
|
+
overlay.setAttribute('aria-hidden', 'true');
|
|
3933
|
+
});
|
|
3934
|
+
}
|
|
3935
|
+
|
|
3737
3936
|
async function initApp() {
|
|
3738
3937
|
await loadRuntimeMode();
|
|
3938
|
+
initMarkdownImagePasteSupport();
|
|
3939
|
+
initMarkdownImageLightboxSupport();
|
|
3739
3940
|
loadWorkItemAssigneePreference();
|
|
3740
3941
|
loadWorkTreeViewModePreference();
|
|
3741
3942
|
loadSandboxSortModePreference();
|
|
@@ -4265,6 +4466,7 @@ async function initApp() {
|
|
|
4265
4466
|
if (!drawer || drawer.classList.contains('hidden')) return;
|
|
4266
4467
|
const target = event.target;
|
|
4267
4468
|
if (!(target instanceof Node)) return;
|
|
4469
|
+
if (target instanceof HTMLElement && target.closest('#image-lightbox')) return;
|
|
4268
4470
|
if (drawer.contains(target)) return;
|
|
4269
4471
|
if (workTree?.contains(target)) return;
|
|
4270
4472
|
closeNodeEntityDrawer();
|
package/dist/web/styles.css
CHANGED
|
@@ -2900,6 +2900,68 @@ h2 {
|
|
|
2900
2900
|
font-size: 12px;
|
|
2901
2901
|
}
|
|
2902
2902
|
|
|
2903
|
+
.diary-content img,
|
|
2904
|
+
.entity-content img,
|
|
2905
|
+
.chat-message.assistant img {
|
|
2906
|
+
max-width: min(100%, 820px);
|
|
2907
|
+
max-height: min(56vh, 520px);
|
|
2908
|
+
height: auto;
|
|
2909
|
+
width: auto;
|
|
2910
|
+
object-fit: contain;
|
|
2911
|
+
border-radius: 6px;
|
|
2912
|
+
display: block;
|
|
2913
|
+
margin: 10px 0;
|
|
2914
|
+
cursor: zoom-in;
|
|
2915
|
+
border: 1px solid #d8e0ec;
|
|
2916
|
+
background: #f8fafd;
|
|
2917
|
+
box-shadow: 0 6px 16px rgba(18, 42, 76, 0.12);
|
|
2918
|
+
padding: 4px;
|
|
2919
|
+
}
|
|
2920
|
+
|
|
2921
|
+
.image-lightbox {
|
|
2922
|
+
position: fixed;
|
|
2923
|
+
inset: 0;
|
|
2924
|
+
z-index: 2000;
|
|
2925
|
+
display: flex;
|
|
2926
|
+
align-items: center;
|
|
2927
|
+
justify-content: center;
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2930
|
+
.image-lightbox.hidden {
|
|
2931
|
+
display: none;
|
|
2932
|
+
}
|
|
2933
|
+
|
|
2934
|
+
.image-lightbox-backdrop {
|
|
2935
|
+
position: absolute;
|
|
2936
|
+
inset: 0;
|
|
2937
|
+
background: rgba(0, 0, 0, 0.68);
|
|
2938
|
+
}
|
|
2939
|
+
|
|
2940
|
+
.image-lightbox-content {
|
|
2941
|
+
position: relative;
|
|
2942
|
+
width: auto;
|
|
2943
|
+
max-width: 92vw;
|
|
2944
|
+
max-height: 92vh;
|
|
2945
|
+
padding: 0;
|
|
2946
|
+
border-radius: 0;
|
|
2947
|
+
background: transparent;
|
|
2948
|
+
box-shadow: none;
|
|
2949
|
+
display: flex;
|
|
2950
|
+
align-items: center;
|
|
2951
|
+
justify-content: center;
|
|
2952
|
+
}
|
|
2953
|
+
|
|
2954
|
+
.image-lightbox-content img {
|
|
2955
|
+
display: block;
|
|
2956
|
+
max-width: 92vw;
|
|
2957
|
+
max-height: 92vh;
|
|
2958
|
+
width: auto;
|
|
2959
|
+
height: auto;
|
|
2960
|
+
border-radius: 6px;
|
|
2961
|
+
margin: 0;
|
|
2962
|
+
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.35);
|
|
2963
|
+
}
|
|
2964
|
+
|
|
2903
2965
|
.diary-actions {
|
|
2904
2966
|
display: flex;
|
|
2905
2967
|
flex-wrap: wrap;
|