Skip to content

Commit 8f1c13c

Browse files
committed
ENG-1272 Migrate all small global settings components
1 parent 29817b9 commit 8f1c13c

File tree

6 files changed

+279
-88
lines changed

6 files changed

+279
-88
lines changed

apps/roam/src/components/settings/ExportSettings.tsx

Lines changed: 30 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,63 @@
11
import React from "react";
2-
import { getFormattedConfigTree } from "~/utils/discourseConfigRef";
3-
import FlagPanel from "roamjs-components/components/ConfigPanels/FlagPanel";
4-
import NumberPanel from "roamjs-components/components/ConfigPanels/NumberPanel";
5-
import MultiTextPanel from "roamjs-components/components/ConfigPanels/MultiTextPanel";
6-
import SelectPanel from "roamjs-components/components/ConfigPanels/SelectPanel";
2+
import {
3+
BlockPropFlagPanel,
4+
BlockPropNumberPanel,
5+
BlockPropSelectPanel,
6+
BlockPropMultiTextPanel,
7+
} from "./components/BlockPropGlobalSettingPanels";
78

8-
const DiscourseGraphExport = ({}: {}) => {
9-
const settings = getFormattedConfigTree();
10-
const exportSettings = settings.export;
11-
const parentUid = settings.export.exportUid;
9+
const DiscourseGraphExport = () => {
1210
return (
1311
<div className="flex flex-col gap-4 p-1">
1412
<div>
15-
<FlagPanel
13+
<BlockPropFlagPanel
1614
title="remove special characters"
1715
description="Whether or not to remove the special characters in a file name"
18-
order={1}
19-
uid={exportSettings.removeSpecialCharacters.uid}
20-
parentUid={parentUid}
21-
value={exportSettings.removeSpecialCharacters.value || false}
16+
settingKeys={["Export", "Remove Special Characters"]}
17+
defaultValue={false}
2218
/>
2319

24-
<FlagPanel
20+
<BlockPropFlagPanel
2521
title="resolve block references"
2622
description="Replaces block references in the markdown content with the block's content"
27-
order={3}
28-
uid={exportSettings.optsRefs.uid}
29-
parentUid={parentUid}
30-
value={exportSettings.optsRefs.value || false}
23+
settingKeys={["Export", "Resolve Block References"]}
24+
defaultValue={false}
3125
/>
32-
<FlagPanel
26+
<BlockPropFlagPanel
3327
title="resolve block embeds"
3428
description="Replaces block embeds in the markdown content with the block's content tree"
35-
order={4}
36-
uid={exportSettings.optsEmbeds.uid}
37-
parentUid={parentUid}
38-
value={exportSettings.optsEmbeds.value || false}
29+
settingKeys={["Export", "Resolve Block Embeds"]}
30+
defaultValue={false}
3931
/>
4032

41-
<FlagPanel
33+
<BlockPropFlagPanel
4234
title="append referenced node"
4335
description="If a referenced node is defined in a node's format, it will be appended to the discourse context"
44-
order={6}
45-
uid={exportSettings.appendRefNodeContext.uid}
46-
parentUid={parentUid}
47-
value={exportSettings.appendRefNodeContext.value || false}
36+
settingKeys={["Export", "Append Referenced Node"]}
37+
defaultValue={false}
4838
/>
4939
</div>
5040
<div className="link-type-select-wrapper">
51-
<SelectPanel
41+
<BlockPropSelectPanel
5242
title="link type"
5343
description="How to format links that appear in your export."
54-
order={5}
55-
options={{
56-
items: ["alias", "wikilinks", "roam url"],
57-
}}
58-
uid={exportSettings.linkType.uid}
59-
parentUid={parentUid}
60-
value={exportSettings.linkType.value || "alias"}
44+
settingKeys={["Export", "Link Type"]}
45+
options={["alias", "wikilinks", "roam url"]}
46+
defaultValue="alias"
6147
/>
6248
</div>
63-
<NumberPanel
49+
<BlockPropNumberPanel
6450
title="max filename length"
6551
description="Set the maximum name length for markdown file exports"
66-
order={0}
67-
uid={exportSettings.maxFilenameLength.uid}
68-
parentUid={parentUid}
69-
value={exportSettings.maxFilenameLength.value || 64}
52+
settingKeys={["Export", "Max Filename Length"]}
53+
defaultValue={64}
54+
min={1}
7055
/>
71-
<MultiTextPanel
56+
<BlockPropMultiTextPanel
7257
title="frontmatter"
7358
description="Specify all the lines that should go to the Frontmatter of the markdown file"
74-
order={2}
75-
uid={exportSettings.frontmatter.uid}
76-
parentUid={parentUid}
77-
value={exportSettings.frontmatter.values || []}
59+
settingKeys={["Export", "Frontmatter"]}
60+
defaultValue={[]}
7861
/>
7962
</div>
8063
);

apps/roam/src/components/settings/GeneralSettings.tsx

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,21 @@
1-
import React, { useMemo } from "react";
2-
import TextPanel from "roamjs-components/components/ConfigPanels/TextPanel";
3-
import { getFormattedConfigTree } from "~/utils/discourseConfigRef";
4-
import refreshConfigTree from "~/utils/refreshConfigTree";
1+
import React from "react";
52
import { DEFAULT_CANVAS_PAGE_FORMAT } from "~/index";
63
import { BlockPropFeatureFlagPanel } from "./components/BlockPropFeatureFlagPanel";
4+
import { BlockPropTextPanel } from "./components/BlockPropGlobalSettingPanels";
75

86
const DiscourseGraphHome = () => {
9-
const settings = useMemo(() => {
10-
refreshConfigTree();
11-
return getFormattedConfigTree();
12-
}, []);
13-
147
return (
158
<div className="flex flex-col gap-4 p-1">
16-
<TextPanel
9+
<BlockPropTextPanel
1710
title="trigger"
1811
description="The trigger to create the node menu."
19-
order={0}
20-
uid={settings.trigger.uid}
21-
parentUid={settings.settingsUid}
22-
value={settings.trigger.value}
12+
settingKeys={["Trigger"]}
13+
defaultValue="\\"
2314
/>
24-
<TextPanel
15+
<BlockPropTextPanel
2516
title="Canvas Page Format"
2617
description="The page format for canvas pages"
27-
order={1}
28-
uid={settings.canvasPageFormat.uid}
29-
parentUid={settings.settingsUid}
30-
value={settings.canvasPageFormat.value}
18+
settingKeys={["Canvas Page Format"]}
3119
defaultValue={DEFAULT_CANVAS_PAGE_FORMAT}
3220
/>
3321
<BlockPropFeatureFlagPanel
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
import React, { useState } from "react";
2+
import {
3+
Checkbox,
4+
InputGroup,
5+
Label,
6+
NumericInput,
7+
HTMLSelect,
8+
Button,
9+
Tag,
10+
} from "@blueprintjs/core";
11+
import Description from "roamjs-components/components/Description";
12+
import idToTitle from "roamjs-components/util/idToTitle";
13+
import { getGlobalSetting, setGlobalSetting } from "../utils/accessors";
14+
15+
type BaseProps = {
16+
title: string;
17+
description: string;
18+
settingKeys: string[];
19+
};
20+
21+
export const BlockPropTextPanel = ({
22+
title,
23+
description,
24+
settingKeys,
25+
defaultValue = "",
26+
placeholder,
27+
}: BaseProps & {
28+
defaultValue?: string;
29+
placeholder?: string;
30+
}) => {
31+
const [value, setValue] = useState(
32+
() => getGlobalSetting<string>(settingKeys) ?? defaultValue,
33+
);
34+
35+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
36+
const newValue = e.target.value;
37+
setValue(newValue);
38+
setGlobalSetting(settingKeys, newValue);
39+
};
40+
41+
return (
42+
<Label>
43+
{idToTitle(title)}
44+
<Description description={description} />
45+
<InputGroup
46+
value={value}
47+
onChange={handleChange}
48+
placeholder={placeholder || defaultValue}
49+
/>
50+
</Label>
51+
);
52+
};
53+
54+
export const BlockPropFlagPanel = ({
55+
title,
56+
description,
57+
settingKeys,
58+
defaultValue = false,
59+
disabled = false,
60+
onChange,
61+
}: BaseProps & {
62+
defaultValue?: boolean;
63+
disabled?: boolean;
64+
onChange?: (checked: boolean) => void;
65+
}) => {
66+
const [value, setValue] = useState(
67+
() => getGlobalSetting<boolean>(settingKeys) ?? defaultValue,
68+
);
69+
70+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
71+
const { checked } = e.target;
72+
setValue(checked);
73+
setGlobalSetting(settingKeys, checked);
74+
onChange?.(checked);
75+
};
76+
77+
return (
78+
<Checkbox
79+
checked={value}
80+
onChange={handleChange}
81+
disabled={disabled}
82+
labelElement={
83+
<>
84+
{idToTitle(title)}
85+
<Description description={description} />
86+
</>
87+
}
88+
/>
89+
);
90+
};
91+
92+
export const BlockPropNumberPanel = ({
93+
title,
94+
description,
95+
settingKeys,
96+
defaultValue = 0,
97+
min,
98+
max,
99+
}: BaseProps & {
100+
defaultValue?: number;
101+
min?: number;
102+
max?: number;
103+
}) => {
104+
const [value, setValue] = useState(
105+
() => getGlobalSetting<number>(settingKeys) ?? defaultValue,
106+
);
107+
108+
const handleChange = (valueAsNumber: number) => {
109+
setValue(valueAsNumber);
110+
setGlobalSetting(settingKeys, valueAsNumber);
111+
};
112+
113+
return (
114+
<Label>
115+
{idToTitle(title)}
116+
<Description description={description} />
117+
<NumericInput
118+
value={value}
119+
onValueChange={handleChange}
120+
min={min}
121+
max={max}
122+
fill
123+
/>
124+
</Label>
125+
);
126+
};
127+
128+
export const BlockPropSelectPanel = ({
129+
title,
130+
description,
131+
settingKeys,
132+
options,
133+
defaultValue,
134+
}: BaseProps & {
135+
options: string[];
136+
defaultValue?: string;
137+
}) => {
138+
const [value, setValue] = useState(
139+
() => getGlobalSetting<string>(settingKeys) ?? defaultValue ?? options[0],
140+
);
141+
142+
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
143+
const newValue = e.target.value;
144+
setValue(newValue);
145+
setGlobalSetting(settingKeys, newValue);
146+
};
147+
148+
return (
149+
<Label>
150+
{idToTitle(title)}
151+
<Description description={description} />
152+
<HTMLSelect value={value} onChange={handleChange} fill options={options} />
153+
</Label>
154+
);
155+
};
156+
157+
export const BlockPropMultiTextPanel = ({
158+
title,
159+
description,
160+
settingKeys,
161+
defaultValue = [],
162+
}: BaseProps & {
163+
defaultValue?: string[];
164+
}) => {
165+
const [values, setValues] = useState<string[]>(
166+
() => getGlobalSetting<string[]>(settingKeys) ?? defaultValue,
167+
);
168+
const [inputValue, setInputValue] = useState("");
169+
170+
const handleAdd = () => {
171+
if (inputValue.trim() && !values.includes(inputValue.trim())) {
172+
const newValues = [...values, inputValue.trim()];
173+
setValues(newValues);
174+
setGlobalSetting(settingKeys, newValues);
175+
setInputValue("");
176+
}
177+
};
178+
179+
const handleRemove = (index: number) => {
180+
const newValues = values.filter((_, i) => i !== index);
181+
setValues(newValues);
182+
setGlobalSetting(settingKeys, newValues);
183+
};
184+
185+
const handleKeyDown = (e: React.KeyboardEvent) => {
186+
if (e.key === "Enter") {
187+
e.preventDefault();
188+
handleAdd();
189+
}
190+
};
191+
192+
return (
193+
<Label>
194+
{idToTitle(title)}
195+
<Description description={description} />
196+
<div className="flex gap-2">
197+
<InputGroup
198+
value={inputValue}
199+
onChange={(e) => setInputValue(e.target.value)}
200+
onKeyDown={handleKeyDown}
201+
placeholder="Add new item..."
202+
className="flex-grow"
203+
/>
204+
<Button icon="plus" onClick={handleAdd} disabled={!inputValue.trim()} />
205+
</div>
206+
{values.length > 0 && (
207+
<div className="mt-2 flex flex-wrap gap-1">
208+
{values.map((v, i) => (
209+
<Tag key={i} onRemove={() => handleRemove(i)} minimal>
210+
{v}
211+
</Tag>
212+
))}
213+
</div>
214+
)}
215+
</Label>
216+
);
217+
};

0 commit comments

Comments
 (0)