Skip to content

Commit 9e537bc

Browse files
feat(app,api): add line number start option (#624)
* feat(app,api): add line number start option * chore: cleanup * Create slimy-dolphins-add.md * test(api): add integration test * lint: fix lint * lint: fix lint
1 parent 8b49087 commit 9e537bc

File tree

23 files changed

+1706
-155
lines changed

23 files changed

+1706
-155
lines changed

.changeset/slimy-dolphins-add.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@codeimage/api": minor
3+
"@codeimage/app": minor
4+
---
5+
6+
feat(app,api): add line number start option
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterTable
2+
ALTER TABLE "SnippetEditorTab" ADD COLUMN "lineNumberStart" INTEGER NOT NULL DEFAULT 1;

apps/api/prisma/schema.prisma

+2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ model SnippetEditorTab {
8282
languageId String
8383
tabName String @default("")
8484
85+
lineNumberStart Int @default(1)
86+
8587
@@unique([id, projectId])
8688
}
8789

apps/api/src/modules/project/domain/projectUpdateRequest.ts

+2
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ interface EditorUpdateRequest {
1313
code: NonNullable<SnippetEditorTab['code']>;
1414
languageId: NonNullable<SnippetEditorTab['languageId']>;
1515
tabName: NonNullable<SnippetEditorTab['tabName']>;
16+
lineNumberStart: NonNullable<SnippetEditorTab['lineNumberStart']>;
1617
}
1718

1819
interface EditorTabResponse {
1920
id: NonNullable<SnippetEditorTab['id']>;
2021
code: NonNullable<SnippetEditorTab['code']>;
2122
languageId: NonNullable<SnippetEditorTab['languageId']>;
2223
tabName: NonNullable<SnippetEditorTab['tabName']>;
24+
lineNumberStart: NonNullable<SnippetEditorTab['lineNumberStart']>;
2325
}
2426

2527
export interface ProjectUpdateRequest {

apps/api/src/modules/project/infra/prisma/prisma-project.repository.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -138,20 +138,22 @@ export function makePrismaProjectRepository(
138138
},
139139
},
140140
upsert: data.editors.map(editor => {
141-
const {languageId, code, tabName} = editor;
141+
const {languageId, code, tabName, lineNumberStart, id} = editor;
142142
return {
143143
where: {
144-
id: editor.id,
144+
id,
145145
},
146146
create: {
147147
code,
148148
tabName,
149149
languageId,
150+
lineNumberStart,
150151
},
151152
update: {
152153
code,
153154
tabName,
154155
languageId,
156+
lineNumberStart,
155157
},
156158
};
157159
}),

apps/api/src/modules/project/mapper/create-project-mapper.ts

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export function createProjectRequestMapper(
6262
languageId: editor.languageId,
6363
code: editor.code,
6464
tabName: editor.tabName,
65+
lineNumberStart: editor.lineNumberStart,
6566
})),
6667
};
6768
}

apps/api/src/modules/project/mapper/get-project-by-id-mapper.ts

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export function createCompleteProjectGetByIdResponseMapper(
4545
languageId: editor.languageId,
4646
code: editor.code,
4747
tabName: editor.tabName,
48+
lineNumberStart: editor.lineNumberStart,
4849
})),
4950
isOwner: false,
5051
};

apps/api/src/modules/project/schema/project-create.schema.ts

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export const SnippetEditorTabsCreateRequestSchema = Type.Array(
2626
code: Type.String(),
2727
languageId: Type.String(),
2828
tabName: Type.String(),
29+
lineNumberStart: Type.Integer({minimum: 1, maximum: 999_999}),
2930
},
3031
{title: 'SnippetEditorTabCreateRequest'},
3132
),

apps/api/src/modules/project/schema/project-update.schema.ts

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export const SnippetEditorTabsUpdateRequestSchema = Type.Array(
2121
code: Type.String(),
2222
languageId: Type.String(),
2323
tabName: Type.String(),
24+
lineNumberStart: Type.Integer({minimum: 1, maximum: 999_999}),
2425
},
2526
{title: 'SnippetEditorTabUpdateRequest'},
2627
),

apps/api/src/modules/project/schema/project.schema.ts

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export const BaseSnippetEditorTabsSchema = Type.Array(
2121
code: Type.String(),
2222
languageId: Type.String(),
2323
tabName: Type.String(),
24+
lineNumberStart: Type.Integer({minimum: 1, maximum: 999_999}),
2425
}),
2526
);
2627

