tsondb 0.7.4 → 0.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -84,7 +84,7 @@ switch (passedArguments.command.name) {
84
84
  break;
85
85
  case "serve":
86
86
  debug(`running command: serve`);
87
- await serve(config.schema, config.dataRootPath, config.defaultLocales, config.homeLayoutSections, config.serverOptions);
87
+ await serve(config.schema, config.dataRootPath, config.defaultLocales, config.homeLayoutSections, config.serverOptions, config.customStylesheetPath);
88
88
  break;
89
89
  case "validate":
90
90
  debug(`running command: validate`);
@@ -8,6 +8,7 @@ export type Config = {
8
8
  defaultLocales: string[];
9
9
  dataRootPath: string;
10
10
  homeLayoutSections?: HomeLayoutSection[];
11
+ customStylesheetPath?: string;
11
12
  };
12
13
  export type ServerOptions = {
13
14
  port: number;
@@ -9,7 +9,7 @@ type ValidationOptions = {
9
9
  };
10
10
  export declare const validate: (schema: Schema, dataRootPath: string, options?: Partial<ValidationOptions>) => Promise<void>;
11
11
  export declare const generateAndValidate: (schema: Schema, outputs: Output[], dataRootPath: string, validationOptions?: Partial<ValidationOptions>) => Promise<void>;
12
- export declare const serve: (schema: Schema, dataRootPath: string, defaultLocales: string[], homeLayoutSections?: HomeLayoutSection[], serverOptions?: Partial<ServerOptions>) => Promise<void>;
12
+ export declare const serve: (schema: Schema, dataRootPath: string, defaultLocales: string[], homeLayoutSections?: HomeLayoutSection[], serverOptions?: Partial<ServerOptions>, customStylesheetPath?: string) => Promise<void>;
13
13
  export declare const generateValidateAndServe: (schema: Schema, outputs: Output[], dataRootPath: string, defaultLocales: string[], homeLayoutSections?: HomeLayoutSection[], serverOptions?: Partial<ServerOptions>, validationOptions?: Partial<ValidationOptions>) => Promise<void>;
14
14
  export declare const format: (schema: Schema, dataRootPath: string) => Promise<void>;
15
15
  export {};
@@ -57,7 +57,7 @@ export const generateAndValidate = async (schema, outputs, dataRootPath, validat
57
57
  const instancesByEntityName = await getInstancesByEntityName(dataRootPath, entities);
58
58
  _validate(dataRootPath, entities, instancesByEntityName, validationOptions);
59
59
  };
60
- export const serve = async (schema, dataRootPath, defaultLocales, homeLayoutSections, serverOptions) => {
60
+ export const serve = async (schema, dataRootPath, defaultLocales, homeLayoutSections, serverOptions, customStylesheetPath) => {
61
61
  if (defaultLocales.length === 0) {
62
62
  throw new Error("At least one default locale must be specified to start the server.");
63
63
  }
@@ -66,7 +66,7 @@ export const serve = async (schema, dataRootPath, defaultLocales, homeLayoutSect
66
66
  debug("prepared folders");
67
67
  const instancesByEntityName = await getInstancesByEntityName(dataRootPath, entities);
68
68
  debug("loaded instances");
69
- await createServer(schema, dataRootPath, instancesByEntityName, defaultLocales, homeLayoutSections, serverOptions);
69
+ await createServer(schema, dataRootPath, instancesByEntityName, defaultLocales, homeLayoutSections, serverOptions, customStylesheetPath);
70
70
  };
71
71
  export const generateValidateAndServe = async (schema, outputs, dataRootPath, defaultLocales, homeLayoutSections, serverOptions, validationOptions) => {
72
72
  await generateOutputs(schema, outputs);
@@ -35,4 +35,4 @@ declare global {
35
35
  }
36
36
  }
37
37
  }
38
- export declare const createServer: (schema: Schema, dataRootPath: string, instancesByEntityName: InstancesByEntityName, defaultLocales: string[], homeLayoutSections?: HomeLayoutSection[], options?: Partial<ServerOptions>) => Promise<void>;
38
+ export declare const createServer: (schema: Schema, dataRootPath: string, instancesByEntityName: InstancesByEntityName, defaultLocales: string[], homeLayoutSections?: HomeLayoutSection[], options?: Partial<ServerOptions>, customStylesheetPath?: string) => Promise<void>;
@@ -16,7 +16,7 @@ const staticNodeModule = (moduleName) => {
16
16
  }
17
17
  return express.static(dirname(pathToPackageJson));
18
18
  };
19
- export const createServer = async (schema, dataRootPath, instancesByEntityName, defaultLocales, homeLayoutSections, options) => {
19
+ export const createServer = async (schema, dataRootPath, instancesByEntityName, defaultLocales, homeLayoutSections, options, customStylesheetPath) => {
20
20
  const { port } = { ...defaultOptions, ...options };
21
21
  const app = express();
22
22
  app.use(express.static(join(import.meta.dirname, "../../../../public")));
@@ -44,6 +44,15 @@ export const createServer = async (schema, dataRootPath, instancesByEntityName,
44
44
  "preact-iso": "/js/node_modules/preact-iso/src/index.js",
45
45
  },
46
46
  }, null, 2);
47
+ const customStylesheetLinkHeader = customStylesheetPath
48
+ ? `
49
+ <link rel="stylesheet" href="/css/custom.css">`
50
+ : "";
51
+ if (customStylesheetPath) {
52
+ app.use("/css/custom.css", (_req, res) => {
53
+ res.sendFile(customStylesheetPath);
54
+ });
55
+ }
47
56
  app.get(/^\/.*/, (_req, res) => {
48
57
  res.send(`<!DOCTYPE html>
49
58
  <html lang="en">
@@ -51,7 +60,7 @@ export const createServer = async (schema, dataRootPath, instancesByEntityName,
51
60
  <meta charset="UTF-8">
52
61
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
53
62
  <title>TSONDB</title>
54
- <link rel="stylesheet" href="/css/styles.css">
63
+ <link rel="stylesheet" href="/css/styles.css">${customStylesheetLinkHeader}
55
64
  <script type="importmap">${importMap}</script>
56
65
  </head>
57
66
  <body>
@@ -20,6 +20,10 @@ export type InlineMarkdownNode = {
20
20
  export type BlockMarkdownNode = {
21
21
  kind: "paragraph";
22
22
  content: InlineMarkdownNode[];
23
+ } | {
24
+ kind: "heading";
25
+ level: number;
26
+ content: InlineMarkdownNode[];
23
27
  } | {
24
28
  kind: "list";
25
29
  ordered: boolean;
@@ -38,6 +42,9 @@ export type BlockSyntaxMarkdownNode = InlineMarkdownNode | {
38
42
  } | {
39
43
  kind: "tablemarker";
40
44
  content: string;
45
+ } | {
46
+ kind: "headingmarker";
47
+ content: string;
41
48
  };
42
49
  export declare const parseBlockMarkdown: (text: string) => BlockMarkdownNode[];
43
50
  export declare const parseBlockMarkdownForSyntaxHighlighting: (text: string) => BlockSyntaxMarkdownNode[];
@@ -234,6 +234,19 @@ const paragraphRule = {
234
234
  ...nodesForTrailingWhitespace(result[2]),
235
235
  ],
236
236
  };
237
+ const headingRule = {
238
+ pattern: /^(#+)( +)([^\s\n][^\n]*?)(\n{2,}|\s*$)/,
239
+ map: result => ({
240
+ kind: "heading",
241
+ level: result[1]?.length ?? 1,
242
+ content: parseInlineMarkdown(result[3] ?? "", false),
243
+ }),
244
+ mapHighlighting: result => [
245
+ { kind: "headingmarker", content: (result[1] ?? "") + (result[2] ?? "") },
246
+ ...parseInlineMarkdown(result[3] ?? "", true),
247
+ ...nodesForTrailingWhitespace(result[4]),
248
+ ],
249
+ };
237
250
  const removeSurroundingPipes = (text) => text.replace(/^\|/, "").replace(/\|$/, "");
238
251
  const tableMarker = (text) => ({
239
252
  kind: "tablemarker",
@@ -273,7 +286,7 @@ const tableRule = {
273
286
  ...nodesForTrailingWhitespace(result[6]),
274
287
  ],
275
288
  };
276
- const blockRules = [tableRule, listRule, paragraphRule];
289
+ const blockRules = [headingRule, tableRule, listRule, paragraphRule];
277
290
  const parseActiveBlockRule = (rule, res) => [
278
291
  rule.map(res),
279
292
  ];
@@ -1,9 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
2
  import { useLocation } from "preact-iso";
3
- import { useCallback, useEffect, useState } from "preact/hooks";
3
+ import { useCallback, useContext, useEffect, useState } from "preact/hooks";
4
4
  import { getGitStatusForDisplay, getLabelForGitStatus, isChangedInIndex, isChangedInWorkingDir, } from "../../shared/utils/git.js";
5
5
  import { getAllEntities } from "../api/declarations.js";
6
6
  import { commitStagedFiles, createBranch, getBranches, getStatus, pullCommits, pushCommits, stageAllFiles, stageFileOfEntity, switchBranch, unstageAllFiles, unstageFileOfEntity, } from "../api/git.js";
7
+ import { GitContext } from "../context/git.js";
7
8
  import { useSetting } from "../hooks/useSettings.js";
8
9
  const filterFilesForDisplay = (predicate, entities, data) => Object.entries(data.instances)
9
10
  .map(([entityName, instances]) => [
@@ -23,7 +24,7 @@ const GitFileList = ({ filesByEntity, onFile, isIndex = false }) => filesByEntit
23
24
  }) })] }, entityName))) }));
24
25
  export const Git = () => {
25
26
  const [locales] = useSetting("displayedLocales");
26
- const [isOpen, setIsOpen] = useState(false);
27
+ const [isOpen] = useContext(GitContext);
27
28
  const [commitsAhead, setCommitsAhead] = useState(0);
28
29
  const [commitsBehind, setCommitsBehind] = useState(0);
29
30
  const [commitMessage, setCommitMessage] = useState("");
@@ -157,9 +158,7 @@ export const Git = () => {
157
158
  }
158
159
  });
159
160
  };
160
- return (_jsxs("aside", { class: "git", children: [_jsx("h2", { class: "h1-faded", children: "Version Control" }), _jsx("button", { onClick: () => {
161
- setIsOpen(b => !b);
162
- }, children: "File changes" }), _jsxs("div", { className: `git-overlay ${isOpen ? "git-overlay--open" : ""}`, children: [_jsxs("div", { class: "sync", children: [_jsxs("button", { onClick: push, children: ["Push", commitsAhead > 0 ? ` (${commitsAhead.toString()})` : ""] }), _jsxs("button", { onClick: pull, children: ["Pull", commitsBehind > 0 ? ` (${commitsBehind.toString()})` : ""] })] }), _jsxs("div", { className: "branch", children: [_jsx("div", { className: "select-wrapper", children: _jsx("select", { value: currentBranch, onInput: onSwitchBranch, children: allBranches.map(branch => (_jsx("option", { value: branch, children: branch }, branch))) }) }), _jsx("button", { onClick: onCreateBranch, children: "New branch" })] }), _jsxs("div", { class: "commit", children: [_jsx("input", { type: "text", value: commitMessage, onInput: event => {
161
+ return (_jsxs("aside", { class: "git", children: [_jsx("h2", { class: "h1-faded", children: "Version Control" }), _jsxs("div", { className: `git-overlay ${isOpen ? "git-overlay--open" : ""}`, children: [_jsxs("div", { class: "sync", children: [_jsxs("button", { onClick: push, children: ["Push", commitsAhead > 0 ? ` (${commitsAhead.toString()})` : ""] }), _jsxs("button", { onClick: pull, children: ["Pull", commitsBehind > 0 ? ` (${commitsBehind.toString()})` : ""] })] }), _jsxs("div", { className: "branch", children: [_jsx("div", { className: "select-wrapper", children: _jsx("select", { value: currentBranch, onInput: onSwitchBranch, children: allBranches.map(branch => (_jsx("option", { value: branch, children: branch }, branch))) }) }), _jsx("button", { onClick: onCreateBranch, children: "New branch" })] }), _jsxs("div", { class: "commit", children: [_jsx("input", { type: "text", value: commitMessage, onInput: event => {
163
162
  setCommitMessage(event.currentTarget.value);
164
163
  }, placeholder: "added X to instance Y, \u2026" }), _jsx("button", { onClick: commit, disabled: commitMessage.length === 0 || indexFiles.length === 0, children: "Commit" })] }), _jsxs("div", { className: "git-section-title", children: [_jsx("h3", { children: "Files to be committed" }), _jsx("button", { onClick: unstageAll, children: "Unstage all" })] }), _jsx(GitFileList, { filesByEntity: indexFiles, isIndex: true, onFile: unstage }), _jsxs("div", { className: "git-section-title", children: [_jsx("h3", { children: "Working tree changes" }), _jsx("button", { onClick: stageAll, children: "Stage all" })] }), _jsx(GitFileList, { filesByEntity: workingTreeFiles, onFile: stage })] })] }));
165
164
  };
@@ -1,5 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
2
+ import { useContext } from "preact/hooks";
3
+ import { GitContext } from "../context/git.js";
2
4
  import { Settings } from "./Settings.js";
3
5
  export const Layout = ({ breadcrumbs, children }) => {
4
- return (_jsxs(_Fragment, { children: [_jsxs("header", { children: [_jsx("nav", { children: _jsx("ol", { children: breadcrumbs.map(({ url, label }) => (_jsx("li", { children: _jsx("a", { href: url, children: label }) }, url))) }) }), _jsx(Settings, {})] }), _jsx("main", { children: children })] }));
6
+ const [_, setIsGitOpen] = useContext(GitContext);
7
+ return (_jsxs(_Fragment, { children: [_jsxs("header", { children: [_jsx("nav", { children: _jsx("ol", { children: breadcrumbs.map(({ url, label }) => (_jsx("li", { children: _jsx("a", { href: url, children: label }) }, url))) }) }), _jsxs("div", { class: "nav-buttons", children: [_jsx("button", { class: "git-toggle", onClick: () => {
8
+ setIsGitOpen(b => !b);
9
+ }, children: "File changes" }), _jsx(Settings, {})] })] }), _jsx("main", { children: children })] }));
5
10
  };
@@ -12,7 +12,7 @@ export const StringTypeInput = ({ type, value, disabled, onChange }) => {
12
12
  const errors = validateStringConstraints(type, value);
13
13
  return (_jsx("div", { class: "field field--string", children: isMarkdown ? (_jsxs(_Fragment, { children: [_jsxs("div", { class: "editor editor--markdown", children: [_jsxs("div", { class: "textarea-grow-wrap", children: [_jsx("textarea", { value: value, minLength: minLength, maxLength: maxLength, onInput: event => {
14
14
  onChange(event.currentTarget.value);
15
- }, "aria-invalid": errors.length > 0, disabled: disabled }), _jsxs("p", { class: "help", children: ["This textarea supports", " ", _jsx("a", { href: "https://www.markdownguide.org/getting-started/", target: "_blank", rel: "noreferrer", children: "Markdown" }), "."] }), _jsx(MarkdownHighlighting, { class: "textarea-grow-wrap__mirror editor-highlighting", string: value })] }), _jsx(ValidationErrors, { disabled: disabled, errors: errors })] }), _jsx("div", { class: "preview", children: _jsx(Markdown, { string: value }) })] })) : (_jsxs("div", { class: "editor", children: [_jsx("input", { type: "text", value: value, minLength: minLength, maxLength: maxLength, pattern: pattern === undefined
15
+ }, "aria-invalid": errors.length > 0, disabled: disabled }), _jsxs("p", { class: "help", children: ["This textarea supports", " ", _jsx("a", { href: "https://www.markdownguide.org/getting-started/", target: "_blank", rel: "noreferrer", children: "Markdown" }), "."] }), _jsx(MarkdownHighlighting, { class: "textarea-grow-wrap__mirror editor-highlighting", string: value })] }), _jsx(ValidationErrors, { disabled: disabled, errors: errors })] }), _jsx("div", { class: "preview", children: _jsx(Markdown, { string: value, outerHeadingLevel: 2 }) })] })) : (_jsxs("div", { class: "editor", children: [_jsx("input", { type: "text", value: value, minLength: minLength, maxLength: maxLength, pattern: pattern === undefined
16
16
  ? undefined
17
17
  : pattern.startsWith("^(?:") && pattern.endsWith(")$")
18
18
  ? pattern.slice(4, -2)
@@ -0,0 +1,3 @@
1
+ import type { SetStateAction } from "preact/compat";
2
+ import type { Dispatch } from "preact/hooks";
3
+ export declare const GitContext: import("preact").Context<[isOpen: boolean, setIsOpen: Dispatch<SetStateAction<boolean>>]>;
@@ -0,0 +1,2 @@
1
+ import { createContext } from "preact";
2
+ export const GitContext = createContext([false, () => { }]);
@@ -1,12 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
2
  import { render } from "preact";
3
3
  import { LocationProvider, Route, Router, useLocation } from "preact-iso";
4
- import { useEffect } from "preact/hooks";
4
+ import { useEffect, useState } from "preact/hooks";
5
5
  import { getAllEntities } from "./api/declarations.js";
6
6
  import { getWebConfig } from "./api/index.js";
7
7
  import { Git } from "./components/Git.js";
8
8
  import { ConfigContext } from "./context/config.js";
9
9
  import { EntitiesContext } from "./context/entities.js";
10
+ import { GitContext } from "./context/git.js";
10
11
  import { SettingsContext } from "./context/settings.js";
11
12
  import { useMappedAPIResource } from "./hooks/useMappedAPIResource.js";
12
13
  import { useSettings } from "./hooks/useSettings.js";
@@ -20,6 +21,7 @@ const mapEntities = (data) => data.declarations
20
21
  .sort((a, b) => a.declaration.name.localeCompare(b.declaration.name));
21
22
  const App = ({ config }) => {
22
23
  const settingsContext = useSettings(config);
24
+ const [isGitOpen, setIsGitOpen] = useState(false);
23
25
  const [entities, reloadEntities] = useMappedAPIResource(getAllEntities, mapEntities, settingsContext.settings.displayedLocales);
24
26
  const location = useLocation();
25
27
  useEffect(() => {
@@ -27,7 +29,7 @@ const App = ({ config }) => {
27
29
  alert("Error reloading entities: " + String(error));
28
30
  });
29
31
  }, [location.path, reloadEntities]);
30
- return (_jsx(ConfigContext.Provider, { value: config, children: _jsx(SettingsContext.Provider, { value: settingsContext, children: _jsx(LocationProvider, { children: _jsxs(EntitiesContext.Provider, { value: { entities: entities ?? [], reloadEntities }, children: [_jsxs(Router, { children: [_jsx(Route, { path: "/", component: Home }), _jsx(Route, { path: "/entities/:name", component: Entity }), _jsx(Route, { path: "/entities/:name/instances/create", component: CreateInstance }), _jsx(Route, { path: "/entities/:name/instances/:id", component: Instance }), _jsx(Route, { default: true, component: NotFound })] }), _jsx(Git, {})] }) }) }) }));
32
+ return (_jsx(ConfigContext.Provider, { value: config, children: _jsx(SettingsContext.Provider, { value: settingsContext, children: _jsx(GitContext.Provider, { value: [isGitOpen, setIsGitOpen], children: _jsx(LocationProvider, { children: _jsxs(EntitiesContext.Provider, { value: { entities: entities ?? [], reloadEntities }, children: [_jsxs(Router, { children: [_jsx(Route, { path: "/", component: Home }), _jsx(Route, { path: "/entities/:name", component: Entity }), _jsx(Route, { path: "/entities/:name/instances/create", component: CreateInstance }), _jsx(Route, { path: "/entities/:name/instances/:id", component: Instance }), _jsx(Route, { default: true, component: NotFound })] }), _jsx(Git, {})] }) }) }) }) }));
31
33
  };
32
34
  const config = await getWebConfig();
33
35
  const root = document.getElementById("app");
@@ -2,6 +2,7 @@ import type { FunctionalComponent } from "preact";
2
2
  import type { BlockMarkdownNode } from "../../shared/utils/markdown.ts";
3
3
  type Props = {
4
4
  node: BlockMarkdownNode;
5
+ outerHeadingLevel?: number;
5
6
  };
6
7
  export declare const BlockMarkdown: FunctionalComponent<Props>;
7
8
  export {};
@@ -1,9 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
2
  import { InlineMarkdown } from "./InlineMarkdown.js";
3
- export const BlockMarkdown = ({ node }) => {
3
+ export const BlockMarkdown = ({ node, outerHeadingLevel = 0 }) => {
4
4
  switch (node.kind) {
5
5
  case "paragraph":
6
6
  return (_jsx("p", { children: node.content.map((inline, ii) => (_jsx(InlineMarkdown, { node: inline }, ii))) }));
7
+ case "heading":
8
+ const Tag = `h${(node.level + outerHeadingLevel).toString()}`;
9
+ return (_jsx(Tag, { children: node.content.map((inline, ii) => (_jsx(InlineMarkdown, { node: inline }, ii))) }));
7
10
  case "list":
8
11
  if (node.ordered) {
9
12
  return (_jsx("ol", { children: node.content.map((item, ii) => (_jsx("li", { children: item.content.map((inline, iii) => (_jsx(InlineMarkdown, { node: inline }, iii))) }, ii))) }));
@@ -6,6 +6,8 @@ export const BlockMarkdownHighlighting = ({ node }) => {
6
6
  return _jsx("span", { class: "list-item-marker", children: node.content });
7
7
  case "tablemarker":
8
8
  return _jsx("span", { class: "table-marker", children: node.content });
9
+ case "headingmarker":
10
+ return _jsx("span", { class: "heading-marker", children: node.content });
9
11
  default:
10
12
  return _jsx(InlineMarkdown, { node: node });
11
13
  }
@@ -2,6 +2,7 @@ import type { FunctionalComponent } from "preact";
2
2
  type Props = {
3
3
  class?: string;
4
4
  string: string;
5
+ outerHeadingLevel?: number;
5
6
  };
6
7
  export declare const Markdown: FunctionalComponent<Props>;
7
8
  export {};
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment } from "preact/jsx-runtime";
2
2
  import { parseBlockMarkdown } from "../../shared/utils/markdown.js";
3
3
  import { BlockMarkdown } from "./BlockMarkdown.js";
4
- export const Markdown = ({ class: className, string }) => {
4
+ export const Markdown = ({ class: className, string, outerHeadingLevel, }) => {
5
5
  const blocks = parseBlockMarkdown(string);
6
- const blockElements = blocks.map((block, i) => (_jsx(BlockMarkdown, { node: block }, `md-block-${i.toString()}`)));
6
+ const blockElements = blocks.map((block, i) => (_jsx(BlockMarkdown, { node: block, outerHeadingLevel: outerHeadingLevel }, `md-block-${i.toString()}`)));
7
7
  if (className) {
8
8
  return _jsx("div", { class: className, children: blockElements });
9
9
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsondb",
3
- "version": "0.7.4",
3
+ "version": "0.7.6",
4
4
  "description": "",
5
5
  "license": "ISC",
6
6
  "author": "Lukas Obermann",
@@ -54,6 +54,7 @@
54
54
  --highlight-color-list-item-marker: rgb(195, 58, 237);
55
55
  --highlight-color-table-marker: rgb(237, 58, 118);
56
56
  --highlight-color-attributed: rgb(48, 81, 228);
57
+ --highlight-color-heading-marker: rgb(62, 189, 191);
57
58
  }
58
59
 
59
60
  @media (prefers-color-scheme: dark) {
@@ -87,6 +88,7 @@
87
88
  --highlight-color-list-item-marker: rgb(220, 133, 245);
88
89
  --highlight-color-table-marker: rgb(244, 135, 171);
89
90
  --highlight-color-attributed: rgb(137, 157, 244);
91
+ --highlight-color-heading-marker: rgb(140, 229, 231);
90
92
  --shadow-color: rgba(0, 0, 0, 0);
91
93
  }
92
94
  }
@@ -134,6 +136,11 @@ header nav ol {
134
136
  margin: 0;
135
137
  }
136
138
 
139
+ .nav-buttons {
140
+ display: flex;
141
+ gap: 0.5rem;
142
+ }
143
+
137
144
  main {
138
145
  grid-area: main;
139
146
  }
@@ -682,6 +689,10 @@ form > .field--container {
682
689
  color: var(--highlight-color-table-marker);
683
690
  }
684
691
 
692
+ .editor-highlighting .heading-marker {
693
+ color: var(--highlight-color-heading-marker);
694
+ }
695
+
685
696
  .preview .attributed {
686
697
  text-decoration-line: underline;
687
698
  text-decoration-style: dashed;
@@ -875,6 +886,12 @@ main:has(.form-footer) {
875
886
 
876
887
  aside.git {
877
888
  grid-area: aside;
889
+ position: absolute;
890
+ top: 5rem;
891
+ right: 0;
892
+ width: 30rem;
893
+ max-width: calc(100% - 1.5rem);
894
+ max-height: calc(100% - 6.5rem);
878
895
  }
879
896
 
880
897
  aside.git h2 {
@@ -886,13 +903,18 @@ aside.git h2 {
886
903
  width: 30rem;
887
904
  border-left: 1px solid var(--separator-color);
888
905
  padding-left: 1rem;
906
+ top: unset;
907
+ right: unset;
908
+ position: static;
909
+ max-height: none;
910
+ max-width: none;
889
911
  }
890
912
 
891
913
  aside.git h2 {
892
914
  display: block;
893
915
  }
894
916
 
895
- aside.git > button {
917
+ .git-toggle {
896
918
  display: none;
897
919
  }
898
920
  }