sync: update from private repo (e62f5c7)
CI / build-and-test (push) Has been cancelled

This commit is contained in:
oss-sync
2026-06-11 01:52:48 +00:00
parent 000a2474aa
commit d061ad08d8
237 changed files with 8441 additions and 5549 deletions
+20 -11
View File
@@ -1,5 +1,7 @@
import type { ReactNode } from 'react';
import { useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import i18n from '../../i18n';
import { Marked, Renderer } from 'marked';
import DOMPurify from 'dompurify';
import mermaid from 'mermaid';
@@ -229,6 +231,7 @@ interface MarkdownPreviewProps {
}
export function MarkdownPreview({ content, imageBaseUrl, taskId, showOutline = false }: MarkdownPreviewProps): JSX.Element {
const { t } = useTranslation('files');
const truncated = content.slice(0, 100000);
const containerRef = useRef<HTMLDivElement>(null);
const [activeSlug, setActiveSlug] = useState<string>('');
@@ -346,7 +349,7 @@ export function MarkdownPreview({ content, imageBaseUrl, taskId, showOutline = f
return (
<div className="flex gap-4 items-start">
<aside className="mdxg-outline hidden md:block flex-shrink-0 sticky top-0 max-h-[68vh] overflow-y-auto pr-2 border-r border-hairline" style={{ width: '200px' }}>
<div className="text-2xs font-semibold text-slate-500 uppercase tracking-wide px-2 py-1.5"></div>
<div className="text-2xs font-semibold text-slate-500 uppercase tracking-wide px-2 py-1.5">{t('toc')}</div>
<nav>
{outline.map(h => (
<a
@@ -585,7 +588,7 @@ function renderJsonl(content: string): JSX.Element {
}
if (records.length === 0) {
return <p className="text-slate-400 text-sm"></p>;
return <p className="text-slate-400 text-sm">{i18n.t('files:records.empty')}</p>;
}
const columns = [...new Set(records.flatMap(r => Object.keys(r)))];
@@ -620,6 +623,7 @@ function renderJsonl(content: string): JSX.Element {
// --- FilePreview ---
export function FilePreview({ name, content, imageSrc, markdownImageBaseUrl, onClose, taskId, section, filePath, editable }: FilePreviewProps) {
const { t } = useTranslation('files');
const [mode, setMode] = useState<'view' | 'edit'>('view');
const [editContent, setEditContent] = useState(content);
const [saving, setSaving] = useState(false);
@@ -639,14 +643,14 @@ export function FilePreview({ name, content, imageSrc, markdownImageBaseUrl, onC
const html = await buildPrintHtml(currentContent, { title: name, imageBaseUrl: markdownImageBaseUrl });
const win = window.open('', '_blank');
if (!win) {
setError('印刷ウィンドウを開けませんでした。ポップアップブロックを解除してください。');
setError(t('print.popupBlocked'));
return;
}
win.document.open();
win.document.write(html);
win.document.close();
} catch (err) {
setError(err instanceof Error ? err.message : '印刷の準備に失敗しました');
setError(err instanceof Error ? err.message : t('print.prepFailed'));
} finally {
setPrinting(false);
}
@@ -682,14 +686,14 @@ export function FilePreview({ name, content, imageSrc, markdownImageBaseUrl, onC
onClick={() => { setMode('view'); setError(''); }}
className="px-3 h-8 text-xs rounded-md border border-hairline bg-canvas text-slate-700 hover:bg-surface transition-colors"
>
{t('cancel')}
</button>
<button
onClick={handleSave}
disabled={saving}
className="px-3 h-8 text-xs font-semibold rounded-md bg-accent text-accent-fg hover:bg-accent-deep disabled:opacity-50 transition-colors"
>
{saving ? '保存中...' : '保存'}
{saving ? t('saving') : t('save')}
</button>
</div>
</div>
@@ -702,7 +706,12 @@ export function FilePreview({ name, content, imageSrc, markdownImageBaseUrl, onC
return (
<iframe
src={imageSrc}
sandbox="allow-scripts allow-same-origin"
// No allow-same-origin / allow-scripts: workspace HTML is
// untrusted (agent- or web-sourced). The pair would let embedded
// scripts run on our origin and ride the viewer's session. Render
// the markup in an opaque, scriptless sandbox; the raw endpoint
// also sends `Content-Security-Policy: sandbox` as a second layer.
sandbox=""
className="w-full rounded-lg border-0"
style={{ height: '80vh' }}
title={name}
@@ -751,13 +760,13 @@ export function FilePreview({ name, content, imageSrc, markdownImageBaseUrl, onC
<button
onClick={handlePrint}
disabled={printing}
title="ブラウザの印刷ダイアログから PDF として保存または印刷"
title={t('print.tooltip')}
className="inline-flex items-center gap-1 px-2.5 h-7 text-2xs font-medium rounded-md border border-hairline bg-canvas text-slate-700 hover:bg-surface disabled:opacity-50 transition-colors"
>
<svg className="w-3 h-3" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M4 5V2h8v3M4 11H2.5A1.5 1.5 0 0 1 1 9.5v-3A1.5 1.5 0 0 1 2.5 5h11A1.5 1.5 0 0 1 15 6.5v3a1.5 1.5 0 0 1-1.5 1.5H12M4 9.5h8v4.5H4z" />
</svg>
{printing ? '準備中...' : 'PDF / 印刷'}
{printing ? t('print.preparing') : t('print.button')}
</button>
)}
{canEdit && mode === 'view' && (
@@ -768,13 +777,13 @@ export function FilePreview({ name, content, imageSrc, markdownImageBaseUrl, onC
<svg className="w-3 h-3" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M11.5 2.5l2 2L5 13l-2.5.5L3 11l8.5-8.5z" />
</svg>
{t('edit')}
</button>
)}
<button
onClick={onClose}
className="inline-flex items-center justify-center w-7 h-7 rounded-md text-slate-400 hover:text-slate-700 hover:bg-surface-2 transition-colors"
aria-label="プレビューを閉じる"
aria-label={t('close')}
>
<svg className="w-3.5 h-3.5" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round">
<path d="M4 4l8 8M12 4l-8 8" />