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
21 changes: 17 additions & 4 deletions src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@
.mdv-app {
--mdv-writing-font-size: 14px;
--mdv-writing-line-height: 1.55;
--mdv-prose-font-family: var(--font-ui);
--mdv-prose-font-size: 15px;
--mdv-prose-line-height: 1.65;
--mdv-reading-font-size: 16px;
--mdv-reading-content-width: 880px;
--mdv-reading-prose-width: 720px;
display: grid;
grid-template-rows: var(--titlebar-h) var(--breadcrumb-h) 1fr var(--statusbar-h);
height: 100vh;
Expand Down Expand Up @@ -62,22 +66,31 @@
display: flex;
}

html.is-mac .mdv-app.has-hidden-titlebar:not(.is-reading) .mdv-breadcrumb {
padding-left: 132px;
height: 42px;
}

html.is-mac .mdv-app.has-hidden-titlebar:not(.is-reading) {
grid-template-rows: 0 42px 1fr var(--statusbar-h);
}

/* iA Writer-style reading mode: wide max-width, generous breathing room,
subtle warmer tint, and slow calm fade-in */
.mdv-app.is-reading .mdv-shell > .mdv-preview {
flex: 1;
min-width: 0;
padding-left: max(56px, calc((100% - 880px) / 2));
padding-right: max(56px, calc((100% - 880px) / 2));
padding-left: max(56px, calc((100% - var(--mdv-reading-content-width)) / 2));
padding-right: max(56px, calc((100% - var(--mdv-reading-content-width)) / 2));
padding-top: 80px;
padding-bottom: 96px;
background: color-mix(in srgb, var(--bg) 96%, var(--fg) 4%);
animation: mdv-reading-in 360ms var(--easing) both;
}

.mdv-app.is-reading .mdv-shell > .mdv-preview .mdv-prose {
max-width: 720px;
font-size: 16px;
max-width: var(--mdv-reading-prose-width);
font-size: var(--mdv-reading-font-size);
line-height: 1.75;
}

