Skip to content

Commit 3b1b30f

Browse files
committed
frontend/latex/output: "stats" label, CSS tweaks, build → download, print
1 parent 086eaf7 commit 3b1b30f

30 files changed

+295
-181
lines changed

src/.claude/commands/frontend.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# frontend
2+
3+
Build the frontend code for development, after changing files in the frontend package. This is done by compiling the static package in dev mode.
4+
5+
Run this command:
6+
7+
```bash
8+
cd packages/static && pnpm build-dev
9+
```

src/.claude/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"Bash(pnpm build:*)",
3030
"Bash(pnpm exec tsc:*)",
3131
"Bash(pnpm i18n:*)",
32+
"Bash(pnpm i18n:*:*)",
3233
"Bash(pnpm info:*)",
3334
"Bash(pnpm list:*)",
3435
"Bash(pnpm remove:*)",

src/packages/frontend/frame-editors/_style.sass

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,31 +32,35 @@
3232
display: flex
3333
flex-direction: column
3434

35-
// latex editor, output panel - full height tabs with outline
35+
// latex editor, output panel - full height tabs
36+
// This ensures the new output panel tabs (Build, Errors, Stats) take full height
37+
// and their content (like build logs, error lists) fills the available space
3638
.cocalc-latex-output-tabs
37-
height: 100% !important
38-
display: flex !important
39-
flex-direction: column !important
39+
// Make the entire tabs container take full height and use flex layout
40+
// This is needed because the output panel should fill the available editor space
41+
height: 100%
42+
display: flex
43+
flex-direction: column
4044

41-
// Ensure content fills remaining space
45+
// The content holder contains all tab panes and should expand to fill remaining space
46+
// flex: 1 makes it take all space not used by the tab headers
4247
.ant-tabs-content-holder
43-
flex: 1 !important
44-
display: flex !important
45-
min-height: 0 !important
46-
border-radius: 0 !important
48+
flex: 1
49+
display: flex
4750

51+
// The content wrapper needs to pass through the full height to individual tab panes
4852
.ant-tabs-content
49-
height: 100% !important
50-
display: flex !important
51-
flex-direction: column !important
52-
border: none !important
53+
height: 100%
54+
display: flex
55+
flex-direction: column
5356

57+
// Individual tab panes (Build content, Errors content, etc.) need full height
5458
.ant-tabs-tabpane
55-
height: 100% !important
56-
flex-direction: column !important
57-
min-height: 0 !important
58-
padding: 0 !important
59+
height: 100%
5960

60-
// Only apply flex display to active tab pane
61+
// CRITICAL: Only make the active tab pane use flex layout
62+
// Hidden tab panes (ant-tabs-tabpane-hidden) must remain hidden
63+
// Without this selector, all tab panes would be visible at once
6164
&:not(.ant-tabs-tabpane-hidden)
62-
display: flex !important
65+
display: flex
66+
flex-direction: column

src/packages/frontend/frame-editors/frame-tree/commands/generic-commands.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* License: MS-RSL – see LICENSE.md for details
44
*/
55

