tsondb 0.7.3 → 0.7.5
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.
- package/dist/src/bin/tsondb.js +1 -1
- package/dist/src/node/config.d.ts +1 -0
- package/dist/src/node/index.d.ts +1 -1
- package/dist/src/node/index.js +2 -2
- package/dist/src/node/schema/Schema.js +5 -3
- package/dist/src/node/schema/types/Type.d.ts +4 -2
- package/dist/src/node/schema/types/Type.js +14 -8
- package/dist/src/node/server/index.d.ts +1 -1
- package/dist/src/node/server/index.js +11 -2
- package/dist/src/shared/utils/markdown.d.ts +7 -0
- package/dist/src/shared/utils/markdown.js +14 -1
- package/dist/src/web/components/Git.js +4 -5
- package/dist/src/web/components/Layout.js +6 -1
- package/dist/src/web/components/typeInputs/StringTypeInput.js +1 -1
- package/dist/src/web/context/git.d.ts +3 -0
- package/dist/src/web/context/git.js +2 -0
- package/dist/src/web/index.js +4 -2
- package/dist/src/web/utils/BlockMarkdown.d.ts +1 -0
- package/dist/src/web/utils/BlockMarkdown.js +4 -1
- package/dist/src/web/utils/BlockMarkdownHighlighting.js +2 -0
- package/dist/src/web/utils/Markdown.d.ts +1 -0
- package/dist/src/web/utils/Markdown.js +2 -2
- package/package.json +1 -1
- package/public/css/styles.css +17 -1
package/dist/src/bin/tsondb.js
CHANGED
|
@@ -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`);
|
package/dist/src/node/index.d.ts
CHANGED
|
@@ -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
|
|
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 {};
|
package/dist/src/node/index.js
CHANGED
|
@@ -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);
|
|
@@ -43,20 +43,22 @@ const checkEntityDisplayNamePaths = (decls, localeEntity) => {
|
|
|
43
43
|
if (localeEntity === undefined) {
|
|
44
44
|
throw new Error(`Display name path "${pathToLocaleMap}" for entity "${decl.name}" requires a defined locale entity.`);
|
|
45
45
|
}
|
|
46
|
-
const localeMapAtPath = findTypeAtPath(decl.type.value, pathToLocaleMap.split(".")
|
|
46
|
+
const localeMapAtPath = findTypeAtPath(decl.type.value, pathToLocaleMap.split("."), {
|
|
47
|
+
followTypeAliasIncludes: true,
|
|
48
|
+
});
|
|
47
49
|
if (!localeMapAtPath ||
|
|
48
50
|
!isNestedEntityMapType(localeMapAtPath) ||
|
|
49
51
|
localeMapAtPath.secondaryEntity.name !== localeEntity.name) {
|
|
50
52
|
throw new Error(`Display name path "${pathToLocaleMap}" for entity "${decl.name}" does not lead to a nested entity map for the defined locale entity.`);
|
|
51
53
|
}
|
|
52
|
-
const typeAtLocaleMapPath = findTypeAtPath(localeMapAtPath.type.value, pathInLocaleMap.split("."));
|
|
54
|
+
const typeAtLocaleMapPath = findTypeAtPath(localeMapAtPath.type.value, pathInLocaleMap.split("."), { followTypeAliasIncludes: true });
|
|
53
55
|
if (!typeAtLocaleMapPath || !isStringType(typeAtLocaleMapPath)) {
|
|
54
56
|
throw new Error(`Display name path "${pathInLocaleMap}" for entity "${decl.name}" does not lead to a value of type string in nested locale map.`);
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
else {
|
|
58
60
|
const path = displayName.split(".");
|
|
59
|
-
const typeAtPath = findTypeAtPath(decl.type.value, path);
|
|
61
|
+
const typeAtPath = findTypeAtPath(decl.type.value, path, { followTypeAliasIncludes: true });
|
|
60
62
|
if (!typeAtPath || !isStringType(typeAtPath)) {
|
|
61
63
|
throw new Error(`Display name path "${displayName}" for entity "${decl.name}" does not lead to a value of type string.`);
|
|
62
64
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Decl } from "../index.ts";
|
|
2
2
|
import type { BaseNode } from "../Node.ts";
|
|
3
3
|
import type { ArrayType } from "./generic/ArrayType.ts";
|
|
4
4
|
import type { EnumType } from "./generic/EnumType.ts";
|
|
@@ -23,7 +23,9 @@ export type AsType<T extends Type> = T extends ArrayType<infer I> ? AsType<I>[]
|
|
|
23
23
|
export type AsNode<T> = T extends (infer I)[] ? ArrayType<AsNode<I>> : T extends Record<string, unknown> ? ObjectType<{
|
|
24
24
|
[K in keyof T]: T[K] extends MemberDecl ? T[K] : T extends null | undefined ? MemberDecl<AsNode<NonNullable<T[K]>>, false> : MemberDecl<AsNode<T[K]>, true>;
|
|
25
25
|
}> : T extends string ? StringType : T extends number ? FloatType : T extends boolean ? BooleanType : T extends Date ? DateType : never;
|
|
26
|
-
export declare const findTypeAtPath: (type: Type, path: string[]
|
|
26
|
+
export declare const findTypeAtPath: (type: Type, path: string[], options?: {
|
|
27
|
+
followTypeAliasIncludes?: boolean;
|
|
28
|
+
}) => Type | undefined;
|
|
27
29
|
/**
|
|
28
30
|
* Format the structure of a value to always look the same when serialized as JSON.
|
|
29
31
|
*/
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { assertExhaustive } from "../../../shared/utils/typeSafety.js";
|
|
2
|
+
import { isTypeAliasDecl } from "../index.js";
|
|
2
3
|
import { NodeKind } from "../Node.js";
|
|
3
|
-
import { formatArrayValue } from "./generic/ArrayType.js";
|
|
4
|
+
import { formatArrayValue, isArrayType } from "./generic/ArrayType.js";
|
|
4
5
|
import { formatEnumType } from "./generic/EnumType.js";
|
|
5
|
-
import { formatObjectValue } from "./generic/ObjectType.js";
|
|
6
|
+
import { formatObjectValue, isObjectType } from "./generic/ObjectType.js";
|
|
6
7
|
import { formatBooleanValue } from "./primitives/BooleanType.js";
|
|
7
8
|
import { formatDateValue } from "./primitives/DateType.js";
|
|
8
9
|
import { formatFloatValue } from "./primitives/FloatType.js";
|
|
9
10
|
import { formatIntegerValue } from "./primitives/IntegerType.js";
|
|
10
11
|
import { formatStringValue } from "./primitives/StringType.js";
|
|
11
12
|
import { formatChildEntitiesValue } from "./references/ChildEntitiesType.js";
|
|
12
|
-
import { formatIncludeIdentifierValue } from "./references/IncludeIdentifierType.js";
|
|
13
|
+
import { formatIncludeIdentifierValue, isIncludeIdentifierType, } from "./references/IncludeIdentifierType.js";
|
|
13
14
|
import { formatNestedEntityMapValue } from "./references/NestedEntityMapType.js";
|
|
14
15
|
import { formatReferenceIdentifierValue } from "./references/ReferenceIdentifierType.js";
|
|
15
16
|
import { formatTypeArgumentValue } from "./references/TypeArgumentType.js";
|
|
@@ -63,19 +64,24 @@ export function walkTypeNodeTree(callbackFn, type, parentTypes, parentDecl) {
|
|
|
63
64
|
return assertExhaustive(type);
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
|
-
export const findTypeAtPath = (type, path) => {
|
|
67
|
+
export const findTypeAtPath = (type, path, options = {}) => {
|
|
67
68
|
const [head, ...tail] = path;
|
|
68
69
|
if (head === undefined) {
|
|
69
70
|
return type;
|
|
70
71
|
}
|
|
71
|
-
if (type
|
|
72
|
+
if (isObjectType(type)) {
|
|
72
73
|
const prop = type.properties[head];
|
|
73
74
|
if (prop) {
|
|
74
|
-
return findTypeAtPath(prop.type, tail);
|
|
75
|
+
return findTypeAtPath(prop.type, tail, options);
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
|
-
else if (type
|
|
78
|
-
return findTypeAtPath(type.items, path);
|
|
78
|
+
else if (isArrayType(type) && head === "0") {
|
|
79
|
+
return findTypeAtPath(type.items, path, options);
|
|
80
|
+
}
|
|
81
|
+
else if (isIncludeIdentifierType(type) &&
|
|
82
|
+
options.followTypeAliasIncludes &&
|
|
83
|
+
isTypeAliasDecl(type.reference)) {
|
|
84
|
+
return findTypeAtPath(type.reference.type.value, path, options);
|
|
79
85
|
}
|
|
80
86
|
return undefined;
|
|
81
87
|
};
|
|
@@ -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
|
|
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
|
|
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" }),
|
|
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
|
-
|
|
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)
|
package/dist/src/web/index.js
CHANGED
|
@@ -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
|
}
|
|
@@ -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
package/public/css/styles.css
CHANGED
|
@@ -134,6 +134,11 @@ header nav ol {
|
|
|
134
134
|
margin: 0;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
.nav-buttons {
|
|
138
|
+
display: flex;
|
|
139
|
+
gap: 0.5rem;
|
|
140
|
+
}
|
|
141
|
+
|
|
137
142
|
main {
|
|
138
143
|
grid-area: main;
|
|
139
144
|
}
|
|
@@ -875,6 +880,12 @@ main:has(.form-footer) {
|
|
|
875
880
|
|
|
876
881
|
aside.git {
|
|
877
882
|
grid-area: aside;
|
|
883
|
+
position: absolute;
|
|
884
|
+
top: 5rem;
|
|
885
|
+
right: 0;
|
|
886
|
+
width: 30rem;
|
|
887
|
+
max-width: calc(100% - 1.5rem);
|
|
888
|
+
max-height: calc(100% - 6.5rem);
|
|
878
889
|
}
|
|
879
890
|
|
|
880
891
|
aside.git h2 {
|
|
@@ -886,13 +897,18 @@ aside.git h2 {
|
|
|
886
897
|
width: 30rem;
|
|
887
898
|
border-left: 1px solid var(--separator-color);
|
|
888
899
|
padding-left: 1rem;
|
|
900
|
+
top: unset;
|
|
901
|
+
right: unset;
|
|
902
|
+
position: static;
|
|
903
|
+
max-height: none;
|
|
904
|
+
max-width: none;
|
|
889
905
|
}
|
|
890
906
|
|
|
891
907
|
aside.git h2 {
|
|
892
908
|
display: block;
|
|
893
909
|
}
|
|
894
910
|
|
|
895
|
-
|
|
911
|
+
.git-toggle {
|
|
896
912
|
display: none;
|
|
897
913
|
}
|
|
898
914
|
}
|