apps/api/test/routes/v1/project/create.integration.test.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@ test<TestContext>('POST /v1/project/ [Create Project] -> 200', async context =>
3535
padding: 0,
3636
},
3737
editors: [
38-
{code: 'function(){}', languageId: 'javascript', tabName: 'index.jsx'},
38+
{
39+
code: 'function(){}',
40+
languageId: 'javascript',
41+
tabName: 'index.jsx',
42+
lineNumberStart: 300,
43+
},
3944
],
4045
editorOptions: {
4146
fontWeight: 400,

apps/api/test/routes/v1/project/update.integration.test.ts

+4
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,14 @@ test<TestContext>('POST /v1/project/:id [Update Project] -> 200', async context
4444
code: '## title',
4545
languageId: 'markdown',
4646
tabName: 'README.md',
47+
lineNumberStart: 1,
4748
},
4849
{
4950
id: 'temp',
5051
code: '2',
5152
languageId: 'typescript',
5253
tabName: 'index.tsx',
54+
lineNumberStart: 300,
5355
},
5456
],
5557
editorOptions: {
@@ -134,12 +136,14 @@ test<TestContext>('POST /v1/project/:id [Update Project] -> 200', async context
134136
code: '## title',
135137
languageId: 'markdown',
136138
tabName: 'README.md',
139+
lineNumberStart: 1,
137140
},
138141
{
139142
id: body.editorTabs[1].id,
140143
code: '2',
141144
languageId: 'typescript',
142145
tabName: 'index.tsx',
146+
lineNumberStart: 300,
143147
},
144148
] as ProjectUpdateResponse['editorTabs'],
145149
'return updated editor tabs',

apps/api/tsconfig.json

+4-7
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,13 @@
33
"compilerOptions": {
44
"outDir": "dist",
55
"resolveJsonModule": false,
6+
"declarationMap": true,
67
"allowSyntheticDefaultImports": true,
78
"sourceMap": true,
89
"moduleResolution": "NodeNext",
910
"module": "NodeNext",
1011
"target": "ES2022",
11-
"typeRoots": [
12-
"./src/common/domainFunctions/functions.d.ts"
13-
]
12+
"typeRoots": ["./src/common/domainFunctions/functions.d.ts"]
1413
},
15-
"include": [
16-
"./src/**/*.ts"
17-
]
18-
}
14+
"include": ["./src/**/*.ts"]
15+
}

apps/codeimage/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
"@codemirror/search": "^6.4.0",
6868
"@codemirror/state": "^6.2.0",
6969
"@codemirror/view": "^6.11.0",
70-
"@codeui/kit": "^0.0.36",
70+
"@codeui/kit": "^0.0.37",
7171
"@floating-ui/core": "^1.2.2",
7272
"@floating-ui/dom": "^1.2.3",
7373
"@formatjs/intl-relativetimeformat": "11.1.4",

apps/codeimage/src/components/CustomEditor/CustomEditor.tsx