6+
// cSpell:ignore demaximize subframe rescan
7+
68
import { Input } from "antd";
79
import { debounce } from "lodash";
810
import { useEffect, useRef } from "react";
@@ -960,6 +962,7 @@ addCommands({
960962
},
961963
download_pdf: {
962964
group: "export",
965+
// ATTN: this must be an IntlMessage
963966
label: defineMessage({
964967
id: "menu.generic.download_pdf.label",
965968
defaultMessage: "Download PDF",
@@ -1010,6 +1013,7 @@ addCommands({
10101013
defaultMessage:
10111014
"Show a printable version of this document in a popup window.",
10121015
}),
1016+
// ATTN: this must be an IntlMessage
10131017
label: labels.print,
10141018
},
10151019
new: {

src/packages/frontend/frame-editors/latex-editor/actions.ts

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,13 +1411,7 @@ export class Actions extends BaseActions<LatexEditorState> {
14111411
if (this.knitr) {
14121412
// #v0 will not support multi-file knitr.
14131413
this.programmatically_goto_line(line, true, true);
1414-
// Clear auto sync flag after cursor has moved (backward sync completion)
1415-
// Only for automatic sync - manual sync doesn't set the flag
1416-
if (this.is_auto_sync_in_progress()) {
1417-
setTimeout(() => {
1418-
this.set_auto_sync_in_progress(false);
1419-
}, 200); // Give time for cursor to actually move
1420-
}
1414+
this.clear_auto_sync_after_cursor_move();
14211415
return;
14221416
}
14231417
// Focus a cm frame so that we split a code editor below.
@@ -1431,7 +1425,11 @@ export class Actions extends BaseActions<LatexEditorState> {
14311425
}
14321426
(actions as BaseActions).programmatically_goto_line(line, true, true, id);
14331427

1434-
// Clear auto sync flag after cursor has moved (backward sync completion)
1428+
this.clear_auto_sync_after_cursor_move();
1429+
}
1430+
1431+
// Clear auto sync flag after cursor has moved (backward sync completion)
1432+
private clear_auto_sync_after_cursor_move(): void {
14351433
// Only for automatic sync - manual sync doesn't set the flag
14361434
if (this.is_auto_sync_in_progress()) {
14371435
setTimeout(() => {
@@ -1491,24 +1489,6 @@ export class Actions extends BaseActions<LatexEditorState> {
14911489
}
14921490
}
14931491

1494-
// Public method to trigger auto-sync when cursor position changes (for backwards compatibility)
1495-
public handle_cursor_activity(
1496-
line: number,
1497-
column: number,
1498-
filename?: string,
1499-
): void {
1500-
if (!this.is_auto_sync_enabled()) return;
1501-
1502-
// Prevent duplicate sync operations
1503-
if (this.is_auto_sync_in_progress()) return;
1504-
1505-
// Use current file if filename not provided
1506-
const file = filename || this.path;
1507-
1508-
// Trigger forward sync (source → PDF)
1509-
this.handle_cursor_sync_to_pdf(line + 1, column, file); // line is 0-based, synctex expects 1-based
1510-
}
1511-
15121492
_get_most_recent_pdfjs(): string | undefined {
15131493
return this._get_most_recent_active_frame_id(
15141494
(node) => node.get("type").indexOf("pdfjs") != -1,
@@ -1817,7 +1797,7 @@ export class Actions extends BaseActions<LatexEditorState> {
18171797
super.print(id);
18181798
return;
18191799
}
1820-
if (type.indexOf("pdf") != -1) {
1800+
if (type.indexOf("pdf") != -1 || type === "output") {
18211801
this.print_pdf();
18221802
return;
18231803
}

src/packages/frontend/frame-editors/latex-editor/editor.ts

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,41 @@ const cm: EditorDescription = {
9292
gutters: ["Codemirror-latex-errors"],
9393
} as const;
9494

95+
const output: EditorDescription = {
96+
type: "latex-output",
97+
short: "Output",
98+
name: "Output",
99+
icon: "file-alt",
100+
component: Output,
101+
commands: set([
102+
"build",
103+
"build_on_save",
104+
"force_build",
105+
"stop_build",
106+
"print",
107+
"clean",
108+
"stop_build",
109+
"download",
110+
"download_pdf",
111+
"decrease_font_size",
112+
"increase_font_size",
113+
]),
114+
buttons: set([
115+
"build",
116+
"force_build",
117+
"clean",
118+
"stop_build",
119+
"sync",
120+
"decrease_font_size",
121+
"increase_font_size",
122+
"zoom_page_width",
123+
"zoom_page_height",
124+
"set_zoom",
125+
"print",
126+
"download_pdf",
127+
]),
128+
} as const;
129+
95130
const pdfjs_canvas: EditorDescription = {
96131
type: "preview-pdf-canvas",
97132
short: editor.pdfjs_canvas_title_short,
@@ -179,44 +214,12 @@ const pdf_embed: EditorDescription = {
179214
component: PDFEmbed,
180215
} as const;
181216

182-
const output: EditorDescription = {
183-
type: "latex-output",
184-
short: "Output",
185-
name: "Output",
186-
icon: "file-alt",
187-
component: Output,
188-
commands: {
189-
build: true,
190-
force_build: true,
191-
clean: true,
192-
stop_build: true,
193-
download: false,
194-
download_pdf: true,
195-
decrease_font_size: true,
196-
increase_font_size: true,
197-
},
198-
buttons: set([
199-
"build",
200-
"force_build",
201-
"clean",
202-
"stop_build",
203-
"sync",
204-
"decrease_font_size",
205-
"increase_font_size",
206-
"zoom_page_width",
207-
"zoom_page_height",
208-
"set_zoom",
209-
"print",
210-
"download_pdf",
211-
]),
212-
} as const;
213-
214217
const EDITOR_SPEC = {
215218
cm,
219+
output,
216220
pdfjs_canvas,
217221
error,
218222
build,
219-
output,
220223
latex_table_of_contents,
221224
word_count,
222225
terminal,

src/packages/frontend/frame-editors/latex-editor/errors-and-warnings.tsx

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,12 @@ interface ItemProps {
9393
actions: Actions;
9494
item: TypedMap<item>;
9595
group: string;
96+
font_size: number;
9697
}
9798

9899
// memo has an update function, see bottom
99100
const Item: React.FC<ItemProps> = React.memo(
100-
({ actions, item, group }: ItemProps) => {
101+
({ actions, item, group, font_size }: ItemProps) => {
101102
function edit_source(e: React.SyntheticEvent<any>): void {
102103
e.stopPropagation();
103104
if (!item.get("file")) return; // not known
@@ -168,7 +169,16 @@ const Item: React.FC<ItemProps> = React.memo(
168169
{renderGetHelp()}
169170
{render_location()}
170171
{item.get("message") && <div>{item.get("message")}</div>}
171-
{item.get("content") && <pre>{item.get("content")}</pre>}
172+
{item.get("content") && (
173+
<pre
174+
style={{
175+
fontSize: font_size * 0.85, // slightly smaller than main font size
176+
borderRadius: 0, // remove border radius
177+
}}
178+
>
179+
{item.get("content")}
180+
</pre>
181+
)}
172182
</div>
173183
);
174184
},
@@ -225,7 +235,7 @@ export const ErrorsAndWarnings: React.FC<ErrorsAndWarningsProps> = React.memo(
225235
<Loading
226236
text={status}
227237
style={{
228-
fontSize: "10pt",
238+
fontSize: props.font_size,
229239
color: COLORS.GRAY,
230240
}}
231241
/>
@@ -235,7 +245,15 @@ export const ErrorsAndWarnings: React.FC<ErrorsAndWarningsProps> = React.memo(
235245
}
236246

237247
function render_item(item, key, group): Rendered {
238-
return <Item key={key} item={item} actions={actions} group={group} />;
248+
return (
249+
<Item
250+
key={key}
251+
item={item}
252+
actions={actions}
253+
group={group}
254+
font_size={props.font_size}
255+
/>
256+
);
239257
}
240258

241259
function render_group_content(content, group): Rendered {
@@ -325,7 +343,7 @@ export const ErrorsAndWarnings: React.FC<ErrorsAndWarningsProps> = React.memo(
325343
style={{
326344
overflowY: "scroll",
327345
padding: "5px 15px",
328-
fontSize: "10pt",
346+
fontSize: props.font_size,
329347
}}
330348
>
331349
{includeError && (

0 commit comments

Comments
 (0)