diff --git a/.changeset/red-zoos-march.md b/.changeset/red-zoos-march.md new file mode 100644 index 000000000..3bd8a05bd --- /dev/null +++ b/.changeset/red-zoos-march.md @@ -0,0 +1,6 @@ +--- +"@codeimage/api": minor +"@codeimage/app": minor +--- + +feat(app,api) add new border type glass option diff --git a/.changeset/slimy-dolphins-add.md b/.changeset/slimy-dolphins-add.md new file mode 100644 index 000000000..81a0d01ae --- /dev/null +++ b/.changeset/slimy-dolphins-add.md @@ -0,0 +1,6 @@ +--- +"@codeimage/api": minor +"@codeimage/app": minor +--- + +feat(app,api): add line number start option diff --git a/.changeset/tame-deers-whisper.md b/.changeset/tame-deers-whisper.md new file mode 100644 index 000000000..b47e056b9 --- /dev/null +++ b/.changeset/tame-deers-whisper.md @@ -0,0 +1,5 @@ +--- +'@codeimage/app': minor +--- + +feat: allow zero padding diff --git a/.github/stale.yml b/.github/stale.yml index dc90e5a1c..24ed5161d 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,7 +1,7 @@ # Number of days of inactivity before an issue becomes stale -daysUntilStale: 60 +daysUntilStale: 120 # Number of days of inactivity before a stale issue is closed -daysUntilClose: 7 +daysUntilClose: 120 # Issues with these labels will never be considered stale exemptLabels: - pinned diff --git a/.github/workflows/prod-deploy.yml b/.github/workflows/prod-deploy.yml index d8d1e32f5..861c48f66 100644 --- a/.github/workflows/prod-deploy.yml +++ b/.github/workflows/prod-deploy.yml @@ -1,4 +1,4 @@ -name: "Deploy (Production)" +name: 'Deploy (Production)' on: workflow_dispatch: inputs: @@ -22,8 +22,8 @@ jobs: steps: - name: Checkout PR uses: actions/checkout@v3 -# with: -# submodules: 'true' + # with: + # submodules: 'true' - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: @@ -33,20 +33,20 @@ jobs: lint: name: Lint - needs: [ "install" ] + needs: ['install'] runs-on: ubuntu-latest steps: - name: Checkout PR uses: actions/checkout@v3 -# with: -# submodules: 'true' + # with: + # submodules: 'true' - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - name: 📥 Monorepo install uses: ./.github/actions/pnpm-install - - name: "[API] Generate Prisma Migration" + - name: '[API] Generate Prisma Migration' run: | pnpm --filter=@codeimage/api exec prisma generate pnpm --filter=@codeimage/prisma-models build @@ -55,12 +55,12 @@ jobs: build-packages: name: Build packages/** - needs: [ "install" ] + needs: ['install'] runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 -# with: -# submodules: 'true' + # with: + # submodules: 'true' - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: @@ -68,12 +68,12 @@ jobs: - name: 📥 Monorepo install uses: ./.github/actions/pnpm-install - - name: "[API] Generate Prisma Migration" + - name: '[API] Generate Prisma Migration' run: | pnpm --filter=@codeimage/api exec prisma generate pnpm --filter=@codeimage/prisma-models build - - name: "Build packages" + - name: 'Build packages' run: | pnpm libs:build @@ -84,13 +84,13 @@ jobs: key: packages-dist-${{ github.run_id }}-${{ github.run_number }} build-api: - name: "Build @codeimage/api" - needs: [ "install" ] + name: 'Build @codeimage/api' + needs: ['install'] runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 -# with: -# submodules: 'true' + # with: + # submodules: 'true' - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: @@ -98,7 +98,7 @@ jobs: - name: 📥 Monorepo install uses: ./.github/actions/pnpm-install - - name: "[API] Generate Prisma Migration" + - name: '[API] Generate Prisma Migration' run: | pnpm --filter=@codeimage/api exec prisma generate pnpm --filter=@codeimage/prisma-models build @@ -118,7 +118,7 @@ jobs: test-api: name: Api test - needs: [ install ] + needs: [install] runs-on: ubuntu-latest services: @@ -146,7 +146,7 @@ jobs: GRANT_TYPE_AUTH0: client_credentials MOCK_AUTH: false MOCK_AUTH_EMAIL: dev@example.it - ALLOWED_ORIGINS: "*" + ALLOWED_ORIGINS: '*' steps: - uses: actions/checkout@v3 @@ -159,7 +159,7 @@ jobs: - name: 📥 Monorepo install uses: ./.github/actions/pnpm-install - - name: "Run prisma DB migrations" + - name: 'Run prisma DB migrations' run: | cd apps/api pnpm exec prisma migrate deploy @@ -174,12 +174,12 @@ jobs: typecheck-packages: name: Type-checking packages/** - needs: [ "install", "build-packages" ] + needs: ['install', 'build-packages'] runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 -# with: -# submodules: 'true' + # with: + # submodules: 'true' - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: @@ -205,12 +205,12 @@ jobs: deploy-highlight-package: name: Deploy @codeimage/highlight app environment: Production - needs: [ "install", "lint", "build-packages" ] + needs: ['install', 'lint', 'build-packages'] runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 -# with: -# submodules: 'true' + # with: + # submodules: 'true' - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: @@ -239,12 +239,12 @@ jobs: deploy-api: name: Build and Deploy Api environment: Production - needs: [ install, lint, typecheck-packages, test-api, build-api ] + needs: [install, lint, typecheck-packages, test-api, build-api] runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 -# with: -# submodules: 'true' + # with: + # submodules: 'true' - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: @@ -274,7 +274,7 @@ jobs: find -type f -name '.gitignore' -delete pnpm railway link --environment production $RAILWAY_API_PROJECT_ID cd dist/api-bundle - pnpm railway up --detach + pnpm railway up -s codeimage env: RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }} RAILWAY_API_PROJECT_ID: ${{ secrets.RAILWAY_API_PROJECT_ID }} @@ -282,13 +282,13 @@ jobs: deploy-app: name: Deploy @codeimage/app environment: Production - needs: [ install, lint, typecheck-packages, build-packages, deploy-api ] + needs: [install, lint, typecheck-packages, build-packages, deploy-api] runs-on: ubuntu-latest steps: - name: Checkout PR uses: actions/checkout@v3 -# with: -# submodules: 'true' + # with: + # submodules: 'true' - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: @@ -325,23 +325,22 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} #Optional vercel-args: '--prebuilt --prod' #Optional working-directory: apps/codeimage - vercel-org-id: ${{ secrets.VERCEL_ORG_ID}} #Required + vercel-org-id: ${{ secrets.VERCEL_ORG_ID}} #Required vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }} #Required alias-domains: | #Optional app.codeimage.dev - deploy-website: if: ${{ github.event.inputs.deploy-website == 'true' }} name: Deploy @codeimage/website environment: Production - needs: [ install, lint, typecheck-packages, build-packages ] + needs: [install, lint, typecheck-packages, build-packages] runs-on: ubuntu-latest steps: - name: Checkout PR uses: actions/checkout@v3 -# with: -# submodules: 'true' + # with: + # submodules: 'true' - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: diff --git a/apps/api/package.json b/apps/api/package.json index e3f59b578..5b131aed7 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -52,7 +52,7 @@ "@prisma/client": "^4.15.0", "@sinclair/typebox": "^0.31.28", "@teamhanko/passkeys-sdk": "^0.1.8", - "auth0": "4.2.0", + "auth0": "4.3.1", "close-with-grace": "^1.2.0", "dotenv": "^16.1.4", "dotenv-cli": "^6.0.0", diff --git a/apps/api/prisma/migrations/20231231115803_add_terminal_border_type_property/migration.sql b/apps/api/prisma/migrations/20231231115803_add_terminal_border_type_property/migration.sql new file mode 100644 index 000000000..07b42de0b --- /dev/null +++ b/apps/api/prisma/migrations/20231231115803_add_terminal_border_type_property/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "SnippetTerminal" ADD COLUMN "borderType" TEXT; diff --git a/apps/api/prisma/migrations/20240107110836_add_line_number_start/migration.sql b/apps/api/prisma/migrations/20240107110836_add_line_number_start/migration.sql new file mode 100644 index 000000000..5f6b5312f --- /dev/null +++ b/apps/api/prisma/migrations/20240107110836_add_line_number_start/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "SnippetEditorTab" ADD COLUMN "lineNumberStart" INTEGER NOT NULL DEFAULT 1; diff --git a/apps/api/prisma/schema.prisma b/apps/api/prisma/schema.prisma index 4425eda66..8883dda9b 100644 --- a/apps/api/prisma/schema.prisma +++ b/apps/api/prisma/schema.prisma @@ -62,6 +62,7 @@ model SnippetTerminal { showGlassReflection Boolean @default(false) opacity Float @default(100) alternativeTheme Boolean @default(false) + borderType String? } model SnippetEditorOptions { @@ -82,6 +83,8 @@ model SnippetEditorTab { languageId String tabName String @default("") + lineNumberStart Int @default(1) + @@unique([id, projectId]) } diff --git a/apps/api/src/common/typebox/enum.ts b/apps/api/src/common/typebox/enum.ts index 1e0d2211e..d28c3823c 100644 --- a/apps/api/src/common/typebox/enum.ts +++ b/apps/api/src/common/typebox/enum.ts @@ -1,7 +1,10 @@ -import {Type} from '@sinclair/typebox'; +import {TString, Type} from '@sinclair/typebox'; -export const enumLiteral = (values: [...T]) => { +export const enumLiteral = (values: T[]): TString => { const literals = values.map(value => Type.Literal(value)); // TODO: validation should work but type must work as a string... - return Type.Intersect([Type.Union(literals), Type.String()]); + return Type.Intersect([ + Type.Union(literals), + Type.String(), + ]) as unknown as TString; }; diff --git a/apps/api/src/modules/project/domain/projectUpdateRequest.ts b/apps/api/src/modules/project/domain/projectUpdateRequest.ts index 0298ef1c8..e3447be7e 100644 --- a/apps/api/src/modules/project/domain/projectUpdateRequest.ts +++ b/apps/api/src/modules/project/domain/projectUpdateRequest.ts @@ -13,6 +13,7 @@ interface EditorUpdateRequest { code: NonNullable; languageId: NonNullable; tabName: NonNullable; + lineNumberStart: NonNullable; } interface EditorTabResponse { @@ -20,6 +21,7 @@ interface EditorTabResponse { code: NonNullable; languageId: NonNullable; tabName: NonNullable; + lineNumberStart: NonNullable; } export interface ProjectUpdateRequest { diff --git a/apps/api/src/modules/project/infra/prisma/prisma-project.repository.ts b/apps/api/src/modules/project/infra/prisma/prisma-project.repository.ts index ad37ebe4f..850b64260 100644 --- a/apps/api/src/modules/project/infra/prisma/prisma-project.repository.ts +++ b/apps/api/src/modules/project/infra/prisma/prisma-project.repository.ts @@ -105,6 +105,7 @@ export function makePrismaProjectRepository( showWatermark: data.terminal.showWatermark, textColor: data.terminal.textColor, type: data.terminal.type, + borderType: data.terminal.borderType, }, }, }, @@ -138,20 +139,22 @@ export function makePrismaProjectRepository( }, }, upsert: data.editors.map(editor => { - const {languageId, code, tabName} = editor; + const {languageId, code, tabName, lineNumberStart, id} = editor; return { where: { - id: editor.id, + id, }, create: { code, tabName, languageId, + lineNumberStart, }, update: { code, tabName, languageId, + lineNumberStart, }, }; }), @@ -186,6 +189,7 @@ export function makePrismaProjectRepository( showWatermark: data.terminal.showWatermark, textColor: data.terminal.textColor, type: data.terminal.type, + borderType: data.terminal.borderType, }, }, }, diff --git a/apps/api/src/modules/project/mapper/create-project-mapper.ts b/apps/api/src/modules/project/mapper/create-project-mapper.ts index 423a2ac11..989097e82 100644 --- a/apps/api/src/modules/project/mapper/create-project-mapper.ts +++ b/apps/api/src/modules/project/mapper/create-project-mapper.ts @@ -48,6 +48,7 @@ export function createProjectRequestMapper( data.terminal.alternativeTheme ?? SnippetTerminalCreateRequestSchema.properties.alternativeTheme.default, shadow: data.terminal.shadow ?? null, + borderType: data.terminal.borderType ?? null, }, editorOptions: { fontWeight: data.editorOptions.fontWeight, @@ -62,6 +63,7 @@ export function createProjectRequestMapper( languageId: editor.languageId, code: editor.code, tabName: editor.tabName, + lineNumberStart: editor.lineNumberStart, })), }; } diff --git a/apps/api/src/modules/project/mapper/get-project-by-id-mapper.ts b/apps/api/src/modules/project/mapper/get-project-by-id-mapper.ts index c5322015e..1749d40bd 100644 --- a/apps/api/src/modules/project/mapper/get-project-by-id-mapper.ts +++ b/apps/api/src/modules/project/mapper/get-project-by-id-mapper.ts @@ -30,6 +30,7 @@ export function createCompleteProjectGetByIdResponseMapper( accentVisible: data.terminal.accentVisible, alternativeTheme: data.terminal.alternativeTheme, shadow: data.terminal.shadow, + borderType: data.terminal.borderType as 'glass' | null, }, editorOptions: { id: data.editorOptions.id, @@ -45,6 +46,7 @@ export function createCompleteProjectGetByIdResponseMapper( languageId: editor.languageId, code: editor.code, tabName: editor.tabName, + lineNumberStart: editor.lineNumberStart, })), isOwner: false, }; diff --git a/apps/api/src/modules/project/schema/project-create.schema.ts b/apps/api/src/modules/project/schema/project-create.schema.ts index c6584b8fd..375ffe689 100644 --- a/apps/api/src/modules/project/schema/project-create.schema.ts +++ b/apps/api/src/modules/project/schema/project-create.schema.ts @@ -1,5 +1,6 @@ import {Static, Type} from '@sinclair/typebox'; import {Nullable} from '../../../common/typebox/nullable.js'; +import {SnippetTerminalBorderType} from './project.schema.js'; export const SnippetFrameCreateRequestSchema = Type.Object( { @@ -26,6 +27,7 @@ export const SnippetEditorTabsCreateRequestSchema = Type.Array( code: Type.String(), languageId: Type.String(), tabName: Type.String(), + lineNumberStart: Type.Integer({minimum: 1, maximum: 999_999}), }, {title: 'SnippetEditorTabCreateRequest'}, ), @@ -44,6 +46,7 @@ export const SnippetTerminalCreateRequestSchema = Type.Object( opacity: Nullable(Type.Number({minimum: 0, maximum: 100, default: 100})), showHeader: Type.Boolean(), showWatermark: Nullable(Type.Boolean({default: true})), + borderType: Nullable(SnippetTerminalBorderType), }, {title: 'SnippetTerminalCreateRequest'}, ); diff --git a/apps/api/src/modules/project/schema/project-update.schema.ts b/apps/api/src/modules/project/schema/project-update.schema.ts index 0909d8066..73eb7a8d5 100644 --- a/apps/api/src/modules/project/schema/project-update.schema.ts +++ b/apps/api/src/modules/project/schema/project-update.schema.ts @@ -1,5 +1,6 @@ import {Static, Type} from '@sinclair/typebox'; import {Nullable} from '../../../common/typebox/nullable.js'; +import {SnippetTerminalBorderType} from './project.schema.js'; export const SnippetFrameUpdateRequestSchema = Type.Object( { @@ -21,6 +22,7 @@ export const SnippetEditorTabsUpdateRequestSchema = Type.Array( code: Type.String(), languageId: Type.String(), tabName: Type.String(), + lineNumberStart: Type.Integer({minimum: 1, maximum: 999_999}), }, {title: 'SnippetEditorTabUpdateRequest'}, ), @@ -39,6 +41,7 @@ const SnippetTerminalUpdateRequestSchema = Type.Object( showWatermark: Type.Boolean(), textColor: Nullable(Type.String()), type: Type.String(), + borderType: Nullable(SnippetTerminalBorderType), }, {title: 'SnippetTerminalUpdateRequest'}, ); diff --git a/apps/api/src/modules/project/schema/project.schema.ts b/apps/api/src/modules/project/schema/project.schema.ts index fc0682169..82f9ef1be 100644 --- a/apps/api/src/modules/project/schema/project.schema.ts +++ b/apps/api/src/modules/project/schema/project.schema.ts @@ -1,4 +1,5 @@ import {Type} from '@sinclair/typebox'; +import {enumLiteral} from '../../../common/typebox/enum.js'; import {Nullable} from '../../../common/typebox/nullable.js'; export const BaseProjectResponseSchema = Type.Object( @@ -21,6 +22,7 @@ export const BaseSnippetEditorTabsSchema = Type.Array( code: Type.String(), languageId: Type.String(), tabName: Type.String(), + lineNumberStart: Type.Integer({minimum: 1, maximum: 999_999}), }), ); @@ -33,6 +35,8 @@ export const BaseSnippetFrameSchema = Type.Object({ opacity: Type.Number(), }); +export const SnippetTerminalBorderType = enumLiteral(['glass'] as const); + export const BaseSnippetTerminalSchema = Type.Object({ id: Type.String({format: 'uuid'}), showHeader: Type.Boolean(), @@ -45,6 +49,7 @@ export const BaseSnippetTerminalSchema = Type.Object({ showGlassReflection: Type.Boolean(), opacity: Type.Number(), alternativeTheme: Type.Boolean(), + borderType: Nullable(SnippetTerminalBorderType), }); export const BaseSnippetEditorOptionsSchema = Type.Object({ diff --git a/apps/api/test/modules/project/mapper/create-project-mapper.test.ts b/apps/api/test/modules/project/mapper/create-project-mapper.test.ts index fdc4cfcf3..d9136c7c8 100644 --- a/apps/api/test/modules/project/mapper/create-project-mapper.test.ts +++ b/apps/api/test/modules/project/mapper/create-project-mapper.test.ts @@ -22,6 +22,7 @@ test('should map ProjectCreateRequest to Prisma ProjectCreateRequest with defaul shadow: null, textColor: null, accentVisible: null, + borderType: null, }, name: 'Untitled', editors: [], @@ -53,6 +54,7 @@ test('should map ProjectCreateRequest to Prisma ProjectCreateRequest with defaul showWatermark: true, opacity: 100, showHeader: true, + borderType: null, }, editors: [], name: 'Untitled', diff --git a/apps/api/test/modules/project/mapper/get-project-by-id-mapper.test.ts b/apps/api/test/modules/project/mapper/get-project-by-id-mapper.test.ts index 5a7d9d32f..270d7ef25 100644 --- a/apps/api/test/modules/project/mapper/get-project-by-id-mapper.test.ts +++ b/apps/api/test/modules/project/mapper/get-project-by-id-mapper.test.ts @@ -31,6 +31,7 @@ test('should map Prisma ProjectGetByIdResponse to schema ProjectGetByIdResponse' shadow: null, textColor: null, accentVisible: true, + borderType: 'glass', }, editorOptionsId: 'editorOptionsId', terminalId: 'terminalId', @@ -75,6 +76,7 @@ test('should map Prisma ProjectGetByIdResponse to schema ProjectGetByIdResponse' showWatermark: false, opacity: 100, showHeader: true, + borderType: 'glass', }, editorOptions: { id: 'editorOptionsId', diff --git a/apps/api/test/routes/v1/project/create.integration.test.ts b/apps/api/test/routes/v1/project/create.integration.test.ts index 0c9fccc33..6ed03cac9 100644 --- a/apps/api/test/routes/v1/project/create.integration.test.ts +++ b/apps/api/test/routes/v1/project/create.integration.test.ts @@ -35,7 +35,12 @@ test('POST /v1/project/ [Create Project] -> 200', async context => padding: 0, }, editors: [ - {code: 'function(){}', languageId: 'javascript', tabName: 'index.jsx'}, + { + code: 'function(){}', + languageId: 'javascript', + tabName: 'index.jsx', + lineNumberStart: 300, + }, ], editorOptions: { fontWeight: 400, diff --git a/apps/api/test/routes/v1/project/update.integration.test.ts b/apps/api/test/routes/v1/project/update.integration.test.ts index 1966f4cee..8f4b08581 100644 --- a/apps/api/test/routes/v1/project/update.integration.test.ts +++ b/apps/api/test/routes/v1/project/update.integration.test.ts @@ -44,12 +44,14 @@ test('POST /v1/project/:id [Update Project] -> 200', async context code: '## title', languageId: 'markdown', tabName: 'README.md', + lineNumberStart: 1, }, { id: 'temp', code: '2', languageId: 'typescript', tabName: 'index.tsx', + lineNumberStart: 300, }, ], editorOptions: { @@ -70,6 +72,7 @@ test('POST /v1/project/:id [Update Project] -> 200', async context alternativeTheme: true, accentVisible: false, type: 'windows', + borderType: 'glass', }, }; @@ -123,7 +126,8 @@ test('POST /v1/project/:id [Update Project] -> 200', async context alternativeTheme: true, accentVisible: false, type: 'windows', - } as ProjectUpdateResponse['terminal'], + borderType: 'glass', + } satisfies ProjectUpdateResponse['terminal'], 'return updated terminal', ); assert.deepStrictEqual( @@ -134,12 +138,14 @@ test('POST /v1/project/:id [Update Project] -> 200', async context code: '## title', languageId: 'markdown', tabName: 'README.md', + lineNumberStart: 1, }, { id: body.editorTabs[1].id, code: '2', languageId: 'typescript', tabName: 'index.tsx', + lineNumberStart: 300, }, ] as ProjectUpdateResponse['editorTabs'], 'return updated editor tabs', diff --git a/apps/codeimage/CHANGELOG.md b/apps/codeimage/CHANGELOG.md index a74fddc7e..91e30b327 100644 --- a/apps/codeimage/CHANGELOG.md +++ b/apps/codeimage/CHANGELOG.md @@ -1,5 +1,14 @@ # @codeimage/app +## 1.5.1 + +### Patch Changes + +- [#620](https://github.com/riccardoperra/codeimage/pull/620) [`8046d566`](https://github.com/riccardoperra/codeimage/commit/8046d566b2e9542a8d0c6d66c156afd396713746) Thanks [@riccardoperra](https://github.com/riccardoperra)! - feat: update umami + +- Updated dependencies [[`1f9e5788`](https://github.com/riccardoperra/codeimage/commit/1f9e5788e1a011542f850d2abd35f12201a19b8b)]: + - @codeimage/config@8.2.5 + ## 1.5.0 ### Minor Changes diff --git a/apps/codeimage/package.json b/apps/codeimage/package.json index 07947f791..733acabdd 100644 --- a/apps/codeimage/package.json +++ b/apps/codeimage/package.json @@ -1,7 +1,7 @@ { "name": "@codeimage/app", "private": true, - "version": "1.5.0", + "version": "1.5.1", "type": "module", "scripts": { "start": "vite", @@ -67,7 +67,7 @@ "@codemirror/search": "^6.4.0", "@codemirror/state": "^6.2.0", "@codemirror/view": "^6.11.0", - "@codeui/kit": "^0.0.36", + "@codeui/kit": "^0.0.37", "@floating-ui/core": "^1.2.2", "@floating-ui/dom": "^1.2.3", "@formatjs/intl-relativetimeformat": "11.1.4", diff --git a/apps/codeimage/src/components/CustomEditor/CustomEditor.tsx b/apps/codeimage/src/components/CustomEditor/CustomEditor.tsx index f829423dd..5871676f2 100644 --- a/apps/codeimage/src/components/CustomEditor/CustomEditor.tsx +++ b/apps/codeimage/src/components/CustomEditor/CustomEditor.tsx @@ -172,9 +172,15 @@ export default function CustomEditor(props: VoidProps) { createExtension(() => customFontExtension()); createExtension(currentLanguage); createExtension(currentExtraLanguage); - createExtension(() => - editorState.options.showLineNumbers ? lineNumbers() : [], - ); + + const lineNumberStart = createMemo(() => editor()?.lineNumberStart); + createExtension(() => { + const lnStart = lineNumberStart() ?? 1; + const newLn = (ln: number) => ln + (lnStart - 1); + return editorState.options.showLineNumbers + ? lineNumbers({formatNumber: lineNo => String(newLn(lineNo))}) + : []; + }); createExtension(() => themeConfiguration()?.editorTheme || []); createExtension(baseTheme); diff --git a/apps/codeimage/src/components/FeatureBadge/FeatureBadge.css.ts b/apps/codeimage/src/components/FeatureBadge/FeatureBadge.css.ts index 0d6ab38d6..883937732 100644 --- a/apps/codeimage/src/components/FeatureBadge/FeatureBadge.css.ts +++ b/apps/codeimage/src/components/FeatureBadge/FeatureBadge.css.ts @@ -12,7 +12,7 @@ export const badge = style({ position: 'absolute', left: '100%', top: '50%', - transform: `translateX(10px) translateY(-50%)`, + transform: `translateX(2px) translateY(-50%)`, borderRadius: themeTokens.radii.lg, whiteSpace: 'nowrap', }); diff --git a/apps/codeimage/src/components/Frame/ManagedFrame.tsx b/apps/codeimage/src/components/Frame/ManagedFrame.tsx index c841ddecb..94d9352c4 100644 --- a/apps/codeimage/src/components/Frame/ManagedFrame.tsx +++ b/apps/codeimage/src/components/Frame/ManagedFrame.tsx @@ -40,6 +40,7 @@ export function ManagedFrame() { showWatermark={terminal.showWatermark} opacity={terminal.opacity} alternativeTheme={terminal.alternativeTheme} + borderType={terminal.borderType} themeId={editor.state.options.themeId} > diff --git a/apps/codeimage/src/components/Frame/PreviewFrame.tsx b/apps/codeimage/src/components/Frame/PreviewFrame.tsx index 2bdc66e66..3ee7bbdd9 100644 --- a/apps/codeimage/src/components/Frame/PreviewFrame.tsx +++ b/apps/codeimage/src/components/Frame/PreviewFrame.tsx @@ -121,6 +121,7 @@ export function PreviewFrame(props: VoidProps) { showWatermark={terminal.showWatermark} opacity={terminal.opacity} alternativeTheme={terminal.alternativeTheme} + borderType={terminal.borderType} themeId={editor.state.options.themeId} > diff --git a/apps/codeimage/src/components/Icons/SettingsIcon.tsx b/apps/codeimage/src/components/Icons/SettingsIcon.tsx new file mode 100644 index 000000000..660e0ecbf --- /dev/null +++ b/apps/codeimage/src/components/Icons/SettingsIcon.tsx @@ -0,0 +1,25 @@ +import {SvgIconProps} from '@codeimage/ui'; +import {SvgIcon} from '@codeui/kit'; + +export function SettingsIcon(props: SvgIconProps) { + return ( + + + + + + ); +} diff --git a/apps/codeimage/src/components/Presets/PresetPreview/PresetPreview.tsx b/apps/codeimage/src/components/Presets/PresetPreview/PresetPreview.tsx index f3a636e2e..4dde585c3 100644 --- a/apps/codeimage/src/components/Presets/PresetPreview/PresetPreview.tsx +++ b/apps/codeimage/src/components/Presets/PresetPreview/PresetPreview.tsx @@ -39,6 +39,7 @@ export function PresetPreview(props: PresetPreviewProps) { accentVisible={props.data.terminal.accentVisible} textColor={props.data.terminal.textColor} showHeader={props.data.terminal.showHeader} + borderType={props.data.terminal.borderType} showGlassReflection={props.data.terminal.showGlassReflection} showWatermark={false} opacity={props.data.terminal.opacity} diff --git a/apps/codeimage/src/components/Presets/PresetSwitcher/PresetSwitcher.tsx b/apps/codeimage/src/components/Presets/PresetSwitcher/PresetSwitcher.tsx index 74808945f..1c9948edc 100644 --- a/apps/codeimage/src/components/Presets/PresetSwitcher/PresetSwitcher.tsx +++ b/apps/codeimage/src/components/Presets/PresetSwitcher/PresetSwitcher.tsx @@ -55,7 +55,7 @@ export const PresetSwitcher: ParentComponent< editor.actions.setFromPreset(data.editor); frame.setFromPreset(data.frame); terminal.setFromPreset(data.terminal); - getUmami().trackEvent('preset', 'select-preset'); + getUmami().track('select-preset-theme'); }; const exampleCode = diff --git a/apps/codeimage/src/components/PropertyEditor/EditorStyleForm.tsx b/apps/codeimage/src/components/PropertyEditor/EditorStyleForm.tsx index 065acead1..028d300a6 100644 --- a/apps/codeimage/src/components/PropertyEditor/EditorStyleForm.tsx +++ b/apps/codeimage/src/components/PropertyEditor/EditorStyleForm.tsx @@ -6,7 +6,7 @@ import {getRootEditorStore} from '@codeimage/store/editor'; import {getActiveEditorStore} from '@codeimage/store/editor/activeEditor'; import {dispatchUpdateTheme} from '@codeimage/store/effects/onThemeChange'; import {getThemeStore} from '@codeimage/store/theme/theme.store'; -import {createSelectOptions, Select} from '@codeui/kit'; +import {createSelectOptions, Select, NumberField} from '@codeui/kit'; import {getUmami} from '@core/constants/umami'; import {DynamicSizedContainer} from '@ui/DynamicSizedContainer/DynamicSizedContainer'; import {SegmentedField} from '@ui/SegmentedField/SegmentedField'; @@ -18,6 +18,7 @@ import {PanelDivider} from './PanelDivider'; import {PanelHeader} from './PanelHeader'; import {PanelRow, TwoColumnPanelRow} from './PanelRow'; import {SuspenseEditorItem} from './SuspenseEditorItem'; +import {appEnvironment} from '@core/configuration'; const languages: readonly LanguageDefinition[] = [...SUPPORTED_LANGUAGES].sort( (a, b) => { @@ -35,9 +36,15 @@ const languages: readonly LanguageDefinition[] = [...SUPPORTED_LANGUAGES].sort( export const EditorStyleForm: ParentComponent = () => { const {themeArray} = getThemeStore(); + const {lineNumbers: lineNumbersConfig} = appEnvironment; const [t] = useI18n(); - const {editor, setLanguageId, formatter, setFormatterName} = - getActiveEditorStore(); + const { + editor, + setLanguageId, + formatter, + setFormatterName, + setLineNumberStart, + } = getActiveEditorStore(); const { state, actions: {setShowLineNumbers, setFontWeight, setFontId, setEnableLigatures}, @@ -114,7 +121,9 @@ export const EditorStyleForm: ParentComponent = () => { () => editor().languageId, language => { setLanguageId(language!); - getUmami().trackEvent(language!, 'change-language'); + getUmami().track('change-language', { + language: language!, + }); }, )} options={languagesOptions.options()} @@ -205,6 +214,28 @@ export const EditorStyleForm: ParentComponent = () => { + + + + + } + > + + + + + diff --git a/apps/codeimage/src/components/PropertyEditor/FrameStyleForm.tsx b/apps/codeimage/src/components/PropertyEditor/FrameStyleForm.tsx index 63c929fbc..0579b3996 100644 --- a/apps/codeimage/src/components/PropertyEditor/FrameStyleForm.tsx +++ b/apps/codeimage/src/components/PropertyEditor/FrameStyleForm.tsx @@ -12,12 +12,24 @@ import {CustomColorPicker} from './controls/ColorPicker/CustomColorPicker'; import {PanelHeader} from './PanelHeader'; import {PanelRow, TwoColumnPanelRow} from './PanelRow'; import {SuspenseEditorItem} from './SuspenseEditorItem'; +import {Select, createSelectOptions} from '@codeui/kit'; export const FrameStyleForm: ParentComponent = () => { const [t] = useI18n(); const {editorPadding, editorRadius} = appEnvironment; const frame = getFrameState(); + const paddingOptions = createSelectOptions( + editorPadding.map(padding => ({ + label: padding.label, + value: padding.value, + })), + { + key: 'label', + valueKey: 'value', + }, + ); + return ( <> @@ -27,16 +39,22 @@ export const FrameStyleForm: ParentComponent = () => { } > - String(frame.store.padding), + padding => { + if (typeof padding === 'undefined') { + return; + } + frame.setPadding(Number(padding)); + }, + )} + options={paddingOptions.options()} + aria-label={'Padding'} id={'paddingField'} size={'xs'} - value={frame.store.padding} - onChange={frame.setPadding} - items={editorPadding.map(padding => ({ - label: padding.toString(), - value: padding, - }))} /> @@ -129,7 +147,7 @@ export const FrameStyleForm: ParentComponent = () => { value={frame.store.aspectRatio} onChange={ratio => { frame.setAspectRatio(ratio); - getUmami().trackEvent(ratio ?? 'auto', 'aspect-ratio'); + getUmami().track('aspect-ratio', {ratio: ratio ?? 'unset'}); }} /> diff --git a/apps/codeimage/src/components/PropertyEditor/WindowStyleForm.tsx b/apps/codeimage/src/components/PropertyEditor/WindowStyleForm.tsx index f8bc6fa1d..e45aa1a2f 100644 --- a/apps/codeimage/src/components/PropertyEditor/WindowStyleForm.tsx +++ b/apps/codeimage/src/components/PropertyEditor/WindowStyleForm.tsx @@ -1,11 +1,13 @@ import {useI18n} from '@codeimage/locale'; import {getTerminalState} from '@codeimage/store/editor/terminal'; +import {VersionStore} from '@codeimage/store/version/version.store'; import {createSelectOptions, Select} from '@codeui/kit'; import {shadowsLabel} from '@core/configuration/shadow'; import {getUmami} from '@core/constants/umami'; import {SegmentedField} from '@ui/SegmentedField/SegmentedField'; import {SkeletonLine} from '@ui/Skeleton/Skeleton'; import {createMemo, ParentComponent, Show} from 'solid-js'; +import {provideState} from 'statebuilder'; import {AppLocaleEntries} from '../../i18n'; import {TerminalControlField} from './controls/TerminalControlField/TerminalControlField'; import {PanelHeader} from './PanelHeader'; @@ -14,6 +16,7 @@ import {SuspenseEditorItem} from './SuspenseEditorItem'; export const WindowStyleForm: ParentComponent = () => { const terminal = getTerminalState(); + const versionStore = provideState(VersionStore); const [t] = useI18n(); const terminalShadows = createMemo( @@ -25,6 +28,17 @@ export const WindowStyleForm: ParentComponent = () => { valueKey: 'value', }); + const borderTypeSelect = createSelectOptions( + [ + {label: 'None', value: 'none'}, + {label: 'Glass', value: 'glass'}, + ], + { + key: 'label', + valueKey: 'value', + }, + ); + return ( <> @@ -78,7 +92,12 @@ export const WindowStyleForm: ParentComponent = () => { { + terminal.setType(type); + getUmami().track('change-terminal-type', { + type, + }); + }} onShowAccentChange={terminal.setAccentVisible} /> @@ -133,7 +152,9 @@ export const WindowStyleForm: ParentComponent = () => { {...terminalShadowsSelect.controlled( () => terminal.state.shadow ?? undefined, shadow => { - getUmami().trackEvent(shadow ?? 'none', 'change-shadow'); + getUmami().track('change-shadow', { + shadow: shadow ?? 'none', + }); terminal.setShadow(shadow ?? null); }, )} @@ -144,6 +165,36 @@ export const WindowStyleForm: ParentComponent = () => { + + + } + > +