Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions scripts/previewWidth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {

const settingsSource = readFileSync(new URL('../src/lib/stores/settings.svelte.ts', import.meta.url), 'utf8');
const viewerSource = readFileSync(new URL('../src/lib/MarkdownViewer.svelte', import.meta.url), 'utf8');
const settingsComponentSource = readFileSync(new URL('../src/lib/components/Settings.svelte', import.meta.url), 'utf8');

test('preview width defaults and clamps persisted numeric values', () => {
assert.equal(DEFAULT_PREVIEW_MAX_WIDTH, 880);
Expand Down Expand Up @@ -47,3 +48,11 @@ test('preview layout derives width and ToC geometry from the same preference', (
assert.match(viewerSource, /--preview-max-width:/);
assert.match(viewerSource, /max-width: var\(--preview-max-width, 880px\)/);
});

test('Settings exposes a bounded preview-width input and reset action', () => {
assert.match(settingsComponentSource, /id="preview-max-width"/);
assert.match(settingsComponentSource, /min=\{MIN_PREVIEW_MAX_WIDTH\}/);
assert.match(settingsComponentSource, /max=\{MAX_PREVIEW_MAX_WIDTH\}/);
assert.match(settingsComponentSource, /bind:value=\{settings\.previewMaxWidth\}/);
assert.match(settingsComponentSource, /settings\.resetPreviewMaxWidth\(\)/);
});
47 changes: 44 additions & 3 deletions src/lib/components/Settings.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
import type { LanguageCode } from '../utils/i18n.js';
import { getEditorToolbarTools } from '../utils/editorToolbar.js';
import { getTitlebarToolbarActions, type TitlebarToolbarPlacement } from '../utils/titlebarToolbar.js';
import {
DEFAULT_PREVIEW_MAX_WIDTH,
MAX_PREVIEW_MAX_WIDTH,
MIN_PREVIEW_MAX_WIDTH,
normalizePreviewMaxWidth,
} from '../utils/previewWidth.js';

let {
show = false,
Expand All @@ -19,6 +25,10 @@

let activeCategory = $state<'editor' | 'preview' | 'appearance' | 'toolbars' | 'files'>('editor');
let highlightMenuOpen = $state(false);

function updatePreviewMaxWidth(value: unknown) {
settings.previewMaxWidth = normalizePreviewMaxWidth(value);
}
const highlightColors = [
{ value: 'default', color: 'var(--color-accent-fg)' },
{ value: 'yellow', color: '#ffd000' },
Expand Down Expand Up @@ -901,12 +911,43 @@
<h2>{t('settings.previewSettings', settings.language)}</h2>
<button
class="reset-text-btn"
class:disabled={settings.previewFont === defaultFonts.previewFont && settings.previewFontSize === 16 && settings.codeFont === defaultFonts.codeFont && settings.codeFontSize === 14}
onclick={() => settings.resetPreviewFont()}>
{t('settings.resetFontSettings', settings.language)}
class:disabled={settings.previewFont === defaultFonts.previewFont && settings.previewFontSize === 16 && settings.codeFont === defaultFonts.codeFont && settings.codeFontSize === 14 && settings.previewMaxWidth === DEFAULT_PREVIEW_MAX_WIDTH}
onclick={() => {
settings.resetPreviewFont();
settings.resetPreviewMaxWidth();
}}>
{t('settings.resetPreviewSettings', settings.language)}
</button>
</div>

<div class="setting-item">
<label for="preview-max-width">{t('settings.previewMaxWidth', settings.language)}</label>
<div class="slider-container">
<div class="number-input-wrapper horizontal">
<button class="spin-btn minus" onclick={() => updatePreviewMaxWidth(settings.previewMaxWidth - 40)} aria-label={t('common.decrease', settings.language)}>
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
><line x1="5" y1="12" x2="19" y2="12"></line></svg>
</button>
<input
type="number"
id="preview-max-width"
min={MIN_PREVIEW_MAX_WIDTH}
max={MAX_PREVIEW_MAX_WIDTH}
step="40"
bind:value={settings.previewMaxWidth}
onchange={() => updatePreviewMaxWidth(settings.previewMaxWidth)}
class="number-input"
style="width: 62px"
/>
<button class="spin-btn plus" onclick={() => updatePreviewMaxWidth(settings.previewMaxWidth + 40)} aria-label={t('common.increase', settings.language)}>
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
</button>
</div>
<span class="slider-value">px · {MIN_PREVIEW_MAX_WIDTH}–{MAX_PREVIEW_MAX_WIDTH} · {t('settings.default', settings.language)} {DEFAULT_PREVIEW_MAX_WIDTH}</span>
</div>
</div>

<div class="setting-item">
<label for="preview-font">{t('settings.font', settings.language)}</label>
<div class="select-wrapper">
Expand Down
4 changes: 4 additions & 0 deletions src/lib/utils/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,10 @@ export const translations: Record<LanguageCode, Translation> = {
confirmBeforeSave: 'Ask for confirmation before saving',
resetEditorSettings: 'Reset editor settings',
resetFontSettings: 'Reset font settings',
resetPreviewSettings: 'Reset preview settings',
font: 'Font',
fontSize: 'Font Size',
previewMaxWidth: 'Preview max width',
wrapColumn: 'Wrap Column',
wordWrap: 'Word Wrap',
lineNumbers: 'Line Numbers',
Expand Down Expand Up @@ -417,8 +419,10 @@ export const translations: Record<LanguageCode, Translation> = {
appearanceSettings: '外观设置',
resetEditorSettings: '重置编辑器设置',
resetFontSettings: '重置字体设置',
resetPreviewSettings: '重置预览设置',
font: '字体',
fontSize: '字体大小',
previewMaxWidth: '预览最大宽度',
wrapColumn: '换行列',
wordWrap: '自动换行',
lineNumbers: '行号',
Expand Down
Loading