feat: add profile language preferences and refine toast, dropdown and history UI
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
import { EMOJI_SHORTCODES } from "@rustpad/emoji-data";
|
||||
import { t } from "@rustpad/i18n";
|
||||
import { parseImageAlias } from "@rustpad/image-alias";
|
||||
|
||||
function escapeHtml(value) {
|
||||
@@ -224,7 +225,7 @@ function renderStandaloneMedia(line, sourceLine) {
|
||||
const label = String(videoAlias[2] || filename).trim() || filename;
|
||||
const playbackUrl = safeAttachmentPlaybackUrl(file);
|
||||
const downloadUrl = safeAttachmentDownloadUrl(file);
|
||||
return `<div class="rustpad-media preview-source-line" data-source-line="${sourceLine}" contenteditable="false"><video class="rustpad-media__player" data-rustpad-player data-player-kind="video" controls playsinline preload="metadata" aria-label="${escapeHtml(label)}"><source src="${playbackUrl}" type="${escapeHtml(file.mimeType)}"></video><p class="rustpad-media__fallback" hidden>Playback is unavailable. <a href="${downloadUrl}" download="${escapeHtml(filename)}">Download ${escapeHtml(label)}</a>.</p></div>`;
|
||||
return `<div class="rustpad-media preview-source-line" data-source-line="${sourceLine}" contenteditable="false"><video class="rustpad-media__player" data-rustpad-player data-player-kind="video" controls playsinline preload="metadata" aria-label="${escapeHtml(label)}"><source src="${playbackUrl}" type="${escapeHtml(file.mimeType)}"></video><p class="rustpad-media__fallback" hidden>${escapeHtml(t("markdown.playbackUnavailable", {}, "Playback is unavailable."))} <a href="${downloadUrl}" download="${escapeHtml(filename)}">${escapeHtml(t("markdown.download", { label }, `Download ${label}`))}</a>.</p></div>`;
|
||||
}
|
||||
|
||||
const trimmed = String(line).trim();
|
||||
@@ -232,8 +233,8 @@ function renderStandaloneMedia(line, sourceLine) {
|
||||
const candidate = markdownLink ? markdownLink[2] : trimmed;
|
||||
const youtube = youtubeVideo(candidate);
|
||||
if (!youtube) return null;
|
||||
const title = markdownLink?.[1]?.trim() || "YouTube video";
|
||||
return `<div class="rustpad-media preview-source-line" data-source-line="${sourceLine}" contenteditable="false"><div class="rustpad-media__player" data-rustpad-player data-player-kind="youtube" data-video-id="${escapeHtml(youtube.id)}" data-player-title="${escapeHtml(title)}"><p class="rustpad-media__fallback"><a href="${safeUrl(youtube.url)}" target="_blank" rel="noopener noreferrer">Open ${escapeHtml(title)}</a></p></div></div>`;
|
||||
const title = markdownLink?.[1]?.trim() || t("markdown.youtubeVideo", {}, "YouTube video");
|
||||
return `<div class="rustpad-media preview-source-line" data-source-line="${sourceLine}" contenteditable="false"><div class="rustpad-media__player" data-rustpad-player data-player-kind="youtube" data-video-id="${escapeHtml(youtube.id)}" data-player-title="${escapeHtml(title)}"><p class="rustpad-media__fallback"><a href="${safeUrl(youtube.url)}" target="_blank" rel="noopener noreferrer">${escapeHtml(t("markdown.open", { title }, `Open ${title}`))}</a></p></div></div>`;
|
||||
}
|
||||
|
||||
function listLine(line) {
|
||||
@@ -462,11 +463,11 @@ export function renderMarkdown(source, lineOffset = 0) {
|
||||
while (end < lines.length && !/^<\/details>\s*$/i.test(lines[end].trim())) end++;
|
||||
if (end < lines.length) {
|
||||
let bodyStart = index + 1;
|
||||
let summary = "Details";
|
||||
let summary = t("markdown.details", {}, "Details");
|
||||
while (bodyStart < end && !lines[bodyStart].trim()) bodyStart++;
|
||||
if (bodyStart < end) {
|
||||
const summaryMatch = lines[bodyStart].trim().match(/^<summary>([\s\S]*?)<\/summary>$/i);
|
||||
if (summaryMatch) { summary = summaryMatch[1].trim() || "Details"; bodyStart++; }
|
||||
if (summaryMatch) { summary = summaryMatch[1].trim() || t("markdown.details", {}, "Details"); bodyStart++; }
|
||||
}
|
||||
while (bodyStart < end && !lines[bodyStart].trim()) bodyStart++;
|
||||
const body = lines.slice(bodyStart, end).join("\n");
|
||||
@@ -480,7 +481,7 @@ export function renderMarkdown(source, lineOffset = 0) {
|
||||
closeList();
|
||||
const tocHeadings = headings.filter(item => item.index > index);
|
||||
if (tocHeadings.length) {
|
||||
html += `<nav class="markdown-toc preview-source-line" data-source-line="${index + lineOffset + 1}" aria-label="Table of contents">${renderTableOfContentsList(tableOfContentsTree(tocHeadings))}</nav>`;
|
||||
html += `<nav class="markdown-toc preview-source-line" data-source-line="${index + lineOffset + 1}" aria-label="${escapeHtml(t("markdown.toc", {}, "Table of contents"))}">${renderTableOfContentsList(tableOfContentsTree(tocHeadings))}</nav>`;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user