Expand Down
34 changes: 32 additions & 2 deletions src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ import {
getContextBundleStats,
getWhatsNewToastMessage,
isSupportedTextPath,
normalizeProseFontFamily,
normalizeReadingFontSize,
normalizeReadingWidth,
normalizeWritingFontSize,
normalizeWritingLineHeight,
PdfExportError,
Expand All @@ -47,6 +50,9 @@ import {
removeEntry,
STORAGE_KEYS,
useI18n,
type ProseFontFamily,
type ReadingFontSize,
type ReadingWidth,
type WritingDisplay,
type WritingFontSize,
type WritingLineHeight,
Expand Down Expand Up @@ -260,6 +266,18 @@ export function App() {
STORAGE_KEYS.writingLineHeight,
DEFAULT_WRITING_DISPLAY.lineHeight,
);
const [readingFontSize, setReadingFontSize] = usePersistedState<ReadingFontSize>(
STORAGE_KEYS.readingFontSize,
DEFAULT_WRITING_DISPLAY.readingFontSize,
);
const [readingWidth, setReadingWidth] = usePersistedState<ReadingWidth>(
STORAGE_KEYS.readingWidth,
DEFAULT_WRITING_DISPLAY.readingWidth,
);
const [proseFontFamily, setProseFontFamily] = usePersistedState<ProseFontFamily>(
STORAGE_KEYS.proseFontFamily,
DEFAULT_WRITING_DISPLAY.proseFontFamily,
);
const [dragActive, setDragActive] = useState(false);
const [stagedPaths, setStagedPaths] = useState<string[]>([]);
const [stagedTokenLabel, setStagedTokenLabel] = useState("0");
Expand All @@ -269,8 +287,11 @@ export function App() {
() => ({
fontSize: normalizeWritingFontSize(writingFontSize),
lineHeight: normalizeWritingLineHeight(writingLineHeight),
readingFontSize: normalizeReadingFontSize(readingFontSize),
readingWidth: normalizeReadingWidth(readingWidth),
proseFontFamily: normalizeProseFontFamily(proseFontFamily),
}),
[writingFontSize, writingLineHeight],
[writingFontSize, writingLineHeight, readingFontSize, readingWidth, proseFontFamily],
);

const writingDisplayStyle = useMemo(
Expand All @@ -281,7 +302,10 @@ export function App() {
const resetWritingDisplay = useCallback(() => {
setWritingFontSize(DEFAULT_WRITING_DISPLAY.fontSize);
setWritingLineHeight(DEFAULT_WRITING_DISPLAY.lineHeight);
}, [setWritingFontSize, setWritingLineHeight]);
setReadingFontSize(DEFAULT_WRITING_DISPLAY.readingFontSize);
setReadingWidth(DEFAULT_WRITING_DISPLAY.readingWidth);
setProseFontFamily(DEFAULT_WRITING_DISPLAY.proseFontFamily);
}, [setWritingFontSize, setWritingLineHeight, setReadingFontSize, setReadingWidth, setProseFontFamily]);

const handleToggleSidebar = useCallback(() => {
setSidebarOpen((v: boolean) => !v);
Expand Down Expand Up @@ -815,6 +839,9 @@ export function App() {
writingDisplay={writingDisplay}
onWritingFontSizeChange={setWritingFontSize}
onWritingLineHeightChange={setWritingLineHeight}
onReadingFontSizeChange={setReadingFontSize}
onReadingWidthChange={setReadingWidth}
onProseFontFamilyChange={setProseFontFamily}
onResetWritingDisplay={resetWritingDisplay}
/>

Expand All @@ -839,6 +866,9 @@ export function App() {
writingDisplay={writingDisplay}
onWritingFontSizeChange={setWritingFontSize}
onWritingLineHeightChange={setWritingLineHeight}
onReadingFontSizeChange={setReadingFontSize}
onReadingWidthChange={setReadingWidth}
onProseFontFamilyChange={setProseFontFamily}
onResetWritingDisplay={resetWritingDisplay}
/>

Expand Down
138 changes: 79 additions & 59 deletions src/components/chrome/breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import {
startWindowDrag,
useI18n,
type Translate,
type ProseFontFamily,
type ReadingFontSize,
type ReadingWidth,
type WritingDisplay,
type WritingFontSize,
type WritingLineHeight,
Expand Down Expand Up @@ -48,6 +51,9 @@ type BreadcrumbProps = {
writingDisplay: WritingDisplay;
onWritingFontSizeChange: (value: WritingFontSize) => void;
onWritingLineHeightChange: (value: WritingLineHeight) => void;
onReadingFontSizeChange: (value: ReadingFontSize) => void;
onReadingWidthChange: (value: ReadingWidth) => void;
onProseFontFamilyChange: (value: ProseFontFamily) => void;
onResetWritingDisplay: () => void;
};

Expand Down Expand Up @@ -93,6 +99,9 @@ export function Breadcrumb({
writingDisplay,
onWritingFontSizeChange,
onWritingLineHeightChange,
onReadingFontSizeChange,
onReadingWidthChange,
onProseFontFamilyChange,
onResetWritingDisplay,
}: BreadcrumbProps) {
const { t } = useI18n();
Expand All @@ -101,7 +110,11 @@ export function Breadcrumb({
const label = statusLabel(saveStatus, t);

return (
<div className="mdv-breadcrumb" data-tauri-drag-region onMouseDown={startWindowDrag}>
<div
className={`mdv-breadcrumb${titlebarVisible ? "" : " is-titlebar-hidden"}`}
data-tauri-drag-region
onMouseDown={startWindowDrag}
>
<Button
data-tooltip={shortcutLabel(sidebarOpen ? t("breadcrumb.hideSidebarShortcut") : t("breadcrumb.showSidebarShortcut"))}
aria-label={sidebarOpen ? t("breadcrumb.hideSidebar") : t("breadcrumb.showSidebar")}
Expand Down Expand Up @@ -168,65 +181,72 @@ export function Breadcrumb({
/>
}
/>
<Button
data-tooltip={readingMode ? t("title.exitReadingTooltip") : shortcutLabel(t("title.readingModeShortcut"))}
aria-label={readingMode ? t("title.exitReading") : t("title.readingMode")}
aria-pressed={readingMode}
onClick={onToggleReading}
icon={<Icon icon={readingMode ? BookOpen : BookOpen} size={14} strokeWidth={1.5} />}
/>
<ThemeButton
vimOn={vimOn}
onToggleVim={onToggleVim}
writingDisplay={writingDisplay}
onWritingFontSizeChange={onWritingFontSizeChange}
onWritingLineHeightChange={onWritingLineHeightChange}
onResetWritingDisplay={onResetWritingDisplay}
/>
{titlebarVisible ? (
<>
<Button
data-tooltip={readingMode ? t("title.exitReadingTooltip") : shortcutLabel(t("title.readingModeShortcut"))}
aria-label={readingMode ? t("title.exitReading") : t("title.readingMode")}
aria-pressed={readingMode}
onClick={onToggleReading}
icon={<Icon icon={readingMode ? BookOpen : BookOpen} size={14} strokeWidth={1.5} />}
/>
<ThemeButton
vimOn={vimOn}
onToggleVim={onToggleVim}
writingDisplay={writingDisplay}
onWritingFontSizeChange={onWritingFontSizeChange}
onWritingLineHeightChange={onWritingLineHeightChange}
onReadingFontSizeChange={onReadingFontSizeChange}
onReadingWidthChange={onReadingWidthChange}
onProseFontFamilyChange={onProseFontFamilyChange}
onResetWritingDisplay={onResetWritingDisplay}
/>

{/* file actions — border-left matches the status→actions separator */}
<div className="mdv-breadcrumb__file-actions">
{onCopyMarkdown ? (
<button
type="button"
className={`mdv-copybtn${copyPulse ? " is-copied" : ""}`}
data-tooltip={copyPulse ? t("app.copied") : shortcutLabel(t("app.copyMarkdownShortcut"))}
aria-label={copyPulse ? t("app.copied") : t("app.copyMarkdown")}
onClick={onCopyMarkdown}
>
<span className="mdv-copybtn__icon mdv-copybtn__icon--copy" aria-hidden>
<Icon icon={Copy} size={12} strokeWidth={1.5} />
</span>
<span className="mdv-copybtn__icon mdv-copybtn__icon--check" aria-hidden>
<Icon icon={Check} size={13} strokeWidth={2} />
</span>
</button>
) : null}
<Button
data-tooltip={shortcutLabel(t("app.exportPdfShortcut"))}
aria-label={t("app.exportPdf")}
onClick={onExportPdf}
icon={<Icon icon={FileDown} size={13} strokeWidth={1.5} />}
/>
<Button
data-tooltip={shortcutLabel(t("app.newFileShortcut"))}
aria-label={t("app.newFile")}
onClick={onNewFile}
icon={<Icon icon={FilePlus2} size={13} strokeWidth={1.5} />}
/>
<Button
data-tooltip={shortcutLabel(t("app.openFileShortcut"))}
aria-label={t("app.openFile")}
onClick={onOpenFile}
icon={<Icon icon={FileText} size={13} strokeWidth={1.5} />}
/>
<Button
data-tooltip={shortcutLabel(t("app.openFolderShortcut"))}
aria-label={t("app.openFolder")}
onClick={onOpenFolder}
icon={<Icon icon={FolderOpen} size={13} strokeWidth={1.5} />}
/>
</div>
{/* file actions — border-left matches the status→actions separator */}
<div className="mdv-breadcrumb__file-actions">
{onCopyMarkdown ? (
<button
type="button"
className={`mdv-copybtn${copyPulse ? " is-copied" : ""}`}
data-tooltip={copyPulse ? t("app.copied") : shortcutLabel(t("app.copyMarkdownShortcut"))}
aria-label={copyPulse ? t("app.copied") : t("app.copyMarkdown")}
onClick={onCopyMarkdown}
>
<span className="mdv-copybtn__icon mdv-copybtn__icon--copy" aria-hidden>
<Icon icon={Copy} size={12} strokeWidth={1.5} />
</span>
<span className="mdv-copybtn__icon mdv-copybtn__icon--check" aria-hidden>
<Icon icon={Check} size={13} strokeWidth={2} />
</span>
</button>
) : null}
<Button
data-tooltip={shortcutLabel(t("app.exportPdfShortcut"))}
aria-label={t("app.exportPdf")}
onClick={onExportPdf}
icon={<Icon icon={FileDown} size={13} strokeWidth={1.5} />}
/>
<Button
data-tooltip={shortcutLabel(t("app.newFileShortcut"))}
aria-label={t("app.newFile")}
onClick={onNewFile}
icon={<Icon icon={FilePlus2} size={13} strokeWidth={1.5} />}
/>
<Button
data-tooltip={shortcutLabel(t("app.openFileShortcut"))}
aria-label={t("app.openFile")}
onClick={onOpenFile}
icon={<Icon icon={FileText} size={13} strokeWidth={1.5} />}
/>
<Button
data-tooltip={shortcutLabel(t("app.openFolderShortcut"))}
aria-label={t("app.openFolder")}
onClick={onOpenFolder}
icon={<Icon icon={FolderOpen} size={13} strokeWidth={1.5} />}
/>
</div>
</>
) : null}
</div>
</div>
);
Expand Down
Loading
Loading