+9-3
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,15 @@ export default function CustomEditor(props: VoidProps<CustomEditorProps>) {
172172
createExtension(() => customFontExtension());
173173
createExtension(currentLanguage);
174174
createExtension(currentExtraLanguage);
175-
createExtension(() =>
176-
editorState.options.showLineNumbers ? lineNumbers() : [],
177-
);
175+
176+
const lineNumberStart = createMemo(() => editor()?.lineNumberStart);
177+
createExtension(() => {
178+
const lnStart = lineNumberStart() ?? 1;
179+
const newLn = (ln: number) => ln + (lnStart - 1);
180+
return editorState.options.showLineNumbers
181+
? lineNumbers({formatNumber: lineNo => String(newLn(lineNo))})
182+
: [];
183+
});
178184
createExtension(() => themeConfiguration()?.editorTheme || []);
179185
createExtension(baseTheme);
180186

apps/codeimage/src/components/PropertyEditor/EditorStyleForm.tsx

+32-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {getRootEditorStore} from '@codeimage/store/editor';
66
import {getActiveEditorStore} from '@codeimage/store/editor/activeEditor';
77
import {dispatchUpdateTheme} from '@codeimage/store/effects/onThemeChange';
88
import {getThemeStore} from '@codeimage/store/theme/theme.store';
9-
import {createSelectOptions, Select} from '@codeui/kit';
9+
import {createSelectOptions, Select, NumberField} from '@codeui/kit';
1010
import {getUmami} from '@core/constants/umami';
1111
import {DynamicSizedContainer} from '@ui/DynamicSizedContainer/DynamicSizedContainer';
1212
import {SegmentedField} from '@ui/SegmentedField/SegmentedField';
@@ -18,6 +18,7 @@ import {PanelDivider} from './PanelDivider';
1818
import {PanelHeader} from './PanelHeader';
1919
import {PanelRow, TwoColumnPanelRow} from './PanelRow';
2020
import {SuspenseEditorItem} from './SuspenseEditorItem';
21+
import {appEnvironment} from '@core/configuration';
2122

2223
const languages: readonly LanguageDefinition[] = [...SUPPORTED_LANGUAGES].sort(
2324
(a, b) => {
@@ -35,9 +36,15 @@ const languages: readonly LanguageDefinition[] = [...SUPPORTED_LANGUAGES].sort(
3536

3637
export const EditorStyleForm: ParentComponent = () => {
3738
const {themeArray} = getThemeStore();
39+
const {lineNumbers: lineNumbersConfig} = appEnvironment;
3840
const [t] = useI18n<AppLocaleEntries>();
39-
const {editor, setLanguageId, formatter, setFormatterName} =
40-
getActiveEditorStore();
41+
const {
42+
editor,
43+
setLanguageId,
44+
formatter,
45+
setFormatterName,
46+
setLineNumberStart,
47+
} = getActiveEditorStore();
4148
const {
4249
state,
4350
actions: {setShowLineNumbers, setFontWeight, setFontId, setEnableLigatures},
@@ -207,6 +214,28 @@ export const EditorStyleForm: ParentComponent = () => {
207214
</SuspenseEditorItem>
208215
</TwoColumnPanelRow>
209216
</PanelRow>
217+
218+
<Show when={state.options.showLineNumbers}>
219+
<PanelRow
220+
for={'frameLineNumberStartField'}
221+
label={t('frame.lineNumberStart')}
222+
>
223+
<TwoColumnPanelRow>
224+
<SuspenseEditorItem
225+
fallback={<SkeletonLine width={'100%'} height={'26px'} />}
226+
>
227+
<NumberField
228+
size={'xs'}
229+
min={lineNumbersConfig.min}
230+
max={lineNumbersConfig.max}
231+
id={'frameLineNumberStartField'}
232+
value={editor().lineNumberStart}
233+
onChange={setLineNumberStart}
234+
/>
235+
</SuspenseEditorItem>
236+
</TwoColumnPanelRow>
237+
</PanelRow>
238+
</Show>
210239
</DynamicSizedContainer>
211240

212241
<PanelDivider />

apps/codeimage/src/core/configuration.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@ export const [appEnvironment] = createConfiguration({
77
locales: SUPPORTED_LOCALES,
88
themes: [],
99
languages: [],
10+
lineNumbers: {
11+
min: 1,
12+
max: 999_999,
13+
},
1014
editorPadding: [
11-
{label: '0', value: "0"},
12-
{label: '16', value: "16"},
13-
{label: '32', value: "32"},
14-
{label: '64', value: "64"},
15-
{label: '128', value: "128"},
15+
{label: '0', value: '0'},
16+
{label: '16', value: '16'},
17+
{label: '32', value: '32'},
18+
{label: '64', value: '64'},
19+
{label: '128', value: '128'},
1620
],
1721
editorRadius: [
1822
{label: '0', value: 0},

apps/codeimage/src/i18n/sidebar.ts

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export default {
1717
editor: 'Editor',
1818
language: 'Language',
1919
lineNumbers: 'Line number',
20+
lineNumberStart: 'Line start',
2021
font: 'Font',
2122
theme: 'Theme',
2223
fontWeight: 'Font weight',
@@ -43,6 +44,7 @@ export default {
4344
editor: 'Editor',
4445
language: 'Linguaggio',
4546
lineNumbers: 'Numeri di riga',
47+
lineNumberStart: 'Line start',
4648
font: 'Carattere',
4749
fontWeight: 'Peso carattere',
4850
reflection: 'Riflesso',
@@ -70,6 +72,7 @@ export default {
7072
editor: 'Editor',
7173
language: 'Sprache',
7274
lineNumbers: 'Zeilennummer',
75+
lineNumberStart: 'Line start',
7376
font: 'Schriftart',
7477
fontWeight: 'Schriftstärke',
7578
reflection: 'Reflektion',
@@ -97,6 +100,7 @@ export default {
97100
editor: 'Editor',
98101
language: 'Idioma',
99102
lineNumbers: 'Número de línea',
103+
lineNumberStart: 'Line start',
100104
font: 'Fuente',
101105
fontWeight: 'Peso de fuente',
102106
reflection: 'Reflexión',

apps/codeimage/src/pages/Dashboard/dashboard.state.ts

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ function makeDashboardState(authState = getAuth0State()) {
7474
code: appEnvironment.defaultState.editor.code,
7575
languageId: appEnvironment.defaultState.editor.languageId,
7676
tabName: 'index.tsx',
77+
lineNumberStart: 1,
7778
},
7879
],
7980
},

apps/codeimage/src/state/editor/activeEditor.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import {useI18n} from '@codeimage/locale';
33
import {getRootEditorStore} from '@codeimage/store/editor';
44
import {getUiStore} from '@codeimage/store/ui';
55
import {toast} from '@codeimage/ui';
6-
import {isNonNullable} from '@solid-primitives/utils';
6+
import {appEnvironment} from '@core/configuration';
7+
import {clamp, isNonNullable} from '@solid-primitives/utils';
78
import {createEffect, createMemo, createRoot, on} from 'solid-js';
89
import {createPrettierFormatter} from '../../hooks/createPrettierFormatter';
910
import {AppLocaleEntries} from '../../i18n';
@@ -46,6 +47,20 @@ const $activeEditorState = () => {
4647
const setCode = (code: string) =>
4748
setEditors(currentEditorIndex(), 'code', code);
4849

50+
const setLineNumberStart = (lineNumberStart: number | null | undefined) => {
51+
if (lineNumberStart === null) return;
52+
return setEditors(
53+
currentEditorIndex(),
54+
'lineNumberStart',
55+
// TODO Already done by @codeui/kit but I don't feel safe about this component I made
56+
clamp(
57+
lineNumberStart ?? 1,
58+
appEnvironment.lineNumbers.min,
59+
appEnvironment.lineNumbers.max,
60+
),
61+
);
62+
};
63+
4964
const setFormatterName = (formatter: string | null) =>
5065
setEditors(currentEditorIndex(), 'formatter', formatter);
5166

@@ -83,6 +98,7 @@ const $activeEditorState = () => {
8398
editor: currentEditor,
8499
setLanguageId,
85100
setCode,
101+
setLineNumberStart,
86102
formatter,
87103
setFormatterName,
88104
canFormat: formatter.canFormat,

apps/codeimage/src/state/editor/editor.ts

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export function getInitialEditorState(): EditorState {
2222
code: appEnvironment.defaultState.editor.code,
2323
languageId: appEnvironment.defaultState.editor.languageId,
2424
formatter: null,
25+
lineNumberStart: 1,
2526
tab: {
2627
tabName: 'index.tsx',
2728
tabIcon: undefined,
@@ -104,6 +105,7 @@ export function createEditorsStore() {
104105
languageId: editor.languageId,
105106
id: editor.id,
106107
code: editor.code,
108+
lineNumberStart: editor.lineNumberStart,
107109
}));
108110
return {
109111
options: {...state.options, ...persistedState.options},
@@ -114,6 +116,7 @@ export function createEditorsStore() {
114116
languageId: editor.languageId,
115117
tab: {tabName: editor.tabName},
116118
id: editor.id,
119+
lineNumberStart: editor.lineNumberStart,
117120
};
118121
}),
119122
};
@@ -136,6 +139,7 @@ export function createEditorsStore() {
136139
code: editor.code,
137140
tabName: editor.tab.tabName ?? '',
138141
id: editor.id,
142+
lineNumberStart: editor.lineNumberStart ?? 1,
139143
};
140144
}),
141145
options: {
@@ -245,6 +249,7 @@ export function createEditorsStore() {
245249
languageId: editor.languageId,
246250
id: editor.id,
247251
code: editor.code,
252+
lineNumberStart: editor.lineNumberStart ?? 1,
248253
} as EditorState),
249254
),
250255
);

0 commit comments

Comments
 (0)