chore: migrate oxlint & oxfmt (#15464)

#### PR Dependency Tree


* **PR #15464** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Replaced the project’s formatting and linting workflow with Oxfmt and
Oxlint.
* Added shared formatting and linting configuration, editor integration,
and updated automated checks.
* Updated generated files, scripts, and lint guidance to use the new
tooling.

* **Style**
* Reformatted templates, source code, examples, and configuration files
for consistent readability.
  * No user-facing functionality or rendering behavior changed.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky authored and GitHub committed 2026-08-10 23:51:28 +08:00
1 parent 749c83cd8e
commit 0c7b20dc18
291 files changed
+1956 -1450

No files matched your search

+1 -5
View File
@@ -17,11 +17,7 @@
// Configure tool-specific properties. // Configure tool-specific properties.
"customizations": { "customizations": {
"vscode": { "vscode": {
"extensions": [ "extensions": ["ms-playwright.playwright", "oxc.oxc-vscode"]
"ms-playwright.playwright",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint"
]
} }
}, },
"updateContentCommand": "bash ./.devcontainer/build.sh", "updateContentCommand": "bash ./.devcontainer/build.sh",
+1 -1
View File
@@ -13,7 +13,7 @@
{ {
"rangeStrategy": "replace", "rangeStrategy": "replace",
"groupName": "linter", "groupName": "linter",
"matchPackageNames": ["/^eslint/", "/^@typescript-eslint/"] "matchPackageNames": ["/^eslint-plugin/"]
}, },
{ {
"matchDepNames": ["oxlint"], "matchDepNames": ["oxlint"],
+2 -4
View File
@@ -91,13 +91,11 @@ jobs:
run: yarn lint:ox run: yarn lint:ox
- name: Run i18n codegen - name: Run i18n codegen
run: yarn affine @affine/i18n build run: yarn affine @affine/i18n build
- name: Run ESLint - name: Run Oxfmt
run: yarn lint:eslint --max-warnings=0
- name: Run Prettier
# Set nmMode in `actions/setup-node` will modify the .yarnrc.yml # Set nmMode in `actions/setup-node` will modify the .yarnrc.yml
run: | run: |
git checkout .yarnrc.yml git checkout .yarnrc.yml
yarn lint:prettier yarn lint:format
- name: Yarn Dedupe - name: Yarn Dedupe
run: yarn dedupe --check run: yarn dedupe --check
-1
View File
@@ -73,7 +73,6 @@ playwright/.cache
download download
# Cache # Cache
.eslintcache
next-env.d.ts next-env.d.ts
.rollup.cache .rollup.cache
+10
View File
@@ -0,0 +1,10 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"printWidth": 80,
"singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2,
"arrowParens": "avoid",
"sortPackageJson": false,
"ignorePatterns": ["**/*.toml"]
}
+92 -1
View File
@@ -3,9 +3,27 @@
"jsPlugins": [ "jsPlugins": [
"eslint-plugin-simple-import-sort", "eslint-plugin-simple-import-sort",
"eslint-plugin-sonarjs", "eslint-plugin-sonarjs",
"eslint-plugin-lit" "eslint-plugin-lit",
{
"name": "import-x-js",
"specifier": "eslint-plugin-import-x"
},
{
"name": "react-js",
"specifier": "eslint-plugin-react"
},
{
"name": "react-hooks-js",
"specifier": "eslint-plugin-react-hooks"
}
], ],
"plugins": ["import", "react", "typescript", "unicorn", "promise"], "plugins": ["import", "react", "typescript", "unicorn", "promise"],
"settings": {
"_comment": "TODO: Restore rxjs/finnish when Oxlint JS plugins support type-aware rules.",
"react": {
"version": "19.2.1"
}
},
"categories": { "categories": {
"correctness": "error", "correctness": "error",
"perf": "error" "perf": "error"
@@ -66,8 +84,19 @@
"no-unused-private-class-members": "error", "no-unused-private-class-members": "error",
"no-useless-backreference": "error", "no-useless-backreference": "error",
"react/display-name": "error", "react/display-name": "error",
"react-js/no-deprecated": "error",
"react/rules-of-hooks": "error", "react/rules-of-hooks": "error",
"react/exhaustive-deps": "warn", "react/exhaustive-deps": "warn",
"react-hooks-js/component-hook-factories": "error",
"react-hooks-js/preserve-manual-memoization": "error",
"react-hooks-js/incompatible-library": "warn",
"react-hooks-js/globals": "error",
"react-hooks-js/error-boundaries": "error",
"react-hooks-js/purity": "error",
"react-hooks-js/set-state-in-render": "error",
"react-hooks-js/unsupported-syntax": "warn",
"react-hooks-js/config": "error",
"react-hooks-js/gating": "error",
"typescript/prefer-for-of": "error", "typescript/prefer-for-of": "error",
"typescript/no-unsafe-function-type": "error", "typescript/no-unsafe-function-type": "error",
"typescript/no-wrapper-object-types": "error", "typescript/no-wrapper-object-types": "error",
@@ -162,6 +191,7 @@
"no-useless-catch": "error", "no-useless-catch": "error",
"no-async-promise-executor": "error", "no-async-promise-executor": "error",
"no-unreachable": "error", "no-unreachable": "error",
"no-unreachable-loop": "error",
"no-duplicate-case": "error", "no-duplicate-case": "error",
"no-empty-pattern": "error", "no-empty-pattern": "error",
"no-unused-labels": "error", "no-unused-labels": "error",
@@ -399,6 +429,67 @@
"lit/binding-positions": "off", "lit/binding-positions": "off",
"lit/no-invalid-html": "off" "lit/no-invalid-html": "off"
} }
},
{
"files": [
"packages/**/*.{ts,tsx}",
"tools/**/*.{ts,tsx}",
"blocksuite/**/*.{ts,tsx}"
],
"rules": {
"import-x-js/no-extraneous-dependencies": [
"error",
{
"includeInternal": true
}
]
}
},
{
"files": ["packages/frontend/admin/**/*"],
"rules": {
"import-x-js/no-extraneous-dependencies": [
"error",
{
"includeInternal": true,
"whitelist": ["@affine/admin"]
}
]
}
},
{
"files": ["packages/frontend/core/**/*"],
"rules": {
"import-x-js/no-extraneous-dependencies": [
"error",
{
"includeInternal": true,
"whitelist": ["@affine/core"]
}
]
}
},
{
"files": ["packages/frontend/component/**/*"],
"rules": {
"import-x-js/no-extraneous-dependencies": [
"error",
{
"includeInternal": true,
"whitelist": ["@affine/component"]
}
]
}
},
{
"files": [
"packages/frontend/apps/electron/scripts/**/*",
"tests/blocksuite/**/*.{ts,tsx}",
"blocksuite/**/__tests__/**/*.{ts,tsx}"
],
"rules": {
"import-x-js/no-extraneous-dependencies": "off"
}
} }
] ]
} }
+1 -1
View File
@@ -1,4 +1,4 @@
# we will make this file shared by prettier|eslint|oxlint # shared by oxfmt|oxlint
**/node_modules **/node_modules
.yarn .yarn
.github/helm .github/helm
-6
View File
@@ -1,6 +0,0 @@
{
"singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2,
"arrowParens": "avoid"
}
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"recommendations": [ "recommendations": [
"ms-playwright.playwright", "ms-playwright.playwright",
"esbenp.prettier-vscode", "oxc.oxc-vscode",
"deepscan.vscode-deepscan", "deepscan.vscode-deepscan",
"streetsidesoftware.code-spell-checker" "streetsidesoftware.code-spell-checker"
] ]
+4 -6
View File
@@ -1,6 +1,6 @@
{ {
"prisma.pinToPrisma6": true, "prisma.pinToPrisma6": true,
"editor.defaultFormatter": "esbenp.prettier-vscode", "editor.defaultFormatter": "oxc.oxc-vscode",
"editor.formatOnSave": true, "editor.formatOnSave": true,
"editor.formatOnSaveMode": "file", "editor.formatOnSaveMode": "file",
"cSpell.words": [ "cSpell.words": [
@@ -17,10 +17,10 @@
"explorer.fileNesting.enabled": true, "explorer.fileNesting.enabled": true,
"explorer.fileNesting.patterns": { "explorer.fileNesting.patterns": {
"*.js": "${capture}.js.map, ${capture}.min.js, ${capture}.d.ts, ${capture}.d.ts.map", "*.js": "${capture}.js.map, ${capture}.min.js, ${capture}.d.ts, ${capture}.d.ts.map",
"package.json": ".browserslist*, .circleci*, .codecov, .commitlint*, .cz-config.js, .czrc, .dlint.json, .dprint.json, .editorconfig, .eslint*, eslint.*, .firebase*, .flowconfig, .github*, .gitlab*, .gitpod*, .huskyrc*, .jslint*, .lighthouserc.*, .lintstagedrc*, .markdownlint*, .mocha*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .releaserc*, .sentry*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .versionrc*, .vscode*, .watchman*, .xo-config*, .yamllint*, .yarnrc*, Procfile, api-extractor.json, apollo.config.*, appveyor*, ava.config.*, azure-pipelines*, bower.json, build.config.*, commitlint*, dangerfile*, dlint.json, dprint.json, firebase.json, grunt*, gulp*, histoire.config.*, jasmine.*, jenkins*, jest.config.*, jsconfig.*, karma*, lerna*, lighthouserc.*, lint-staged*, nest-cli.*, netlify*, nodemon*, nx.*, package-lock.json, package.nls*.json, phpcs.xml, playwright.config.*, pm2.*, pnpm*, prettier*, pullapprove*, puppeteer.config.*, pyrightconfig.json, release-tasks.sh, renovate*, rollup.config.*, stylelint*, tsconfig.*, tsdoc.*, tslint*, tsup.config.*, turbo*, typedoc*, unlighthouse*, vercel*, vetur.config.*, vitest.*, webpack*, workspace.json, xo.config.*, yarn*, babel.*, .babelrc, project.json, .oxlintrc.json, oxlint.json, nyc.config.*", "package.json": ".browserslist*, .circleci*, .codecov, .commitlint*, .cz-config.js, .czrc, .dlint.json, .dprint.json, .editorconfig, .firebase*, .flowconfig, .github*, .gitlab*, .gitpod*, .huskyrc*, .jslint*, .lighthouserc.*, .lintstagedrc*, .markdownlint*, .mocha*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .releaserc*, .sentry*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .versionrc*, .vscode*, .watchman*, .xo-config*, .yamllint*, .yarnrc*, Procfile, api-extractor.json, apollo.config.*, appveyor*, ava.config.*, azure-pipelines*, bower.json, build.config.*, commitlint*, dangerfile*, dlint.json, dprint.json, firebase.json, grunt*, gulp*, histoire.config.*, jasmine.*, jenkins*, jest.config.*, jsconfig.*, karma*, lerna*, lighthouserc.*, lint-staged*, nest-cli.*, netlify*, nodemon*, nx.*, package-lock.json, package.nls*.json, phpcs.xml, playwright.config.*, pm2.*, pnpm*, prettier*, pullapprove*, puppeteer.config.*, pyrightconfig.json, release-tasks.sh, renovate*, rollup.config.*, stylelint*, tsconfig.*, tsdoc.*, tslint*, tsup.config.*, turbo*, typedoc*, unlighthouse*, vercel*, vetur.config.*, vitest.*, webpack*, workspace.json, xo.config.*, yarn*, babel.*, .babelrc, project.json, .oxlintrc.json, oxlint.json, nyc.config.*",
"Cargo.toml": "Cargo.lock, rust-toolchain*, rustfmt.toml, .taplo.toml", "Cargo.toml": "Cargo.lock, rust-toolchain*, rustfmt.toml, .taplo.toml",
"README.md": "LICENSE*, CHANGELOG.md, CODE_OF_CONDUCT.md, CONTRIBUTING.md, SECURITY.md, README.*", "README.md": "LICENSE*, CHANGELOG.md, CODE_OF_CONDUCT.md, CONTRIBUTING.md, SECURITY.md, README.*",
".gitignore": ".gitattributes, .dockerignore, .eslintignore, .prettierignore, .stylelintignore, .tslintignore, .yarnignore" ".gitignore": ".gitattributes, .dockerignore, .prettierignore, .stylelintignore, .tslintignore, .yarnignore"
}, },
"[rust]": { "[rust]": {
"editor.defaultFormatter": "rust-lang.rust-analyzer" "editor.defaultFormatter": "rust-lang.rust-analyzer"
@@ -29,11 +29,9 @@
"editor.defaultFormatter": "tamasfe.even-better-toml" "editor.defaultFormatter": "tamasfe.even-better-toml"
}, },
"[typescriptreact]": { "[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "oxc.oxc-vscode"
}, },
"vitest.include": ["packages/**/*.spec.ts", "packages/**/*.spec.tsx"], "vitest.include": ["packages/**/*.spec.ts", "packages/**/*.spec.tsx"],
"eslint.runtime": "node",
"eslint.execArgv": ["--max_old_space_size=16384"],
"rust-analyzer.check.extraEnv": { "rust-analyzer.check.extraEnv": {
"DATABASE_URL": "sqlite:affine.db" "DATABASE_URL": "sqlite:affine.db"
}, },
@@ -0,0 +1,26 @@
diff --git a/dist/frameworks/i18next/generator/react-hooks.js b/dist/frameworks/i18next/generator/react-hooks.js
index ae1953ca1baceb09e587eda931567c8d8c5d671e..3bc918f6ff4f378e297d1fe927dcc90cf20c821e 100644
--- a/dist/frameworks/i18next/generator/react-hooks.js
+++ b/dist/frameworks/i18next/generator/react-hooks.js
@@ -99,7 +99,7 @@ export function i18NextReactHooksGenerator(gen) {
// Codegen
const printedSourceFile = [
gen.generatorOptions?.emitTS && '// @ts-nocheck',
- '/* eslint-disable */',
+ '/* oxlint-disable */',
printer.printFile(factory.createSourceFile(statements, factory.createToken(SyntaxKind.EndOfFileToken), NodeFlags.Synthesized)),
]
.filter(Boolean)
diff --git a/src/frameworks/i18next/generator/react-hooks.ts b/src/frameworks/i18next/generator/react-hooks.ts
index bbaf10a2b482e6118e786e634d15abab31c7ba32..a2dfd09ad422cb24c986d1a4ee3458197e70d5c2 100644
--- a/src/frameworks/i18next/generator/react-hooks.ts
+++ b/src/frameworks/i18next/generator/react-hooks.ts
@@ -203,7 +203,7 @@ export function i18NextReactHooksGenerator(gen: GenType) {
// Codegen
const printedSourceFile = [
gen.generatorOptions?.emitTS && '// @ts-nocheck',
- '/* eslint-disable */',
+ '/* oxlint-disable */',
printer.printFile(
factory.createSourceFile(statements, factory.createToken(SyntaxKind.EndOfFileToken), NodeFlags.Synthesized),
),
@@ -234,7 +234,8 @@ export class CalloutBlockComponent extends CaptionedBlockComponent<CalloutBlockM
backgroundColor: backgroundColor ?? 'transparent', backgroundColor: backgroundColor ?? 'transparent',
})} })}
> >
${iconContent ${
iconContent
? html` ? html`
<div <div
@click=${this._toggleIconPicker} @click=${this._toggleIconPicker}
@@ -244,12 +245,15 @@ export class CalloutBlockComponent extends CaptionedBlockComponent<CalloutBlockM
marginTop: this._getEmojiMarginTop(), marginTop: this._getEmojiMarginTop(),
})} })}
> >
<span class="${calloutEmojiStyles}" data-testid="callout-emoji" <span
class="${calloutEmojiStyles}"
data-testid="callout-emoji"
>${iconContent}</span >${iconContent}</span
> >
</div> </div>
` `
: ''} : ''
}
<div class="${calloutChildrenStyles}"> <div class="${calloutChildrenStyles}">
${this.renderChildren(this.model)} ${this.renderChildren(this.model)}
</div> </div>
@@ -489,9 +489,11 @@ export class CodeBlockComponent extends CaptionedBlockComponent<CodeBlockModel>
}} }}
> >
</rich-text> </rich-text>
${collapsed ${
collapsed
? html`<div class="code-collapsed-fade" aria-hidden="true"></div>` ? html`<div class="code-collapsed-fade" aria-hidden="true"></div>`
: nothing} : nothing
}
<div <div
style=${styleMap({ style=${styleMap({
display: shouldRenderPreview && !collapsed ? undefined : 'none', display: shouldRenderPreview && !collapsed ? undefined : 'none',
@@ -132,7 +132,8 @@ export class LinkCell extends BaseCellRenderer<string, string> {
return html` return html`
<div> <div>
<div class="${linkContainerStyle}"> <div class="${linkContainerStyle}">
${isDoc ${
isDoc
? html`<span class="${linkedDocStyle}" @click="${this.openDoc}" ? html`<span class="${linkedDocStyle}" @click="${this.openDoc}"
>${docName}</span >${docName}</span
>` >`
@@ -145,9 +146,11 @@ export class LinkCell extends BaseCellRenderer<string, string> {
target="_blank" target="_blank"
>${linkText}</a >${linkText}</a
>` >`
: html`<span class="${normalTextStyle}">${linkText}</span>`} : html`<span class="${normalTextStyle}">${linkText}</span>`
}
</div> </div>
${hasLink ${
hasLink
? html` <div class="${linkIconContainerStyle} ${showLinkIconStyle}"> ? html` <div class="${linkIconContainerStyle} ${showLinkIconStyle}">
<div <div
class="${linkIconStyle}" class="${linkIconStyle}"
@@ -157,7 +160,8 @@ export class LinkCell extends BaseCellRenderer<string, string> {
${EditIcon()} ${EditIcon()}
</div> </div>
</div>` </div>`
: nothing} : nothing
}
</div> </div>
`; `;
} }
@@ -427,7 +427,8 @@ export class EmbedLinkedDocBlockComponent extends EmbedBlockComponent<EmbedLinke
` `
) )
)} )}
${isError ${
isError
? html` ? html`
<div class="affine-embed-linked-doc-card-content-reload"> <div class="affine-embed-linked-doc-card-content-reload">
<div <div
@@ -444,16 +445,19 @@ export class EmbedLinkedDocBlockComponent extends EmbedBlockComponent<EmbedLinke
<span>${dateText}</span> <span>${dateText}</span>
</div> </div>
`} `
}
</div> </div>
${showDefaultBanner ${
showDefaultBanner
? html` ? html`
<div class="affine-embed-linked-doc-banner default"> <div class="affine-embed-linked-doc-banner default">
${defaultBanner} ${defaultBanner}
</div> </div>
` `
: nothing} : nothing
}
</div> </div>
` `
); );
@@ -202,14 +202,17 @@ export class EmbedSyncedDocCard extends WithDisposable(ShadowlessElement) {
</div> </div>
</div> </div>
${showDefaultNoteContent ${
showDefaultNoteContent
? html`<div class="affine-embed-synced-doc-content-note default"> ? html`<div class="affine-embed-synced-doc-content-note default">
${defaultNoteContent} ${defaultNoteContent}
</div>` </div>`
: nothing} : nothing
}
<div class="affine-embed-synced-doc-content-note render"></div> <div class="affine-embed-synced-doc-content-note render"></div>
${error ${
error
? html` ? html`
<div class="affine-embed-synced-doc-card-content-reload"> <div class="affine-embed-synced-doc-card-content-reload">
<div <div
@@ -226,18 +229,21 @@ export class EmbedSyncedDocCard extends WithDisposable(ShadowlessElement) {
<span>${dateText}</span> <span>${dateText}</span>
</div> </div>
`} `
}
</div> </div>
<div class="affine-embed-synced-doc-card-banner render"></div> <div class="affine-embed-synced-doc-card-banner render"></div>
${showDefaultBanner ${
showDefaultBanner
? html` ? html`
<div class="affine-embed-synced-doc-card-banner default"> <div class="affine-embed-synced-doc-card-banner default">
${defaultBanner} ${defaultBanner}
</div> </div>
` `
: nothing} : nothing
}
</div> </div>
`; `;
} }
@@ -123,7 +123,8 @@ export class EmbedEdgelessSyncedDocBlockComponent extends toEdgelessEmbedBlock(
${header} ${header}
</div> </div>
<div class="affine-embed-synced-doc-editor"> <div class="affine-embed-synced-doc-editor">
${this.isPageMode && this._isEmptySyncedDoc ${
this.isPageMode && this._isEmptySyncedDoc
? html` ? html`
<div class="affine-embed-synced-doc-editor-empty"> <div class="affine-embed-synced-doc-editor-empty">
<span> <span>
@@ -131,7 +132,8 @@ export class EmbedEdgelessSyncedDocBlockComponent extends toEdgelessEmbedBlock(
</span> </span>
</div> </div>
` `
: guard([editorMode, syncedDoc], renderEditor)} : guard([editorMode, syncedDoc], renderEditor)
}
</div> </div>
<div class="affine-embed-synced-doc-editor-overlay"></div> <div class="affine-embed-synced-doc-editor-overlay"></div>
</div> </div>
@@ -242,7 +242,8 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
?data-scale=${undefined} ?data-scale=${undefined}
> >
<div class="affine-embed-synced-doc-editor"> <div class="affine-embed-synced-doc-editor">
${isPageMode && this._isEmptySyncedDoc ${
isPageMode && this._isEmptySyncedDoc
? html` ? html`
<div class="affine-embed-synced-doc-editor-empty"> <div class="affine-embed-synced-doc-editor-empty">
<span> <span>
@@ -253,7 +254,8 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
: guard( : guard(
[editorMode, syncedDoc, appTheme, edgelessTheme], [editorMode, syncedDoc, appTheme, edgelessTheme],
renderEditor renderEditor
)} )
}
</div> </div>
<div <div
class=${classMap({ class=${classMap({
@@ -108,11 +108,13 @@ export class EmbedFigmaBlockComponent extends EmbedBlockComponent<EmbedFigmaMode
</div> </div>
</div> </div>
${description ${
description
? html`<div class="affine-embed-figma-content-description"> ? html`<div class="affine-embed-figma-content-description">
${description} ${description}
</div>` </div>`
: nothing} : nothing
}
<div class="affine-embed-figma-content-url" @click=${this.open}> <div class="affine-embed-figma-content-url" @click=${this.open}>
<span>www.figma.com</span> <span>www.figma.com</span>
@@ -183,7 +183,8 @@ export class EmbedGithubBlockComponent extends EmbedBlockComponent<
${titleIcon} ${titleIcon}
</div> </div>
${status && statusText ${
status && statusText
? html`<div ? html`<div
class=${classMap({ class=${classMap({
'affine-embed-github-content-title-status-icon': true, 'affine-embed-github-content-title-status-icon': true,
@@ -197,7 +198,8 @@ export class EmbedGithubBlockComponent extends EmbedBlockComponent<
<span>${statusText}</span> <span>${statusText}</span>
</div>` </div>`
: nothing} : nothing
}
</div> </div>
<div class="affine-embed-github-content-title-text"> <div class="affine-embed-github-content-title-text">
@@ -209,7 +211,8 @@ export class EmbedGithubBlockComponent extends EmbedBlockComponent<
${descriptionText} ${descriptionText}
</div> </div>
${githubType === 'issue' && assignees ${
githubType === 'issue' && assignees
? html` ? html`
<div class="affine-embed-github-content-assignees"> <div class="affine-embed-github-content-assignees">
<div <div
@@ -221,7 +224,8 @@ export class EmbedGithubBlockComponent extends EmbedBlockComponent<
<div <div
class="affine-embed-github-content-assignees-text users" class="affine-embed-github-content-assignees-text users"
> >
${assignees.length === 0 ${
assignees.length === 0
? html`<span ? html`<span
class="affine-embed-github-content-assignees-text-users placeholder" class="affine-embed-github-content-assignees-text-users placeholder"
>No one</span >No one</span
@@ -237,22 +241,26 @@ export class EmbedGithubBlockComponent extends EmbedBlockComponent<
>${`@${assignee}`}</span >${`@${assignee}`}</span
> >
${index === assignees.length - 1 ? '' : `, `}` ${index === assignees.length - 1 ? '' : `, `}`
)} )
}
</div> </div>
</div> </div>
` `
: nothing} : nothing
}
<div class="affine-embed-github-content-url" @click=${this.open}> <div class="affine-embed-github-content-url" @click=${this.open}>
<span class="affine-embed-github-content-repo" <span class="affine-embed-github-content-repo"
>${`${owner}/${repo} |`}</span >${`${owner}/${repo} |`}</span
> >
${createdAt ${
createdAt
? html`<span class="affine-embed-github-content-date" ? html`<span class="affine-embed-github-content-date"
>${dateText} |</span >${dateText} |</span
>` >`
: nothing} : nothing
}
<span>github.com</span> <span>github.com</span>
<div class="affine-embed-github-content-url-icon"> <div class="affine-embed-github-content-url-icon">
@@ -252,7 +252,8 @@ export class EmbedIframeErrorCard extends WithDisposable(LitElement) {
${this.error?.message || 'Failed to load embedded content'} ${this.error?.message || 'Failed to load embedded content'}
</div> </div>
<div class="error-info"> <div class="error-info">
${this.readonly ${
this.readonly
? nothing ? nothing
: html` : html`
<div class="button edit" @click=${this._toggleEdit}> <div class="button edit" @click=${this._toggleEdit}>
@@ -261,7 +262,8 @@ export class EmbedIframeErrorCard extends WithDisposable(LitElement) {
> >
<span class="text">Edit</span> <span class="text">Edit</span>
</div> </div>
`} `
}
<div class="button retry" @click=${this._handleRetry}> <div class="button retry" @click=${this._handleRetry}>
<span class="icon" <span class="icon"
>${ResetIcon({ width: '16px', height: '16px' })}</span >${ResetIcon({ width: '16px', height: '16px' })}</span
@@ -244,13 +244,15 @@ export class EmbedIframeLinkInputPopup extends EmbedIframeLinkInputBase {
return html` return html`
<div class=${modalMainWrapperClass}> <div class=${modalMainWrapperClass}>
${showCloseButton ${
showCloseButton
? html` ? html`
<div class="popup-close-button" @click=${this._onClose}> <div class="popup-close-button" @click=${this._onClose}>
${CloseIcon({ width: '20', height: '20' })} ${CloseIcon({ width: '20', height: '20' })}
</div> </div>
` `
: nothing} : nothing
}
<div class="link-input-popup-content-wrapper"> <div class="link-input-popup-content-wrapper">
<div class="title">${title}</div> <div class="title">${title}</div>
<div class="description">${description}</div> <div class="description">${description}</div>
@@ -392,9 +392,11 @@ export class EmbedIframeBlockComponent extends CaptionedBlockComponent<EmbedIfra
scrolling=${ifDefined(scrolling)} scrolling=${ifDefined(scrolling)}
style=${ifDefined(style)} style=${ifDefined(style)}
></iframe> ></iframe>
${sourceHost ${
sourceHost
? html`<div class="affine-embed-iframe-source">${sourceHost}</div>` ? html`<div class="affine-embed-iframe-source">${sourceHost}</div>`
: nothing}`; : nothing
}`;
}; };
private readonly _isIframeUrlAllowed = (iframeUrl: string) => { private readonly _isIframeUrlAllowed = (iframeUrl: string) => {
@@ -118,7 +118,8 @@ export class EmbedLoomBlockComponent extends EmbedBlockComponent<
@dblclick=${this._handleDoubleClick} @dblclick=${this._handleDoubleClick}
> >
<div class="affine-embed-loom-video"> <div class="affine-embed-loom-video">
${videoId ${
videoId
? html` ? html`
<div class="affine-embed-loom-video-iframe-container"> <div class="affine-embed-loom-video-iframe-container">
<iframe <iframe
@@ -139,7 +140,8 @@ export class EmbedLoomBlockComponent extends EmbedBlockComponent<
></div> ></div>
</div> </div>
` `
: bannerImage} : bannerImage
}
</div> </div>
<div class="affine-embed-loom-content"> <div class="affine-embed-loom-content">
<div class="affine-embed-loom-content-header"> <div class="affine-embed-loom-content-header">
@@ -134,7 +134,8 @@ export class EmbedYoutubeBlockComponent extends EmbedBlockComponent<
@dblclick=${this._handleDoubleClick} @dblclick=${this._handleDoubleClick}
> >
<div class="affine-embed-youtube-video"> <div class="affine-embed-youtube-video">
${videoId ${
videoId
? html` ? html`
<div class="affine-embed-youtube-video-iframe-container"> <div class="affine-embed-youtube-video-iframe-container">
<iframe <iframe
@@ -167,7 +168,8 @@ export class EmbedYoutubeBlockComponent extends EmbedBlockComponent<
/> />
</div> </div>
` `
: bannerImage} : bannerImage
}
</div> </div>
<div class="affine-embed-youtube-content"> <div class="affine-embed-youtube-content">
<div class="affine-embed-youtube-content-header"> <div class="affine-embed-youtube-content-header">
@@ -188,7 +190,8 @@ export class EmbedYoutubeBlockComponent extends EmbedBlockComponent<
</div> </div>
</div> </div>
${loading ${
loading
? html`<div ? html`<div
class="affine-embed-youtube-content-description" class="affine-embed-youtube-content-description"
></div>` ></div>`
@@ -196,7 +199,8 @@ export class EmbedYoutubeBlockComponent extends EmbedBlockComponent<
? html`<div class="affine-embed-youtube-content-description"> ? html`<div class="affine-embed-youtube-content-description">
${descriptionText} ${descriptionText}
</div>` </div>`
: nothing} : nothing
}
<div class="affine-embed-youtube-content-url" @click=${this.open}> <div class="affine-embed-youtube-content-url" @click=${this.open}>
<span>www.youtube.com</span> <span>www.youtube.com</span>
@@ -25,12 +25,14 @@ export class EdgelessFrameToolButton extends QuickToolMixin(LitElement) {
return html` return html`
<edgeless-tool-icon-button <edgeless-tool-icon-button
class="edgeless-frame-button" class="edgeless-frame-button"
.tooltip=${this.popper .tooltip=${
this.popper
? '' ? ''
: html`<affine-tooltip-content-with-shortcut : html`<affine-tooltip-content-with-shortcut
data-tip="${'Frame'}" data-tip="${'Frame'}"
data-shortcut="${'F'}" data-shortcut="${'F'}"
></affine-tooltip-content-with-shortcut>`} ></affine-tooltip-content-with-shortcut>`
}
.tooltipOffset=${17} .tooltipOffset=${17}
.iconSize=${'24px'} .iconSize=${'24px'}
.active=${type === 'frame'} .active=${type === 'frame'}
@@ -407,7 +407,8 @@ export class PresentationToolbar extends EdgelessToolbarToolMixin(
</edgeless-tool-icon-button> </edgeless-tool-icon-button>
<div class="edgeless-frame-navigator ${this.dense ? 'dense' : ''}"> <div class="edgeless-frame-navigator ${this.dense ? 'dense' : ''}">
${this.dense ${
this.dense
? nothing ? nothing
: html`<span : html`<span
style="color: ${cssVar('textPrimaryColor')}" style="color: ${cssVar('textPrimaryColor')}"
@@ -415,7 +416,8 @@ export class PresentationToolbar extends EdgelessToolbarToolMixin(
@click=${() => this._moveToCurrentFrame()} @click=${() => this._moveToCurrentFrame()}
> >
${frame?.props.title ?? 'no frame'} ${frame?.props.title ?? 'no frame'}
</span>`} </span>`
}
<span class="edgeless-frame-navigator-count"> <span class="edgeless-frame-navigator-count">
${frames.length === 0 ? 0 : current + 1} / ${frames.length} ${frames.length === 0 ? 0 : current + 1} / ${frames.length}
@@ -435,9 +437,11 @@ export class PresentationToolbar extends EdgelessToolbarToolMixin(
<div class="config-buttons"> <div class="config-buttons">
<edgeless-tool-icon-button <edgeless-tool-icon-button
.tooltip=${document.fullscreenElement .tooltip=${
document.fullscreenElement
? 'Exit Full Screen' ? 'Exit Full Screen'
: 'Enter Full Screen'} : 'Enter Full Screen'
}
@click=${() => this._toggleFullScreen()} @click=${() => this._toggleFullScreen()}
.iconContainerPadding=${0} .iconContainerPadding=${0}
.iconContainerWidth=${'24px'} .iconContainerWidth=${'24px'}
@@ -446,14 +450,16 @@ export class PresentationToolbar extends EdgelessToolbarToolMixin(
${document.fullscreenElement ? ExpandCloseIcon() : ExpandFullIcon()} ${document.fullscreenElement ? ExpandCloseIcon() : ExpandFullIcon()}
</edgeless-tool-icon-button> </edgeless-tool-icon-button>
${this.dense ${
this.dense
? nothing ? nothing
: html`<edgeless-frame-order-button : html`<edgeless-frame-order-button
.popperShow=${this.frameMenuShow} .popperShow=${this.frameMenuShow}
.setPopperShow=${this.setFrameMenuShow} .setPopperShow=${this.setFrameMenuShow}
.edgeless=${this.edgeless} .edgeless=${this.edgeless}
> >
</edgeless-frame-order-button>`} </edgeless-frame-order-button>`
}
<edgeless-navigator-setting-button <edgeless-navigator-setting-button
.edgeless=${this.edgeless} .edgeless=${this.edgeless}
@@ -218,9 +218,9 @@ export class EdgelessFrameOrderMenu extends SignalWatcher(
return html` return html`
<div <div
class="edgeless-frame-order-items-container ${this.embed class="edgeless-frame-order-items-container ${
? 'embed' this.embed ? 'embed' : ''
: ''}" }"
@click=${(e: MouseEvent) => e.stopPropagation()} @click=${(e: MouseEvent) => e.stopPropagation()}
> >
${repeat( ${repeat(
@@ -235,11 +235,13 @@ export class EdgelessFrameOrderMenu extends SignalWatcher(
)} )}
<div class="indicator-line"></div> <div class="indicator-line"></div>
<div class="clone item"> <div class="clone item">
${frame ${
frame
? html`<div class="drag-indicator"></div> ? html`<div class="drag-indicator"></div>
<div class="index">${this._curIndex + 1}</div> <div class="index">${this._curIndex + 1}</div>
<div class="title">${frame.props.title.toString()}</div>` <div class="title">${frame.props.title.toString()}</div>`
: nothing} : nothing
}
</div> </div>
</div> </div>
`; `;
@@ -150,7 +150,8 @@ export class EdgelessNavigatorSettingButton extends WithDisposable(LitElement) {
</toggle-switch> </toggle-switch>
</div> </div>
${this.includeFrameOrder ${
this.includeFrameOrder
? html` <div class="divider"></div> ? html` <div class="divider"></div>
<div class="item-container header"> <div class="item-container header">
<div class="text title">Frame Order</div> <div class="text title">Frame Order</div>
@@ -160,7 +161,8 @@ export class EdgelessNavigatorSettingButton extends WithDisposable(LitElement) {
.edgeless=${this.edgeless} .edgeless=${this.edgeless}
.embed=${true} .embed=${true}
></edgeless-frame-order-menu>` ></edgeless-frame-order-menu>`
: nothing} : nothing
}
</div> </div>
`; `;
} }
@@ -174,7 +174,8 @@ export class ListBlockComponent extends CaptionedBlockComponent<ListBlockModel>
[TOGGLE_BUTTON_PARENT_CLASS]: true, [TOGGLE_BUTTON_PARENT_CLASS]: true,
})} })}
> >
${this.model.children.length > 0 ${
this.model.children.length > 0
? html` ? html`
<blocksuite-toggle-button <blocksuite-toggle-button
.collapsed=${collapsed} .collapsed=${collapsed}
@@ -190,7 +191,8 @@ export class ListBlockComponent extends CaptionedBlockComponent<ListBlockModel>
}} }}
></blocksuite-toggle-button> ></blocksuite-toggle-button>
` `
: nothing} : nothing
}
${listIcon} ${listIcon}
<rich-text <rich-text
.yText=${this.model.props.text.yText} .yText=${this.model.props.text.yText}
@@ -58,9 +58,11 @@ export function getListIcon(
class=${`affine-list-block__prefix affine-list-block__todo-prefix ${model.store.readonly ? 'readonly' : ''}`} class=${`affine-list-block__prefix affine-list-block__todo-prefix ${model.store.readonly ? 'readonly' : ''}`}
@click=${onClick} @click=${onClick}
> >
${model.props.checked ${
model.props.checked
? CheckBoxCheckSolidIcon({ style: 'color: #1E96EB' }) ? CheckBoxCheckSolidIcon({ style: 'color: #1E96EB' })
: CheckBoxUnIcon()} : CheckBoxUnIcon()
}
</div>`; </div>`;
case 'toggle': case 'toggle':
return html`<div return html`<div
@@ -322,7 +322,8 @@ export class EdgelessNoteBlockComponent extends toGfxBlockComponent(
.editing=${this._editing} .editing=${this._editing}
></edgeless-note-mask> ></edgeless-note-mask>
${isCollapsable && ${
isCollapsable &&
tool.currentToolName$.value !== 'frameNavigator' && tool.currentToolName$.value !== 'frameNavigator' &&
(!this.model.isPageBlock() || !hasHeader) (!this.model.isPageBlock() || !hasHeader)
? html`<div ? html`<div
@@ -340,7 +341,8 @@ export class EdgelessNoteBlockComponent extends toGfxBlockComponent(
> >
${MoreIndicator} ${MoreIndicator}
</div>` </div>`
: nothing} : nothing
}
${this._collapsedContent()} ${this._collapsedContent()}
</div> </div>
`; `;
@@ -304,14 +304,17 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent<ParagraphBl
[TOGGLE_BUTTON_PARENT_CLASS]: true, [TOGGLE_BUTTON_PARENT_CLASS]: true,
})} })}
> >
${this.model.props.type$.value.startsWith('h') ${
this.model.props.type$.value.startsWith('h')
? html` ? html`
<affine-paragraph-heading-icon <affine-paragraph-heading-icon
.model=${this.model} .model=${this.model}
></affine-paragraph-heading-icon> ></affine-paragraph-heading-icon>
` `
: nothing} : nothing
${this.model.props.type$.value.startsWith('h') && }
${
this.model.props.type$.value.startsWith('h') &&
collapsedSiblings.length > 0 collapsedSiblings.length > 0
? html` ? html`
<blocksuite-toggle-button <blocksuite-toggle-button
@@ -335,7 +338,8 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent<ParagraphBl
}} }}
></blocksuite-toggle-button> ></blocksuite-toggle-button>
` `
: nothing} : nothing
}
<rich-text <rich-text
.yText=${this.model.props.text.yText} .yText=${this.model.props.text.yText}
.inlineEventSource=${this.topContenteditableElement ?? nothing} .inlineEventSource=${this.topContenteditableElement ?? nothing}
@@ -351,7 +355,8 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent<ParagraphBl
.verticalScrollContainerGetter=${() => .verticalScrollContainerGetter=${() =>
getViewportElement(this.host)} getViewportElement(this.host)}
></rich-text> ></rich-text>
${this.inEdgelessText ${
this.inEdgelessText
? nothing ? nothing
: html` : html`
<div <div
@@ -363,7 +368,8 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent<ParagraphBl
> >
${this._placeholder} ${this._placeholder}
</div> </div>
`} `
}
</div> </div>
${children} ${widgets} ${children} ${widgets}
@@ -544,7 +544,7 @@ export class EdgelessClipboardController extends PageClipboard {
} }
}); });
// oxlint-disable-next-line @typescript-eslint/prefer-for-of // oxlint-disable-next-line typescript/prefer-for-of
for (let i = 0; i < blocksInsideFrame.length; i++) { for (let i = 0; i < blocksInsideFrame.length; i++) {
const element = blocksInsideFrame[i]; const element = blocksInsideFrame[i];
await _drawTopLevelBlock(element, true); await _drawTopLevelBlock(element, true);
@@ -645,7 +645,7 @@ export class EdgelessClipboardController extends PageClipboard {
); );
}); });
} else { } else {
// oxlint-disable-next-line @typescript-eslint/prefer-for-of // oxlint-disable-next-line typescript/prefer-for-of
for (let index = 0; index < content.length; index++) { for (let index = 0; index < content.length; index++) {
const blockSnapshot = content[index]; const blockSnapshot = content[index];
if (blockSnapshot.flavour === 'affine:note') { if (blockSnapshot.flavour === 'affine:note') {
@@ -99,24 +99,30 @@ export class SurfaceRefPlaceHolder extends SignalWatcher(
'not-found': modelNotFound, 'not-found': modelNotFound,
})} })}
> >
${modelNotFound ${
modelNotFound
? html`<div class="surface-ref-not-found-background"> ? html`<div class="surface-ref-not-found-background">
${notFoundBackground} ${notFoundBackground}
</div>` </div>`
: nothing} : nothing
}
<div class="surface-ref-placeholder-heading"> <div class="surface-ref-placeholder-heading">
${modelNotFound ? DeleteIcon() : matchedType.icon} ${modelNotFound ? DeleteIcon() : matchedType.icon}
<span class="surface-ref-title"> <span class="surface-ref-title">
${modelNotFound ${
modelNotFound
? `This ${matchedType.name} not available` ? `This ${matchedType.name} not available`
: `${title}`} : `${title}`
}
</span> </span>
</div> </div>
<div class="surface-ref-placeholder-body"> <div class="surface-ref-placeholder-body">
<span class="surface-ref-text"> <span class="surface-ref-text">
${modelNotFound ${
modelNotFound
? `The ${matchedType.name.toLowerCase()} is deleted or not in this doc.` ? `The ${matchedType.name.toLowerCase()} is deleted or not in this doc.`
: `The ${matchedType.name.toLowerCase()} is inserted but cannot display in edgeless mode. Switch to page mode to view the block.`} : `The ${matchedType.name.toLowerCase()} is inserted but cannot display in edgeless mode. Switch to page mode to view the block.`
}
</span> </span>
</div> </div>
</div> </div>
@@ -1,4 +1,4 @@
// oxlint-disable-next-line @typescript-eslint/triple-slash-reference // oxlint-disable-next-line typescript/triple-slash-reference
/// <reference path="./effects.ts" /> /// <reference path="./effects.ts" />
export * from './consts.js'; export * from './consts.js';
export { GRID_GAP_MAX, GRID_GAP_MIN } from './consts.js'; export { GRID_GAP_MAX, GRID_GAP_MIN } from './consts.js';
@@ -281,7 +281,7 @@ export class DefaultTool extends BaseTool {
} }
} }
// oxlint-disable-next-line @typescript-eslint/no-misused-promises // oxlint-disable-next-line typescript/no-misused-promises
override async dragStart(e: PointerEventState) { override async dragStart(e: PointerEventState) {
const { preventDefaultState, handledByView } = const { preventDefaultState, handledByView } =
this.interactivity?.dispatchEvent('dragstart', e) ?? {}; this.interactivity?.dispatchEvent('dragstart', e) ?? {};
@@ -153,7 +153,7 @@ export class AStarRunner {
} }
const neighbors = this._neighbors(current); const neighbors = this._neighbors(current);
// oxlint-disable-next-line @typescript-eslint/prefer-for-of // oxlint-disable-next-line typescript/prefer-for-of
for (let i = 0; i < neighbors.length; i++) { for (let i = 0; i < neighbors.length; i++) {
const next = neighbors[i]; const next = neighbors[i];
const curCosts = this._costSoFar.get(current); const curCosts = this._costSoFar.get(current);
@@ -268,12 +268,14 @@ export class TableBlockComponent extends CaptionedBlockComponent<TableBlockModel
} }
)} )}
</tbody> </tbody>
${IS_MOBILE || this.dataManager.readonly$.value ${
IS_MOBILE || this.dataManager.readonly$.value
? nothing ? nothing
: html`<affine-table-add-button : html`<affine-table-add-button
style="display: contents;" style="display: contents;"
.dataManager=${this.dataManager} .dataManager=${this.dataManager}
></affine-table-add-button>`} ></affine-table-add-button>`
}
${html`<affine-table-selection-layer ${html`<affine-table-selection-layer
style="display: contents;" style="display: contents;"
.selectionController=${this.selectionController} .selectionController=${this.selectionController}
@@ -138,9 +138,9 @@ export class TableCell extends SignalWatcher(
].map(item => ].map(item =>
menu.action({ menu.action({
prefix: html`<div prefix: html`<div
style="color: ${item.color ?? style="color: ${
cssVarV2.layer.background item.color ?? cssVarV2.layer.background.primary
.primary};display: flex;align-items: center;justify-content: center;" };display: flex;align-items: center;justify-content: center;"
> >
${TextBackgroundDuotoneIcon} ${TextBackgroundDuotoneIcon}
</div>`, </div>`,
@@ -264,9 +264,9 @@ export class TableCell extends SignalWatcher(
].map(item => ].map(item =>
menu.action({ menu.action({
prefix: html`<div prefix: html`<div
style="color: ${item.color ?? style="color: ${
cssVarV2.layer.background item.color ?? cssVarV2.layer.background.primary
.primary};display: flex;align-items: center;justify-content: center;" };display: flex;align-items: center;justify-content: center;"
> >
${TextBackgroundDuotoneIcon} ${TextBackgroundDuotoneIcon}
</div>`, </div>`,
@@ -376,9 +376,9 @@ export class TableCell extends SignalWatcher(
items: [{ name: 'Default', color: undefined }, ...colorList].map(item => items: [{ name: 'Default', color: undefined }, ...colorList].map(item =>
menu.action({ menu.action({
prefix: html`<div prefix: html`<div
style="color: ${item.color ?? style="color: ${
cssVarV2.layer.background item.color ?? cssVarV2.layer.background.primary
.primary};display: flex;align-items: center;justify-content: center;" };display: flex;align-items: center;justify-content: center;"
> >
${TextBackgroundDuotoneIcon} ${TextBackgroundDuotoneIcon}
</div>`, </div>`,
@@ -418,7 +418,7 @@ export class TableCell extends SignalWatcher(
name: 'Paste', name: 'Paste',
prefix: PasteIcon(), prefix: PasteIcon(),
select: () => { select: () => {
// oxlint-disable-next-line @typescript-eslint/no-floating-promises // oxlint-disable-next-line typescript/no-floating-promises
navigator.clipboard.readText().then(text => { navigator.clipboard.readText().then(text => {
this.selectionController.doPaste(text, selected); this.selectionController.doPaste(text, selected);
}); });
@@ -501,12 +501,16 @@ export class TableCell extends SignalWatcher(
return nothing; return nothing;
} }
return html` return html`
${this.rowIndex === 0 ${
this.rowIndex === 0
? this.renderColumnOptions(this.column, this.columnIndex) ? this.renderColumnOptions(this.column, this.columnIndex)
: nothing} : nothing
${this.columnIndex === 0 }
${
this.columnIndex === 0
? this.renderRowOptions(this.row, this.rowIndex) ? this.renderRowOptions(this.row, this.rowIndex)
: nothing} : nothing
}
`; `;
} }
@@ -53,19 +53,25 @@ export class CaptionedBlockComponent<
})} })}
> >
${content} ${content}
${this.useCaptionEditor ${
this.useCaptionEditor
? html`<block-caption-editor ? html`<block-caption-editor
${ref(this._captionEditorRef)} ${ref(this._captionEditorRef)}
></block-caption-editor>` ></block-caption-editor>`
: nothing} : nothing
${this.selectedStyle === SelectedStyle.Background }
${
this.selectedStyle === SelectedStyle.Background
? html`<affine-block-selection ? html`<affine-block-selection
.selected=${watch(this.selected$)} .selected=${watch(this.selected$)}
></affine-block-selection>` ></affine-block-selection>`
: null} : null
${this.useZeroWidth && !this.store.readonly }
${
this.useZeroWidth && !this.store.readonly
? html`<block-zero-width .block=${this}></block-zero-width>` ? html`<block-zero-width .block=${this}></block-zero-width>`
: nothing} : nothing
}
</div>`; </div>`;
} }
@@ -126,19 +126,23 @@ export class CitationCard extends SignalWatcher(WithDisposable(LitElement)) {
@dblclick=${this.onDoubleClickCallback} @dblclick=${this.onDoubleClickCallback}
> >
<div class="citation-header"> <div class="citation-header">
${this.icon ${
this.icon
? html`<div class="citation-icon"> ? html`<div class="citation-icon">
${this._IconTemplate(this.icon)} ${this._IconTemplate(this.icon)}
</div>` </div>`
: nothing} : nothing
}
<div class="citation-title">${this.citationTitle}</div> <div class="citation-title">${this.citationTitle}</div>
<div class=${citationIdentifierClasses}> <div class=${citationIdentifierClasses}>
${this.citationIdentifier} ${this.citationIdentifier}
</div> </div>
</div> </div>
${this.citationContent ${
this.citationContent
? html`<div class="citation-content">${this.citationContent}</div>` ? html`<div class="citation-content">${this.citationContent}</div>`
: nothing} : nothing
}
</div> </div>
`; `;
} }
@@ -250,9 +250,11 @@ export const menuButtonItems = {
} }
const data: MenuButtonData = { const data: MenuButtonData = {
content: () => html` content: () => html`
${config.checked.value ${
config.checked.value
? CheckBoxCheckSolidIcon({ style: `color:#1E96EB` }) ? CheckBoxCheckSolidIcon({ style: `color:#1E96EB` })
: CheckBoxUnIcon()} : CheckBoxUnIcon()
}
<div class="affine-menu-action-text"> <div class="affine-menu-action-text">
${config.label?.() ?? config.name} ${config.label?.() ?? config.name}
</div> </div>
@@ -24,11 +24,13 @@ export const menuGroupItems = {
${items} ${items}
</div>`; </div>`;
} }
const result: TemplateResult = html` ${index === 0 const result: TemplateResult = html` ${
index === 0
? '' ? ''
: html` <div : html` <div
style="height: 0.5px;background-color: var(--affine-divider-color);margin: 4px 0" style="height: 0.5px;background-color: var(--affine-divider-color);margin: 4px 0"
></div>`} ></div>`
}
<div style="display: flex;flex-direction: column;gap:4px">${items}</div>`; <div style="display: flex;flex-direction: column;gap:4px">${items}</div>`;
return result; return result;
}, },
@@ -165,9 +165,11 @@ export class MenuComponent
return html` return html`
${this.renderTitle()} ${this.renderSearch()} ${this.renderTitle()} ${this.renderSearch()}
<div class="affine-menu-body"> <div class="affine-menu-body">
${result.length === 0 && this.menu.enableSearch ${
result.length === 0 && this.menu.enableSearch
? html` <div class="no-results">No Results</div>` ? html` <div class="no-results">No Results</div>`
: ''} : ''
}
${result} ${result}
</div> </div>
`; `;
@@ -213,7 +215,8 @@ export class MenuComponent
style="display:flex;align-items:center;gap: 4px;padding:3px 4px 3px 2px" style="display:flex;align-items:center;gap: 4px;padding:3px 4px 3px 2px"
@mouseenter="${() => this.menu.closeSubMenu()}" @mouseenter="${() => this.menu.closeSubMenu()}"
> >
${title.onBack ${
title.onBack
? html` <div ? html` <div
@click="${() => { @click="${() => {
const result = title.onBack?.(this.menu); const result = title.onBack?.(this.menu);
@@ -226,14 +229,16 @@ export class MenuComponent
> >
${ArrowLeftBigIcon()} ${ArrowLeftBigIcon()}
</div>` </div>`
: nothing} : nothing
}
<div <div
style="flex:1;font-weight:500;font-size: 14px;line-height: 22px;color: var(--affine-text-primary-color)" style="flex:1;font-weight:500;font-size: 14px;line-height: 22px;color: var(--affine-text-primary-color)"
> >
${title.text} ${title.text}
</div> </div>
${title.postfix?.()} ${title.postfix?.()}
${title.onClose ${
title.onClose
? html` <div ? html` <div
@click="${title.onClose}" @click="${title.onClose}"
class="dv-icon-20 dv-hover dv-pd-2 dv-round-4" class="dv-icon-20 dv-hover dv-pd-2 dv-round-4"
@@ -241,7 +246,8 @@ export class MenuComponent
> >
${CloseIcon()} ${CloseIcon()}
</div>` </div>`
: nothing} : nothing
}
</div> </div>
`; `;
} }
@@ -323,7 +329,8 @@ export class MobileMenuComponent
@mouseenter="${() => this.menu.closeSubMenu()}" @mouseenter="${() => this.menu.closeSubMenu()}"
> >
<div style="width: 50px;flex-shrink: 0;margin-left: 10px;"> <div style="width: 50px;flex-shrink: 0;margin-left: 10px;">
${title?.onBack ${
title?.onBack
? html` <div ? html` <div
@click="${() => { @click="${() => {
title.onBack?.(this.menu); title.onBack?.(this.menu);
@@ -337,7 +344,8 @@ export class MobileMenuComponent
> >
${ArrowLeftSmallIcon()} ${ArrowLeftSmallIcon()}
</div>` </div>`
: nothing} : nothing
}
</div> </div>
<div <div
style=" style="
@@ -149,7 +149,7 @@ export class Menu {
renderItems(items: MenuConfig[]) { renderItems(items: MenuConfig[]) {
const result = []; const result = [];
// oxlint-disable-next-line @typescript-eslint/prefer-for-of // oxlint-disable-next-line typescript/prefer-for-of
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
const item = items[i]; const item = items[i];
const template = item(this, result.length); const template = item(this, result.length);
@@ -178,7 +178,8 @@ export class DatePicker extends WithDisposable(LitElement) {
</div>` </div>`
)} )}
</div> </div>
${this.onClear ${
this.onClear
? html`<div class="date-picker-footer"> ? html`<div class="date-picker-footer">
<button <button
tabindex="0" tabindex="0"
@@ -189,7 +190,8 @@ export class DatePicker extends WithDisposable(LitElement) {
Clear Clear
</button> </button>
</div>` </div>`
: nothing}`; : nothing
}`;
} }
/** Week header */ /** Week header */
@@ -40,9 +40,8 @@ export const LoadingIcon = ({
stroke="${strokeColor}" stroke="${strokeColor}"
stroke-width="4" stroke-width="4"
stroke-linecap="round" stroke-linecap="round"
stroke-dasharray="${2 * Math.PI * 8 * progress} ${2 * stroke-dasharray="${2 * Math.PI * 8 * progress} ${
Math.PI * 2 * Math.PI * 8 * (1 - progress)
8 * }"
(1 - progress)}"
/> />
</svg>`; </svg>`;
@@ -40,7 +40,7 @@ export interface PeekViewService {
* @returns A promise that resolves when the peek view is closed. * @returns A promise that resolves when the peek view is closed.
*/ */
peek( peek(
// oxlint-disable-next-line @typescript-eslint/unified-signatures // oxlint-disable-next-line typescript/unified-signatures
element: { target: HTMLElement; template?: TemplateResult }, element: { target: HTMLElement; template?: TemplateResult },
options?: PeekOptions options?: PeekOptions
): Promise<void>; ): Promise<void>;
@@ -161,8 +161,9 @@ export class SizeDropdownMenu extends SignalWatcher(
.labelHeight="${'20px'}" .labelHeight="${'20px'}"
.iconContainerWidth="${icon ? 'unset' : '65px'}" .iconContainerWidth="${icon ? 'unset' : '65px'}"
> >
${icon ?? ${
html`<span class="label">${format?.(size) ?? size}</span>`} icon ?? html`<span class="label">${format?.(size) ?? size}</span>`
}
${EditorChevronDown} ${EditorChevronDown}
</editor-icon-button> </editor-icon-button>
`} `}
@@ -151,9 +151,11 @@ export class Slider extends WithDisposable(LitElement) {
<div class="drag-handle"></div> <div class="drag-handle"></div>
<div class="bottom-line"></div> <div class="bottom-line"></div>
<div class="slider-selected-overlay"></div> <div class="slider-selected-overlay"></div>
${this.tooltip ${
this.tooltip
? html`<affine-tooltip .offset=${8}>${this.tooltip}</affine-tooltip>` ? html`<affine-tooltip .offset=${8}>${this.tooltip}</affine-tooltip>`
: nothing} : nothing
}
</div>`; </div>`;
} }
} }
@@ -83,9 +83,11 @@ export function renderActions(
?disabled=${item.disabled} ?disabled=${item.disabled}
@click=${item.action ? item.action : () => action?.(item)} @click=${item.action ? item.action : () => action?.(item)}
> >
${item.icon}${item.label ${item.icon}${
item.label
? html`<span class="label">${item.label}</span>` ? html`<span class="label">${item.label}</span>`
: nothing} : nothing
}
</editor-menu-action> </editor-menu-action>
` `
) )
@@ -237,13 +237,15 @@ export class Tooltip extends LitElement {
${unsafeCSS(this.style.cssText)} ${unsafeCSS(this.style.cssText)}
} }
${this.allowInteractive ${
this.allowInteractive
? css`` ? css``
: css` : css`
:host { :host {
pointer-events: none; pointer-events: none;
} }
`} `
}
${this.tooltipStyle} ${this.tooltipStyle}
`; `;
@@ -29,9 +29,11 @@ export const typeConfig = (property: Property) => {
style="color: var(--affine-text-secondary-color);gap:4px;font-size: 14px;" style="color: var(--affine-text-secondary-color);gap:4px;font-size: 14px;"
> >
${renderUniLit(property.icon)} ${renderUniLit(property.icon)}
${property.view.propertyMetas$.value.find( ${
property.view.propertyMetas$.value.find(
v => v.type === property.type$.value v => v.type === property.type$.value
)?.config.name} )?.config.name
}
</div>`, </div>`,
options: { options: {
title: { title: {
@@ -361,11 +361,13 @@ export class MultiTagSelect extends SignalWatcher(
}); });
return html` <div class="${tagContainerStyle}" style=${style}> return html` <div class="${tagContainerStyle}" style=${style}>
<div data-testid="tag-name" class="${tagTextStyle}">${name}</div> <div data-testid="tag-name" class="${tagTextStyle}">${name}</div>
${onDelete ${
onDelete
? html` <div class="${tagDeleteIconStyle}" @click="${onDelete}"> ? html` <div class="${tagDeleteIconStyle}" @click="${onDelete}">
${CloseIcon()} ${CloseIcon()}
</div>` </div>`
: nothing} : nothing
}
</div>`; </div>`;
} }
@@ -402,7 +404,8 @@ export class MultiTagSelect extends SignalWatcher(
@click="${select.select}" @click="${select.select}"
> >
<div class="${selectOptionContentStyle}"> <div class="${selectOptionContentStyle}">
${select.isCreate ${
select.isCreate
? html` <div class="${selectOptionNewIconStyle}"> ? html` <div class="${selectOptionNewIconStyle}">
Create Create
</div>` </div>`
@@ -411,10 +414,12 @@ export class MultiTagSelect extends SignalWatcher(
${dragHandler(select.id)} ${dragHandler(select.id)}
class="${selectOptionDragHandlerStyle}" class="${selectOptionDragHandlerStyle}"
></div> ></div>
`} `
}
${this.renderTag(select.value, select.color)} ${this.renderTag(select.value, select.color)}
</div> </div>
${!select.isCreate ${
!select.isCreate
? html` <div ? html` <div
class="${selectOptionIconStyle}" class="${selectOptionIconStyle}"
@click="${clickOption}" @click="${clickOption}"
@@ -422,7 +427,8 @@ export class MultiTagSelect extends SignalWatcher(
> >
${MoreHorizontalIcon()} ${MoreHorizontalIcon()}
</div>` </div>`
: null} : null
}
</div> </div>
`; `;
} }
@@ -586,9 +592,13 @@ const popMobileTagSelect = (target: PopupTarget, ops: TagSelectOptions) => {
}); });
return html` return html`
<div style="display: flex; align-items:center;"> <div style="display: flex; align-items:center;">
${option.isCreate ${
? html` <div style="margin-right: 8px;">Create</div>` option.isCreate
: ''} ? html` <div style="margin-right: 8px;">
Create
</div>`
: ''
}
<div class="${tagContainerStyle}" style=${style}> <div class="${tagContainerStyle}" style=${style}>
<div class="${tagTextStyle}">${option.value}</div> <div class="${tagTextStyle}">${option.value}</div>
</div> </div>
@@ -256,7 +256,8 @@ export class RecordDetail extends SignalWatcher(
); );
} }
)} )}
${!this.readonly ${
!this.readonly
? html` <div ? html` <div
class="add-property" class="add-property"
@click="${this._clickAddProperty}" @click="${this._clickAddProperty}"
@@ -264,7 +265,8 @@ export class RecordDetail extends SignalWatcher(
<div class="icon">${PlusIcon()}</div> <div class="icon">${PlusIcon()}</div>
Add Property Add Property
</div>` </div>`
: nothing} : nothing
}
</div> </div>
${keyed(this.rowId, this.renderNote())} ${keyed(this.rowId, this.renderNote())}
</div> </div>
@@ -96,7 +96,8 @@ const GroupTitleMobile = (
${icon} ${renderUniLit(groupData.view, props)} ${columnName} ${icon} ${renderUniLit(groupData.view, props)} ${columnName}
${GroupHeaderCount(groupData)} ${GroupHeaderCount(groupData)}
</div> </div>
${ops.readonly ${
ops.readonly
? nothing ? nothing
: html` <div class="group-header-ops"> : html` <div class="group-header-ops">
<div @click="${ops.clickAdd}" class="group-header-op add-card"> <div @click="${ops.clickAdd}" class="group-header-op add-card">
@@ -105,7 +106,8 @@ const GroupTitleMobile = (
<div @click="${ops.clickOps}" class="group-header-op"> <div @click="${ops.clickOps}" class="group-header-op">
${MoreHorizontalIcon()} ${MoreHorizontalIcon()}
</div> </div>
</div>`} </div>`
}
`; `;
}; };
@@ -211,7 +213,8 @@ export const GroupTitle = (
${icon} ${renderUniLit(groupData.view, props)} ${columnName} ${icon} ${renderUniLit(groupData.view, props)} ${columnName}
${GroupHeaderCount(groupData)} ${GroupHeaderCount(groupData)}
</div> </div>
${ops.readonly ${
ops.readonly
? nothing ? nothing
: html` <div class="group-header-ops"> : html` <div class="group-header-ops">
<div @click="${ops.clickAdd}" class="group-header-op add-card"> <div @click="${ops.clickAdd}" class="group-header-op add-card">
@@ -220,6 +223,7 @@ export const GroupTitle = (
<div @click="${ops.clickOps}" class="group-header-op"> <div @click="${ops.clickOps}" class="group-header-op">
${MoreHorizontalIcon()} ${MoreHorizontalIcon()}
</div> </div>
</div>`} </div>`
}
`; `;
}; };
@@ -25,9 +25,11 @@ export class BooleanGroupView extends BaseGroup<boolean, NonNullable<unknown>> {
} }
return html` <div class="data-view-group-title-boolean-view"> return html` <div class="data-view-group-title-boolean-view">
${this.value ${
this.value
? CheckBoxCheckSolidIcon({ style: `color:#1E96EB` }) ? CheckBoxCheckSolidIcon({ style: `color:#1E96EB` })
: CheckBoxUnIcon()} : CheckBoxUnIcon()
}
</div>`; </div>`;
} }
} }
@@ -224,9 +224,9 @@ export class GroupSetting extends SignalWatcher(
<div <div
${sortable(g.key)} ${sortable(g.key)}
${dragHandler(g.key)} ${dragHandler(g.key)}
class="dv-hover dv-round-4 group-item ${g.hide$.value class="dv-hover dv-round-4 group-item ${
? 'group-hidden' g.hide$.value ? 'group-hidden' : ''
: ''}" }"
> >
<div class="group-item-drag-bar"></div> <div class="group-item-drag-bar"></div>
<div <div
@@ -376,17 +376,18 @@ export const buildGroupSettingItems = (
['Month', 'date-month'], ['Month', 'date-month'],
['Year', 'date-year'], ['Year', 'date-year'],
] as [string, string][] ] as [string, string][]
).map( ).map(([label, key]): MenuConfig =>
([label, key]): MenuConfig =>
menu.action({ menu.action({
name: label, name: label,
label: () => { label: () => {
const isSelected = const isSelected =
group.groupInfo$.value?.config.name === key; group.groupInfo$.value?.config.name === key;
return html`<span return html`<span
style="font-size:14px;color:${isSelected style="font-size:14px;color:${
isSelected
? 'var(--affine-text-emphasis-color)' ? 'var(--affine-text-emphasis-color)'
: 'var(--affine-text-secondary-color)'}" : 'var(--affine-text-secondary-color)'
}"
>${label}</span >${label}</span
>`; >`;
}, },
@@ -417,10 +418,12 @@ export const buildGroupSettingItems = (
<div <div
style="display:flex;align-items:center;gap:4px;font-size:14px;line-height:20px;color:var(--affine-text-secondary-color);margin-left:8px;" style="display:flex;align-items:center;gap:4px;font-size:14px;line-height:20px;color:var(--affine-text-secondary-color);margin-left:8px;"
> >
${group.groupInfo$.value?.config.name === ${
group.groupInfo$.value?.config.name ===
'date-week-mon' 'date-week-mon'
? 'Monday' ? 'Monday'
: 'Sunday'} : 'Sunday'
}
</div> </div>
`, `,
options: { options: {
@@ -439,9 +442,11 @@ export const buildGroupSettingItems = (
group.groupInfo$.value?.config.name === group.groupInfo$.value?.config.name ===
key; key;
return html`<span return html`<span
style="font-size:14px;color:${isSelected style="font-size:14px;color:${
isSelected
? 'var(--affine-text-emphasis-color)' ? 'var(--affine-text-emphasis-color)'
: 'var(--affine-text-secondary-color)'}" : 'var(--affine-text-secondary-color)'
}"
>${label}</span >${label}</span
>`; >`;
}, },
@@ -485,9 +490,11 @@ export const buildGroupSettingItems = (
label: () => { label: () => {
const isSelected = group.sortAsc$.value; const isSelected = group.sortAsc$.value;
return html`<span return html`<span
style="font-size:14px;color:${isSelected style="font-size:14px;color:${
isSelected
? 'var(--affine-text-emphasis-color)' ? 'var(--affine-text-emphasis-color)'
: 'var(--affine-text-secondary-color)'}" : 'var(--affine-text-secondary-color)'
}"
>Oldest first</span >Oldest first</span
>`; >`;
}, },
@@ -502,9 +509,11 @@ export const buildGroupSettingItems = (
label: () => { label: () => {
const isSelected = !group.sortAsc$.value; const isSelected = !group.sortAsc$.value;
return html`<span return html`<span
style="font-size:14px;color:${isSelected style="font-size:14px;color:${
isSelected
? 'var(--affine-text-emphasis-color)' ? 'var(--affine-text-emphasis-color)'
: 'var(--affine-text-secondary-color)'}" : 'var(--affine-text-secondary-color)'
}"
>Newest first</span >Newest first</span
>`; >`;
}, },
@@ -131,7 +131,8 @@ export class ProgressCell extends BaseCellRenderer<number, number> {
style=${bgStyles} style=${bgStyles}
> >
<div class="${progressFgStyle}" style=${fgStyles}></div> <div class="${progressFgStyle}" style=${fgStyles}></div>
${this.isEditing$.value ${
this.isEditing$.value
? html` <div ? html` <div
class="${progressDragHandleStyle}" class="${progressDragHandleStyle}"
data-testid="progress-drag-handle" data-testid="progress-drag-handle"
@@ -139,7 +140,8 @@ export class ProgressCell extends BaseCellRenderer<number, number> {
left: `calc(${progress}% - 3px)`, left: `calc(${progress}% - 3px)`,
})} })}
></div>` ></div>`
: ''} : ''
}
</div> </div>
</div> </div>
<span class="${progressNumberStyle}" data-testid="progress" <span class="${progressNumberStyle}" data-testid="progress"
@@ -65,20 +65,28 @@ export const openCalendarEntry = (
<span class="calendar-event-popover-icon">${DateTimeIcon()}</span> <span class="calendar-event-popover-icon">${DateTimeIcon()}</span>
<span>${formatEntryTime(entry)}</span> <span>${formatEntryTime(entry)}</span>
</div> </div>
${entry.location ${
entry.location
? html`<div class="calendar-event-popover-row"> ? html`<div class="calendar-event-popover-row">
<span class="calendar-event-popover-icon">${PinIcon()}</span> <span class="calendar-event-popover-icon"
>${PinIcon()}</span
>
<span>${entry.location}</span> <span>${entry.location}</span>
</div>` </div>`
: ''} : ''
${entry.description }
${
entry.description
? html`<div class="calendar-event-popover-row"> ? html`<div class="calendar-event-popover-row">
<span class="calendar-event-popover-icon">${TextIcon()}</span> <span class="calendar-event-popover-icon"
>${TextIcon()}</span
>
<span class="calendar-event-popover-description" <span class="calendar-event-popover-description"
>${entry.description}</span >${entry.description}</span
> >
</div>` </div>`
: ''} : ''
}
</div> </div>
`, `,
], ],
@@ -416,10 +416,12 @@ export class CalendarViewUILogic extends DataViewUILogicBase<CalendarSingleView>
postfix: html`<div postfix: html`<div
style="font-size:14px;color:var(--affine-text-secondary-color);" style="font-size:14px;color:var(--affine-text-secondary-color);"
> >
${this.view.startDateMapping$.value.status === 'ready' ${
this.view.startDateMapping$.value.status === 'ready'
? this.view.propertyGetOrCreate(selectedStart ?? '').name$ ? this.view.propertyGetOrCreate(selectedStart ?? '').name$
.value .value
: ''} : ''
}
</div> </div>
${ArrowRightSmallIcon()}`, ${ArrowRightSmallIcon()}`,
select: () => { select: () => {
@@ -448,9 +450,11 @@ export class CalendarViewUILogic extends DataViewUILogicBase<CalendarSingleView>
postfix: html`<div postfix: html`<div
style="font-size:14px;color:var(--affine-text-secondary-color);" style="font-size:14px;color:var(--affine-text-secondary-color);"
> >
${selectedEnd ${
selectedEnd
? this.view.propertyGetOrCreate(selectedEnd).name$.value ? this.view.propertyGetOrCreate(selectedEnd).name$.value
: 'None'} : 'None'
}
</div> </div>
${ArrowRightSmallIcon()}`, ${ArrowRightSmallIcon()}`,
select: () => { select: () => {
@@ -726,10 +730,9 @@ export class CalendarViewUI extends DataViewUIBase<CalendarViewUILogic> {
return html` return html`
<div <div
${ref(element => this.logic.bindEntryDraggable(dndKey, entry, element))} ${ref(element => this.logic.bindEntryDraggable(dndKey, entry, element))}
class="calendar-entry ${entry.kind} ${segmentClass} ${this.logic class="calendar-entry ${entry.kind} ${segmentClass} ${
.selectedEntryId === entry.id this.logic.selectedEntryId === entry.id ? 'selected' : ''
? 'selected' }"
: ''}"
role="button" role="button"
tabindex="0" tabindex="0"
aria-label=${entry.title || 'Untitled'} aria-label=${entry.title || 'Untitled'}
@@ -744,15 +747,18 @@ export class CalendarViewUI extends DataViewUIBase<CalendarViewUILogic> {
this.logic.handleEntryKeydown(entry, event); this.logic.handleEntryKeydown(entry, event);
}} }}
> >
${showLeftHandle ${
showLeftHandle
? html`<span ? html`<span
class="calendar-resize-handle left" class="calendar-resize-handle left"
@pointerdown=${(event: PointerEvent) => @pointerdown=${(event: PointerEvent) =>
this.logic.startResize(entry, 'start', event)} this.logic.startResize(entry, 'start', event)}
></span>` ></span>`
: nothing} : nothing
}
${this.renderEntryTitle(entry)} ${this.renderEntryTitle(entry)}
${entry.kind === 'row' && entry.cardProperties.length ${
entry.kind === 'row' && entry.cardProperties.length
? html`<span class="calendar-entry-properties"> ? html`<span class="calendar-entry-properties">
${entry.cardProperties.map( ${entry.cardProperties.map(
property => property =>
@@ -761,14 +767,17 @@ export class CalendarViewUI extends DataViewUIBase<CalendarViewUILogic> {
>` >`
)} )}
</span>` </span>`
: nothing} : nothing
${showRightHandle }
${
showRightHandle
? html`<span ? html`<span
class="calendar-resize-handle right" class="calendar-resize-handle right"
@pointerdown=${(event: PointerEvent) => @pointerdown=${(event: PointerEvent) =>
this.logic.startResize(entry, 'end', event)} this.logic.startResize(entry, 'end', event)}
></span>` ></span>`
: nothing} : nothing
}
</div> </div>
`; `;
} }
@@ -785,16 +794,18 @@ export class CalendarViewUI extends DataViewUIBase<CalendarViewUILogic> {
${entry.titleSegments.map( ${entry.titleSegments.map(
segment => segment =>
html`<span html`<span
class="calendar-entry-title-segment ${segment.linkedDoc class="calendar-entry-title-segment ${
? 'linked-doc-segment' segment.linkedDoc ? 'linked-doc-segment' : ''
: ''}" }"
> >
${segment.linkedDoc ? LinkedPageIcon() : nothing} ${segment.linkedDoc ? LinkedPageIcon() : nothing}
${segment.text ${
segment.text
? html`<span class="calendar-entry-title-text" ? html`<span class="calendar-entry-title-text"
>${segment.text}</span >${segment.text}</span
>` >`
: nothing} : nothing
}
</span>` </span>`
)} )}
</span>`; </span>`;
@@ -895,11 +906,12 @@ export class CalendarViewUI extends DataViewUIBase<CalendarViewUILogic> {
if (!preview) return nothing; if (!preview) return nothing;
return html`<div return html`<div
class="calendar-entry-preview ${preview.continuesLeft class="calendar-entry-preview ${
? 'continues-left' preview.continuesLeft ? 'continues-left' : ''
: ''} ${preview.continuesRight ? 'continues-right' : ''}" } ${preview.continuesRight ? 'continues-right' : ''}"
style="grid-column:${preview.sIdx + style="grid-column:${
1} / span ${preview.span};grid-row:${preview.slot + 1};" preview.sIdx + 1
} / span ${preview.span};grid-row:${preview.slot + 1};"
> >
${preview.title} ${preview.title}
</div>`; </div>`;
@@ -919,7 +931,8 @@ export class CalendarViewUI extends DataViewUIBase<CalendarViewUILogic> {
</span> </span>
</div> </div>
<div class="calendar-empty-month-hint-actions"> <div class="calendar-empty-month-hint-actions">
${this.logic.view.readonly$.value ${
this.logic.view.readonly$.value
? nothing ? nothing
: html`<button : html`<button
class="calendar-empty-month-hint-action" class="calendar-empty-month-hint-action"
@@ -929,7 +942,8 @@ export class CalendarViewUI extends DataViewUIBase<CalendarViewUILogic> {
)} )}
> >
${PlusIcon()}<span>New row</span> ${PlusIcon()}<span>New row</span>
</button>`} </button>`
}
<button <button
class="calendar-empty-month-hint-close" class="calendar-empty-month-hint-close"
aria-label="Dismiss" aria-label="Dismiss"
@@ -963,14 +977,16 @@ export class CalendarViewUI extends DataViewUIBase<CalendarViewUILogic> {
${monthFormatter.format(new Date(this.logic.currentMonth))} ${monthFormatter.format(new Date(this.logic.currentMonth))}
</div> </div>
<div class="calendar-nav"> <div class="calendar-nav">
${this.logic.isCurrentMonth() ${
this.logic.isCurrentMonth()
? nothing ? nothing
: html`<button : html`<button
class="calendar-today-button" class="calendar-today-button"
@click=${() => this.logic.goToday()} @click=${() => this.logic.goToday()}
> >
<span>Today</span> <span>Today</span>
</button>`} </button>`
}
<button <button
class="calendar-icon-button" class="calendar-icon-button"
aria-label="Previous month" aria-label="Previous month"
@@ -1022,13 +1038,13 @@ export class CalendarViewUI extends DataViewUIBase<CalendarViewUILogic> {
return html` return html`
<div <div
data-date=${day.date} data-date=${day.date}
class="calendar-day ${day.inMonth class="calendar-day ${
? '' day.inMonth ? '' : 'is-outside'
: 'is-outside'} ${day.date === today } ${day.date === today ? 'is-today' : ''} ${
? 'is-today' this.logic.isDayInPreview(day.date)
: ''} ${this.logic.isDayInPreview(day.date)
? 'is-drop-target' ? 'is-drop-target'
: ''}" : ''
}"
style="--calendar-segment-slots:${getCalendarDaySegmentSlots( style="--calendar-segment-slots:${getCalendarDaySegmentSlots(
day, day,
movingEntryId movingEntryId
@@ -1044,7 +1060,8 @@ export class CalendarViewUI extends DataViewUIBase<CalendarViewUILogic> {
${this.renderDayPreview(day.date)} ${this.renderDayPreview(day.date)}
${this.renderPreviewSpacer(day, preview, dayIndex)} ${this.renderPreviewSpacer(day, preview, dayIndex)}
</div> </div>
${canReserveNewRow ${
canReserveNewRow
? html`<button ? html`<button
class="calendar-new-row" class="calendar-new-row"
aria-label="+ New row" aria-label="+ New row"
@@ -1054,7 +1071,8 @@ export class CalendarViewUI extends DataViewUIBase<CalendarViewUILogic> {
> >
${PlusIcon()}<span>New row</span> ${PlusIcon()}<span>New row</span>
</button>` </button>`
: nothing} : nothing
}
</div> </div>
`; `;
} }
@@ -1083,25 +1101,31 @@ export class CalendarViewUI extends DataViewUIBase<CalendarViewUILogic> {
override render(): TemplateResult { override render(): TemplateResult {
const setup = this.logic.view.dateMapping$.value.status === 'setup'; const setup = this.logic.view.dateMapping$.value.status === 'setup';
return html` return html`
${this.logic.headerWidget ${
this.logic.headerWidget
? renderUniLit(this.logic.headerWidget, { ? renderUniLit(this.logic.headerWidget, {
dataViewLogic: this.logic, dataViewLogic: this.logic,
}) })
: nothing} : nothing
}
<div class=${setup ? 'calendar-setup-wrap' : ''}> <div class=${setup ? 'calendar-setup-wrap' : ''}>
<div class="calendar-scroll" @wheel="${this.logic.onWheel}"> <div class="calendar-scroll" @wheel="${this.logic.onWheel}">
${this.renderCalendar(setup)} ${this.renderCalendar(setup)}
</div> </div>
${setup ${
setup
? html`<div class="calendar-setup"> ? html`<div class="calendar-setup">
<button <button
@click=${(event: MouseEvent) => @click=${(event: MouseEvent) =>
this.logic.openSetupMenu(event.currentTarget as HTMLElement)} this.logic.openSetupMenu(
event.currentTarget as HTMLElement
)}
> >
${TodayIcon()}<span>Select or create date property</span> ${TodayIcon()}<span>Select or create date property</span>
</button> </button>
</div>` </div>`
: nothing} : nothing
}
</div> </div>
`; `;
} }
@@ -121,7 +121,8 @@ export class MobileKanbanGroup extends SignalWatcher(
`; `;
} }
)} )}
${this.view.readonly$.value ${
this.view.readonly$.value
? nothing ? nothing
: html` <div class="mobile-add-card" @click="${this.clickAddCard}"> : html` <div class="mobile-add-card" @click="${this.clickAddCard}">
<div <div
@@ -130,7 +131,8 @@ export class MobileKanbanGroup extends SignalWatcher(
${AddCursorIcon()} ${AddCursorIcon()}
</div> </div>
Add Add
</div>`} </div>`
}
</div> </div>
`; `;
} }
@@ -179,7 +179,8 @@ export class KanbanGroup extends SignalWatcher(
`; `;
} }
)} )}
${this.view.readonly$.value ${
this.view.readonly$.value
? nothing ? nothing
: html`<div class="add-card" @click="${this.clickAddCard}"> : html`<div class="add-card" @click="${this.clickAddCard}">
<div <div
@@ -188,7 +189,8 @@ export class KanbanGroup extends SignalWatcher(
${AddCursorIcon()} ${AddCursorIcon()}
</div> </div>
Add Add
</div>`} </div>`
}
</div> </div>
`; `;
} }
@@ -148,9 +148,9 @@ export class MobileTableGroup extends SignalWatcher(
class=${`group-toggle-btn ${this.collapsed$.value ? '' : 'expanded'}`} class=${`group-toggle-btn ${this.collapsed$.value ? '' : 'expanded'}`}
role="button" role="button"
aria-expanded=${this.collapsed$.value ? 'false' : 'true'} aria-expanded=${this.collapsed$.value ? 'false' : 'true'}
aria-label=${this.collapsed$.value aria-label=${
? 'Expand group' this.collapsed$.value ? 'Expand group' : 'Collapse group'
: 'Collapse group'} }
tabindex="0" tabindex="0"
@click=${this._toggleCollapse} @click=${this._toggleCollapse}
@keydown=${(e: KeyboardEvent) => { @keydown=${(e: KeyboardEvent) => {
@@ -160,9 +160,11 @@ export class MobileTableGroup extends SignalWatcher(
} }
}} }}
> >
${this.collapsed$.value ${
this.collapsed$.value
? ToggleRightIcon({ width: '16px', height: '16px' }) ? ToggleRightIcon({ width: '16px', height: '16px' })
: ToggleDownIcon({ width: '16px', height: '16px' })} : ToggleDownIcon({ width: '16px', height: '16px' })
}
</div> </div>
${GroupTitle(this.group, { ${GroupTitle(this.group, {
@@ -198,7 +200,8 @@ export class MobileTableGroup extends SignalWatcher(
} }
)} )}
</div> </div>
${this.view.readonly$.value ${
this.view.readonly$.value
? null ? null
: html` <div : html` <div
class="data-view-table-group-add-row dv-hover" class="data-view-table-group-add-row dv-hover"
@@ -211,7 +214,8 @@ export class MobileTableGroup extends SignalWatcher(
> >
${PlusIcon()}<span style="font-size: 12px">New Record</span> ${PlusIcon()}<span style="font-size: 12px">New Record</span>
</div> </div>
</div>`} </div>`
}
`; `;
} }
@@ -109,19 +109,23 @@ export class MobileTableRow extends SignalWatcher(
</mobile-table-cell> </mobile-table-cell>
<div class="${cellDivider}"></div> <div class="${cellDivider}"></div>
</div> </div>
${!column.readonly$.value && ${
!column.readonly$.value &&
column.view.mainProperties$.value.titleColumn === column.id column.view.mainProperties$.value.titleColumn === column.id
? html` <div class="mobile-row-ops"> ? html` <div class="mobile-row-ops">
<div class="mobile-row-op" @click="${clickDetail}"> <div class="mobile-row-op" @click="${clickDetail}">
${CenterPeekIcon()} ${CenterPeekIcon()}
</div> </div>
${!view.readonly$.value ${
!view.readonly$.value
? html` <div class="mobile-row-op" @click="${openMenu}"> ? html` <div class="mobile-row-op" @click="${openMenu}">
${MoreHorizontalIcon()} ${MoreHorizontalIcon()}
</div>` </div>`
: nothing} : nothing
}
</div>` </div>`
: nothing} : nothing
}
`; `;
} }
)} )}
@@ -74,7 +74,8 @@ export class TableGroupFooter extends WithDisposable(ShadowlessElement) {
override render() { override render() {
return html` return html`
${this.tableViewManager.readonly$.value ${
this.tableViewManager.readonly$.value
? null ? null
: html` : html`
<div <div
@@ -91,7 +92,8 @@ export class TableGroupFooter extends WithDisposable(ShadowlessElement) {
> >
</div> </div>
</div> </div>
`} `
}
<affine-database-virtual-column-stats <affine-database-virtual-column-stats
.view="${this.tableViewManager}" .view="${this.tableViewManager}"
.group="${this.group$.value}" .group="${this.group$.value}"
@@ -225,12 +225,14 @@ export class VirtualDatabaseColumnStatsCell extends SignalWatcher(
class="stats-cell" class="stats-cell"
> >
<div class="content"> <div class="content">
${!this.statsResult$.value ${
!this.statsResult$.value
? html`Calculate ${ArrowDownSmallIcon()}` ? html`Calculate ${ArrowDownSmallIcon()}`
: html` : html`
<span class="label">${this.statsResult$.value.name}</span> <span class="label">${this.statsResult$.value.name}</span>
<span class="value">${this.statsResult$.value.value} </span> <span class="value">${this.statsResult$.value.value} </span>
`} `
}
</div> </div>
</div>`; </div>`;
} }
@@ -64,7 +64,8 @@ export const GroupTitle = (
${icon} ${renderUniLit(view, props)} ${columnName} ${icon} ${renderUniLit(view, props)} ${columnName}
${GroupHeaderCount(groupData)} ${GroupHeaderCount(groupData)}
</div> </div>
${!ops.readonly ${
!ops.readonly
? html` <div class="${opsClass}"> ? html` <div class="${opsClass}">
<div @click="${ops.clickAdd}" class="${groupHeaderOp}"> <div @click="${ops.clickAdd}" class="${groupHeaderOp}">
${PlusIcon()} ${PlusIcon()}
@@ -73,6 +74,7 @@ export const GroupTitle = (
${MoreHorizontalIcon()} ${MoreHorizontalIcon()}
</div> </div>
</div>` </div>`
: nothing} : nothing
}
`; `;
}; };
@@ -428,14 +428,16 @@ export class DatabaseHeaderColumn extends SignalWatcher(
${draggable(column.id)} ${draggable(column.id)}
${droppable(column.id)} ${droppable(column.id)}
> >
${this.readonly ${
this.readonly
? null ? null
: html` <button class="${classes}"> : html` <button class="${classes}">
<div class="hover-trigger"></div> <div class="hover-trigger"></div>
<div class="control-h"></div> <div class="control-h"></div>
<div class="control-l"></div> <div class="control-l"></div>
<div class="control-r"></div> <div class="control-r"></div>
</button>`} </button>`
}
<div class="affine-database-column-text ${column.type$.value}"> <div class="affine-database-column-text ${column.type$.value}">
<div <div
class="affine-database-column-type-icon dv-hover" class="affine-database-column-type-icon dv-hover"
@@ -84,9 +84,11 @@ export class TableRowHeader extends SignalWatcher(
return html` return html`
<div @click=${this.selectRow} class="${styles.checkboxWrapper}"> <div @click=${this.selectRow} class="${styles.checkboxWrapper}">
<div class="${classString}"> <div class="${classString}">
${this.rowSelected$.value ${
this.rowSelected$.value
? CheckBoxCheckSolidIcon({ style: `color:#1E96EB` }) ? CheckBoxCheckSolidIcon({ style: `color:#1E96EB` })
: CheckBoxUnIcon()} : CheckBoxUnIcon()
}
</div> </div>
</div> </div>
`; `;
@@ -206,9 +206,9 @@ export class TableGroup extends SignalWatcher(
class=${`group-toggle-btn ${this.collapsed$.value ? '' : 'expanded'}`} class=${`group-toggle-btn ${this.collapsed$.value ? '' : 'expanded'}`}
role="button" role="button"
aria-expanded=${this.collapsed$.value ? 'false' : 'true'} aria-expanded=${this.collapsed$.value ? 'false' : 'true'}
aria-label=${this.collapsed$.value aria-label=${
? 'Expand group' this.collapsed$.value ? 'Expand group' : 'Collapse group'
: 'Collapse group'} }
tabindex="0" tabindex="0"
@click=${this._toggleCollapse} @click=${this._toggleCollapse}
@keydown=${(e: KeyboardEvent) => { @keydown=${(e: KeyboardEvent) => {
@@ -218,9 +218,11 @@ export class TableGroup extends SignalWatcher(
} }
}} }}
> >
${this.collapsed$.value ${
this.collapsed$.value
? ToggleRightIcon({ width: '16px', height: '16px' }) ? ToggleRightIcon({ width: '16px', height: '16px' })
: ToggleDownIcon({ width: '16px', height: '16px' })} : ToggleDownIcon({ width: '16px', height: '16px' })
}
</div> </div>
${GroupTitle(this.group, { ${GroupTitle(this.group, {
@@ -344,7 +346,8 @@ export class TableGroup extends SignalWatcher(
} }
)} )}
</div> </div>
${this.view.readonly$.value ${
this.view.readonly$.value
? null ? null
: html` <div : html` <div
class="data-view-table-group-add-row dv-hover" class="data-view-table-group-add-row dv-hover"
@@ -357,7 +360,8 @@ export class TableGroup extends SignalWatcher(
> >
${PlusIcon()}<span style="font-size: 12px">New Record</span> ${PlusIcon()}<span style="font-size: 12px">New Record</span>
</div> </div>
</div>`} </div>`
}
<affine-database-column-stats <affine-database-column-stats
.tableViewLogic="${this.tableViewLogic}" .tableViewLogic="${this.tableViewLogic}"
.group="${this.group}" .group="${this.group}"
@@ -87,9 +87,11 @@ export class DatabaseColumnHeader extends SignalWatcher(
return html` return html`
${this.renderGroupHeader?.()} ${this.renderGroupHeader?.()}
<div class="affine-database-column-header database-row"> <div class="affine-database-column-header database-row">
${this.readonly ${
this.readonly
? nothing ? nothing
: html`<div class="${tableStyle.leftToolBarStyle}"></div>`} : html`<div class="${tableStyle.leftToolBarStyle}"></div>`
}
${repeat( ${repeat(
this.tableViewManager.properties$.value, this.tableViewManager.properties$.value,
column => column.id, column => column.id,
@@ -431,14 +431,16 @@ export class DatabaseHeaderColumn extends SignalWatcher(
${draggable(column.id)} ${draggable(column.id)}
${droppable(column.id)} ${droppable(column.id)}
> >
${this.readonly ${
this.readonly
? null ? null
: html` <button class="${classes}"> : html` <button class="${classes}">
<div class="hover-trigger"></div> <div class="hover-trigger"></div>
<div class="control-h"></div> <div class="control-h"></div>
<div class="control-l"></div> <div class="control-l"></div>
<div class="control-r"></div> <div class="control-r"></div>
</button>`} </button>`
}
<div class="affine-database-column-text ${column.type$.value}"> <div class="affine-database-column-text ${column.type$.value}">
<div <div
class="affine-database-column-type-icon dv-hover" class="affine-database-column-type-icon dv-hover"
@@ -71,9 +71,11 @@ export class RowSelectCheckbox extends SignalWatcher(
}); });
return html` return html`
<div class="${classString}"> <div class="${classString}">
${this.isSelected$.value ${
this.isSelected$.value
? CheckBoxCheckSolidIcon({ style: `color:#1E96EB` }) ? CheckBoxCheckSolidIcon({ style: `color:#1E96EB` })
: CheckBoxUnIcon()} : CheckBoxUnIcon()
}
</div> </div>
`; `;
} }
@@ -177,7 +177,8 @@ export class TableRowView extends SignalWatcher(
protected override render(): unknown { protected override render(): unknown {
const view = this.view; const view = this.view;
return html` return html`
${view.readonly$.value ${
view.readonly$.value
? nothing ? nothing
: html`<div class="data-view-table-left-bar" style="height: 34px"> : html`<div class="data-view-table-left-bar" style="height: 34px">
<div style="display: flex;"> <div style="display: flex;">
@@ -198,7 +199,8 @@ export class TableRowView extends SignalWatcher(
.groupKey="${this.groupKey}" .groupKey="${this.groupKey}"
></row-select-checkbox> ></row-select-checkbox>
</div> </div>
</div>`} </div>`
}
${repeat( ${repeat(
view.properties$.value, view.properties$.value,
v => v.id, v => v.id,
@@ -265,19 +267,23 @@ export class TableRowView extends SignalWatcher(
</dv-table-view-cell-container> </dv-table-view-cell-container>
<div class="${cellDivider}"></div> <div class="${cellDivider}"></div>
</div> </div>
${!column.readonly$.value && ${
!column.readonly$.value &&
column.view.mainProperties$.value.titleColumn === column.id column.view.mainProperties$.value.titleColumn === column.id
? html`<div class="row-ops show-on-hover-row"> ? html`<div class="row-ops show-on-hover-row">
<div class="row-op" @click="${clickDetail}"> <div class="row-op" @click="${clickDetail}">
${CenterPeekIcon()} ${CenterPeekIcon()}
</div> </div>
${!view.readonly$.value ${
!view.readonly$.value
? html`<div class="row-op" @click="${openMenu}"> ? html`<div class="row-op" @click="${openMenu}">
${MoreHorizontalIcon()} ${MoreHorizontalIcon()}
</div>` </div>`
: nothing} : nothing
}
</div>` </div>`
: nothing} : nothing
}
`; `;
} }
)} )}
@@ -191,11 +191,13 @@ export class TableViewUI extends DataViewUIBase<TableViewUILogic> {
paddingRight: `${vPadding}px`, paddingRight: `${vPadding}px`,
}); });
return html` return html`
${this.logic.headerWidget ${
this.logic.headerWidget
? renderUniLit(this.logic.headerWidget, { ? renderUniLit(this.logic.headerWidget, {
dataViewLogic: this.logic, dataViewLogic: this.logic,
}) })
: ''} : ''
}
<div class="${tableWrapperStyle}" style="${wrapperStyle}"> <div class="${tableWrapperStyle}" style="${wrapperStyle}">
<div <div
${ref(this.logic.scrollContainer$)} ${ref(this.logic.scrollContainer$)}
@@ -207,11 +209,13 @@ export class TableViewUI extends DataViewUIBase<TableViewUILogic> {
class="affine-database-table-container" class="affine-database-table-container"
style="${containerStyle}" style="${containerStyle}"
> >
${this.logic.view.groupTrait.allHidden$.value ${
this.logic.view.groupTrait.allHidden$.value
? html`<div class="${groupsHiddenMessageStyle}"> ? html`<div class="${groupsHiddenMessageStyle}">
All groups are hidden All groups are hidden
</div>` </div>`
: this.renderTable()} : this.renderTable()
}
</div> </div>
</div> </div>
</div> </div>
@@ -225,12 +225,14 @@ export class DatabaseColumnStatsCell extends SignalWatcher(
class="stats-cell" class="stats-cell"
> >
<div class="content"> <div class="content">
${!this.statsResult$.value ${
!this.statsResult$.value
? html`Calculate ${ArrowDownSmallIcon()}` ? html`Calculate ${ArrowDownSmallIcon()}`
: html` : html`
<span class="label">${this.statsResult$.value.name}</span> <span class="label">${this.statsResult$.value.name}</span>
<span class="value">${this.statsResult$.value.value} </span> <span class="value">${this.statsResult$.value.value} </span>
`} `
}
</div> </div>
</div>`; </div>`;
} }
@@ -374,7 +374,8 @@ export class FilterGroupView extends SignalWatcher(ShadowlessElement) {
<div <div
style="flex:1;display:flex;align-items:start;justify-content: space-between;gap: 8px;" style="flex:1;display:flex;align-items:start;justify-content: space-between;gap: 8px;"
> >
${filter.type === 'filter' ${
filter.type === 'filter'
? html` ? html`
<filter-condition-view <filter-condition-view
.vars="${this.vars}" .vars="${this.vars}"
@@ -392,7 +393,8 @@ export class FilterGroupView extends SignalWatcher(ShadowlessElement) {
.vars="${this.vars}" .vars="${this.vars}"
.filterGroup="${computed(() => filter)}" .filterGroup="${computed(() => filter)}"
></filter-group-view> ></filter-group-view>
`} `
}
<div class="filter-group-item-ops" @click="${clickOps}"> <div class="filter-group-item-ops" @click="${clickOps}">
${MoreHorizontalIcon()} ${MoreHorizontalIcon()}
</div> </div>
@@ -37,13 +37,15 @@ export const widgetQuickSettingBar = defineUniComponent(
> >
${barList.map((bar, index) => { ${barList.map((bar, index) => {
return html` return html`
${index !== 0 ${
index !== 0
? html` <div ? html` <div
style="width: 1px;height:27px;background-color: ${unsafeCSSVarV2( style="width: 1px;height:27px;background-color: ${unsafeCSSVarV2(
'layer/insideBorder/border' 'layer/insideBorder/border'
)}" )}"
></div>` ></div>`
: nothing} : nothing
}
${bar} ${bar}
`; `;
})} })}
@@ -36,9 +36,11 @@ export class DataViewHeaderToolsAddRow extends WidgetBase {
class="affine-database-toolbar-item new-record" class="affine-database-toolbar-item new-record"
.onClick="${this.onAddNewRecord}" .onClick="${this.onAddNewRecord}"
.icon="${PlusIcon()}" .icon="${PlusIcon()}"
.text="${IS_MOBILE .text="${
IS_MOBILE
? html`<span style="font-weight: 500">New</span>` ? html`<span style="font-weight: 500">New</span>`
: html`<span style="font-weight: 500">New Record</span>`}" : html`<span style="font-weight: 500">New Record</span>`
}"
> >
</data-view-component-button>`; </data-view-component-button>`;
} }
@@ -440,11 +440,13 @@ export const popViewOptions = (
closeOnSelect: false, closeOnSelect: false,
postfix: html` postfix: html`
<div style="font-size: 14px;"> <div style="font-size: 14px;">
${filterCount === 0 ${
filterCount === 0
? '' ? ''
: filterCount === 1 : filterCount === 1
? '1 active' ? '1 active'
: `${filterCount} active`} : `${filterCount} active`
}
</div> </div>
${ArrowRightSmallIcon()} ${ArrowRightSmallIcon()}
`, `,
@@ -466,11 +468,13 @@ export const popViewOptions = (
closeOnSelect: false, closeOnSelect: false,
postfix: html` postfix: html`
<div style="font-size: 14px;"> <div style="font-size: 14px;">
${sortCount === 0 ${
sortCount === 0
? '' ? ''
: sortCount === 1 : sortCount === 1
? '1 active' ? '1 active'
: `${sortCount} active`} : `${sortCount} active`
}
</div> </div>
${ArrowRightSmallIcon()} ${ArrowRightSmallIcon()}
`, `,
+16 -4
View File
@@ -11,7 +11,10 @@ import { BaseExtensionProvider } from '@blocksuite/affine-ext-loader';
import { z } from 'zod'; import { z } from 'zod';
// Create a custom provider with options // Create a custom provider with options
class MyProvider extends BaseExtensionProvider<'my-scope', { enabled: boolean }> { class MyProvider extends BaseExtensionProvider<
'my-scope',
{ enabled: boolean }
> {
name = 'MyProvider'; name = 'MyProvider';
schema = z.object({ schema = z.object({
@@ -28,7 +31,10 @@ class MyProvider extends BaseExtensionProvider<'my-scope', { enabled: boolean }>
### Store Extensions ### Store Extensions
```typescript ```typescript
import { StoreExtensionProvider, StoreExtensionManager } from '@blocksuite/affine-ext-loader'; import {
StoreExtensionProvider,
StoreExtensionManager,
} from '@blocksuite/affine-ext-loader';
import { z } from 'zod'; import { z } from 'zod';
// Create a store provider with custom options // Create a store provider with custom options
@@ -39,7 +45,10 @@ class MyStoreProvider extends StoreExtensionProvider<{ cacheSize: number }> {
cacheSize: z.number().min(0), cacheSize: z.number().min(0),
}); });
override setup(context: StoreExtensionContext, options?: { cacheSize: number }) { override setup(
context: StoreExtensionContext,
options?: { cacheSize: number }
) {
super.setup(context, options); super.setup(context, options);
context.register([Ext1, Ext2, Ext3]); context.register([Ext1, Ext2, Ext3]);
} }
@@ -54,7 +63,10 @@ const extensions = manager.get('store');
### View Extensions ### View Extensions
```typescript ```typescript
import { ViewExtensionProvider, ViewExtensionManager } from '@blocksuite/affine-ext-loader'; import {
ViewExtensionProvider,
ViewExtensionManager,
} from '@blocksuite/affine-ext-loader';
import { z } from 'zod'; import { z } from 'zod';
// Create a view provider with custom options // Create a view provider with custom options
@@ -134,13 +134,15 @@ export class AdapterPanelBody extends SignalWatcher(LitElement) {
private _renderHtmlPanel() { private _renderHtmlPanel() {
return html` return html`
${this.isHtmlPreview ${
this.isHtmlPreview
? html`<iframe ? html`<iframe
class="html-preview-container" class="html-preview-container"
.srcdoc=${this.htmlContent} .srcdoc=${this.htmlContent}
sandbox="allow-same-origin" sandbox="allow-same-origin"
></iframe>` ></iframe>`
: html`<div class="html-panel-content">${this.htmlContent}</div>`} : html`<div class="html-panel-content">${this.htmlContent}</div>`
}
<div class="html-panel-footer"> <div class="html-panel-footer">
<div class="html-toggle-container"> <div class="html-toggle-container">
<span <span
@@ -213,9 +213,9 @@ export class DocTitle extends WithDisposable(ShadowlessElement) {
return html` return html`
<div <div
class="doc-title-container ${isEmpty class="doc-title-container ${
? 'doc-title-container-empty' isEmpty ? 'doc-title-container-empty' : ''
: ''}" }"
data-block-is-title="true" data-block-is-title="true"
> >
<rich-text <rich-text
@@ -268,11 +268,13 @@ export class FramePanelBody extends SignalWatcher(
.std=${this.editorHost.std} .std=${this.editorHost.std}
.cardIndex=${cardIndex} .cardIndex=${cardIndex}
.frameIndex=${frameIndex} .frameIndex=${frameIndex}
.status=${selectedFrames.has(frame.id) .status=${
selectedFrames.has(frame.id)
? this._dragging ? this._dragging
? 'placeholder' ? 'placeholder'
: 'selected' : 'selected'
: 'none'} : 'none'
}
@select=${this._selectFrame} @select=${this._selectFrame}
@fitview=${this._fitToElement} @fitview=${this._fitToElement}
@drag=${this._drag} @drag=${this._drag}
@@ -281,12 +283,14 @@ export class FramePanelBody extends SignalWatcher(
})}`; })}`;
const frameList = html` <div class="frame-list-container"> const frameList = html` <div class="frame-list-container">
${this.insertIndex !== undefined ${
this.insertIndex !== undefined
? html`<div ? html`<div
class="insert-indicator" class="insert-indicator"
style=${`transform: translateY(${this._indicatorTranslateY}px)`} style=${`transform: translateY(${this._indicatorTranslateY}px)`}
></div>` ></div>`
: nothing} : nothing
}
${frameCards} ${frameCards}
</div>`; </div>`;
return frameList; return frameList;
@@ -385,9 +389,11 @@ export class FramePanelBody extends SignalWatcher(
override render() { override render() {
this._updateFrameItems(); this._updateFrameItems();
return html` ${this._frameItems.length return html` ${
this._frameItems.length
? this._renderFrameList() ? this._renderFrameList()
: this._renderEmptyContent()}`; : this._renderEmptyContent()
}`;
} }
override updated(_changedProperties: PropertyValues) { override updated(_changedProperties: PropertyValues) {
@@ -193,24 +193,28 @@ export class FrameCard extends WithDisposable(ShadowlessElement) {
class="frame-card-container ${this.status ?? ''}" class="frame-card-container ${this.status ?? ''}"
style=${containerStyle} style=${containerStyle}
> >
${this.status === 'dragging' ${
this.status === 'dragging'
? nothing ? nothing
: html`<affine-frame-card-title : html`<affine-frame-card-title
.cardIndex=${this.cardIndex} .cardIndex=${this.cardIndex}
.frame=${this.frame} .frame=${this.frame}
></affine-frame-card-title>`} ></affine-frame-card-title>`
}
<div <div
class="frame-card-body" class="frame-card-body"
@click=${this._dispatchSelectEvent} @click=${this._dispatchSelectEvent}
@dblclick=${this._dispatchFitViewEvent} @dblclick=${this._dispatchFitViewEvent}
@mousedown=${this._dispatchDragEvent} @mousedown=${this._dispatchDragEvent}
> >
${this.status === 'dragging' && stackOrder !== 0 ${
this.status === 'dragging' && stackOrder !== 0
? nothing ? nothing
: html`<frame-preview : html`<frame-preview
.frame=${this.frame} .frame=${this.frame}
.std=${this.std} .std=${this.std}
></frame-preview>`} ></frame-preview>`
}
${this._DraggingCardNumber()} ${this._DraggingCardNumber()}
</div> </div>
</div>`; </div>`;
@@ -191,9 +191,9 @@ export class FramePanelHeader extends WithDisposable(LitElement) {
<div class="all-frames-setting"> <div class="all-frames-setting">
<span class="all-frames-setting-label">All frames</span> <span class="all-frames-setting-label">All frames</span>
<edgeless-tool-icon-button <edgeless-tool-icon-button
class="all-frames-setting-button ${this._settingPopperShow class="all-frames-setting-button ${
? 'active' this._settingPopperShow ? 'active' : ''
: ''}" }"
.tooltip=${this._settingPopperShow ? '' : 'All Frames Settings'} .tooltip=${this._settingPopperShow ? '' : 'All Frames Settings'}
.tipPosition=${'top'} .tipPosition=${'top'}
.active=${this._settingPopperShow} .active=${this._settingPopperShow}
@@ -412,11 +412,13 @@ export class OutlinePanelBody extends SignalWatcher(
index=${index} index=${index}
.note=${note} .note=${note}
.activeHeadingId=${this._activeHeadingId$.value} .activeHeadingId=${this._activeHeadingId$.value}
.status=${this._allSelectedNotes$.value.includes(note) .status=${
this._allSelectedNotes$.value.includes(note)
? this._dragging$.value ? this._dragging$.value
? 'dragging' ? 'dragging'
: 'selected' : 'selected'
: 'normal'} : 'normal'
}
@fitview=${this._fitToElement} @fitview=${this._fitToElement}
@select=${this._selectNote} @select=${this._selectNote}
@displaymodechange=${this._handleDisplayModeChange} @displaymodechange=${this._handleDisplayModeChange}
@@ -101,11 +101,13 @@ export class OutlineBlockPreview extends SignalWatcher(
class="${styles.text} ${styles.textGeneral} ${headingClass}" class="${styles.text} ${styles.textGeneral} ${headingClass}"
>${previewText}</span >${previewText}</span
> >
${this._context.showIcons$.value ${
this._context.showIcons$.value
? html`<span class=${iconClass} ? html`<span class=${iconClass}
>${previewIconMap[block.props.type]}</span >${previewIconMap[block.props.type]}</span
>` >`
: nothing}`; : nothing
}`;
} }
override render() { override render() {
@@ -148,15 +150,17 @@ export class OutlineBlockPreview extends SignalWatcher(
assertType<BookmarkBlockModel>(block); assertType<BookmarkBlockModel>(block);
return html` return html`
<span class="${styles.text} ${styles.textGeneral}" <span class="${styles.text} ${styles.textGeneral}"
>${block.props.title || >${
block.props.url || block.props.title || block.props.url || placeholderMap['bookmark']
placeholderMap['bookmark']}</span }</span
> >
${showPreviewIcon ${
showPreviewIcon
? html`<span class=${iconClass} ? html`<span class=${iconClass}
>${previewIconMap['bookmark']}</span >${previewIconMap['bookmark']}</span
>` >`
: nothing} : nothing
}
`; `;
case 'affine:code': case 'affine:code':
assertType<CodeBlockModel>(block); assertType<CodeBlockModel>(block);
@@ -164,47 +168,61 @@ export class OutlineBlockPreview extends SignalWatcher(
<span class="${styles.text} ${styles.textGeneral}" <span class="${styles.text} ${styles.textGeneral}"
>${block.props.language ?? placeholderMap['code']}</span >${block.props.language ?? placeholderMap['code']}</span
> >
${showPreviewIcon ${
showPreviewIcon
? html`<span class=${iconClass}>${previewIconMap['code']}</span>` ? html`<span class=${iconClass}>${previewIconMap['code']}</span>`
: nothing} : nothing
}
`; `;
case 'affine:database': case 'affine:database':
assertType<DatabaseBlockModel>(block); assertType<DatabaseBlockModel>(block);
return html` return html`
<span class="${styles.text} ${styles.textGeneral}" <span class="${styles.text} ${styles.textGeneral}"
>${block.props.title.toString().length >${
block.props.title.toString().length
? block.props.title.toString() ? block.props.title.toString()
: placeholderMap['database']}</span : placeholderMap['database']
}</span
> >
${showPreviewIcon ${
showPreviewIcon
? html`<span class=${iconClass}>${previewIconMap['table']}</span>` ? html`<span class=${iconClass}>${previewIconMap['table']}</span>`
: nothing} : nothing
}
`; `;
case 'affine:image': case 'affine:image':
assertType<ImageBlockModel>(block); assertType<ImageBlockModel>(block);
return html` return html`
<span class="${styles.text} ${styles.textGeneral}" <span class="${styles.text} ${styles.textGeneral}"
>${block.props.caption?.length >${
block.props.caption?.length
? block.props.caption ? block.props.caption
: placeholderMap['image']}</span : placeholderMap['image']
}</span
> >
${showPreviewIcon ${
showPreviewIcon
? html`<span class=${iconClass}>${previewIconMap['image']}</span>` ? html`<span class=${iconClass}>${previewIconMap['image']}</span>`
: nothing} : nothing
}
`; `;
case 'affine:attachment': case 'affine:attachment':
assertType<AttachmentBlockModel>(block); assertType<AttachmentBlockModel>(block);
return html` return html`
<span class="${styles.text} ${styles.textGeneral}" <span class="${styles.text} ${styles.textGeneral}"
>${block.props.name?.length >${
block.props.name?.length
? block.props.name ? block.props.name
: placeholderMap['attachment']}</span : placeholderMap['attachment']
}</span
> >
${showPreviewIcon ${
showPreviewIcon
? html`<span class=${iconClass} ? html`<span class=${iconClass}
>${previewIconMap['attachment']}</span >${previewIconMap['attachment']}</span
>` >`
: nothing} : nothing
}
`; `;
default: default:
return nothing; return nothing;
@@ -963,7 +963,7 @@ export class ConnectionOverlay extends Overlay {
this._clearRect(); this._clearRect();
let result: Connection | null = null; let result: Connection | null = null;
// oxlint-disable-next-line @typescript-eslint/prefer-for-of // oxlint-disable-next-line typescript/prefer-for-of
for (let i = 0; i < connectables.length; i++) { for (let i = 0; i < connectables.length; i++) {
const connectable = connectables[i]; const connectable = connectables[i];
// first check if in excluedIds // first check if in excluedIds
@@ -357,22 +357,26 @@ export class EdgelessConnectorLabelEditor extends WithDisposable(
<rich-text <rich-text
.yText=${connector.text} .yText=${connector.text}
.enableFormat=${false} .enableFormat=${false}
style=${isEmpty style=${
isEmpty
? styleMap({ ? styleMap({
position: 'absolute', position: 'absolute',
left: 0, left: 0,
top: 0, top: 0,
padding: `${VERTICAL_PADDING}px ${HORIZONTAL_PADDING}px`, padding: `${VERTICAL_PADDING}px ${HORIZONTAL_PADDING}px`,
}) })
: nothing} : nothing
}
></rich-text> ></rich-text>
${isEmpty ${
isEmpty
? html` ? html`
<span class="edgeless-connector-label-editor-placeholder"> <span class="edgeless-connector-label-editor-placeholder">
Add text Add text
</span> </span>
` `
: nothing} : nothing
}
</div> </div>
`; `;
} }
@@ -53,12 +53,14 @@ export class EdgelessConnectorToolButton extends QuickToolMixin(
return html` return html`
<edgeless-tool-icon-button <edgeless-tool-icon-button
class="edgeless-connector-button" class="edgeless-connector-button"
.tooltip=${this.popper .tooltip=${
this.popper
? '' ? ''
: html`<affine-tooltip-content-with-shortcut : html`<affine-tooltip-content-with-shortcut
data-tip="${getConnectorModeName(mode)}" data-tip="${getConnectorModeName(mode)}"
data-shortcut="${'C'}" data-shortcut="${'C'}"
></affine-tooltip-content-with-shortcut>`} ></affine-tooltip-content-with-shortcut>`
}
.tooltipOffset=${17} .tooltipOffset=${17}
.active=${active} .active=${active}
.iconContainerPadding=${6} .iconContainerPadding=${6}
@@ -278,14 +278,16 @@ export class EdgelessMindmapMenu extends EdgelessToolbarToolMixin(
return html`<edgeless-slide-menu .height=${'64px'}> return html`<edgeless-slide-menu .height=${'64px'}>
<div class="text-and-mindmap"> <div class="text-and-mindmap">
<div class="media-item"> <div class="media-item">
${isDraggingMedia ${
isDraggingMedia
? html`<button ? html`<button
class="next" class="next"
style="transform: translateY(${showNextText ? 0 : 64}px)" style="transform: translateY(${showNextText ? 0 : 64}px)"
> >
${mediaItem.icon} ${mediaItem.icon}
</button>` </button>`
: nothing} : nothing
}
<button <button
style="opacity: ${isDraggingMedia ? 0 : 1}" style="opacity: ${isDraggingMedia ? 0 : 1}"
@mousedown=${(e: MouseEvent) => @mousedown=${(e: MouseEvent) =>
@@ -309,14 +311,16 @@ export class EdgelessMindmapMenu extends EdgelessToolbarToolMixin(
</div> </div>
<div class="thin-divider"></div> <div class="thin-divider"></div>
<div class="text-item"> <div class="text-item">
${isDraggingText ${
isDraggingText
? html`<button ? html`<button
class="next" class="next"
style="transform: translateY(${showNextText ? 0 : 64}px)" style="transform: translateY(${showNextText ? 0 : 64}px)"
> >
${textItem.icon} ${textItem.icon}
</button>` </button>`
: nothing} : nothing
}
<button <button
style="opacity: ${isDraggingText ? 0 : 1}" style="opacity: ${isDraggingText ? 0 : 1}"
@mousedown=${(e: MouseEvent) => @mousedown=${(e: MouseEvent) =>
@@ -350,14 +354,16 @@ export class EdgelessMindmapMenu extends EdgelessToolbarToolMixin(
const isActive = this._style$.value === mindMap.style; const isActive = this._style$.value === mindMap.style;
return html` return html`
<div class="mindmap-item" data-is-active=${isActive}> <div class="mindmap-item" data-is-active=${isActive}>
${isBeingDragged ${
isBeingDragged
? html`<button ? html`<button
style="transform: translateY(${showNext ? 0 : 64}px)" style="transform: translateY(${showNext ? 0 : 64}px)"
class="next" class="next"
> >
${mindMap.icon} ${mindMap.icon}
</button>` </button>`
: nothing} : nothing
}
<button <button
style="opacity: ${isBeingDragged ? 0 : 1}" style="opacity: ${isBeingDragged ? 0 : 1}"
@mousedown=${(e: MouseEvent) => { @mousedown=${(e: MouseEvent) => {
@@ -387,11 +393,13 @@ export class EdgelessMindmapMenu extends EdgelessToolbarToolMixin(
</div> </div>
`; `;
})} })}
${this.std.store ${
this.std.store
.get(FeatureFlagService) .get(FeatureFlagService)
.getFlag('enable_mind_map_import') .getFlag('enable_mind_map_import')
? this._importMindMapEntry() ? this._importMindMapEntry()
: nothing} : nothing
}
</div> </div>
</edgeless-slide-menu>`; </edgeless-slide-menu>`;
} }
@@ -374,7 +374,8 @@ export class EdgelessMindmapToolButton extends EdgelessToolbarToolMixin(
pointerEvents: draggingElement ? 'none' : 'auto', pointerEvents: draggingElement ? 'none' : 'auto',
}); });
return html`${isBeingDragged return html`${
isBeingDragged
? html`<div ? html`<div
class=${classMap({ class=${classMap({
'basket-tool-item': true, 'basket-tool-item': true,
@@ -385,7 +386,8 @@ export class EdgelessMindmapToolButton extends EdgelessToolbarToolMixin(
> >
${tool.icon} ${tool.icon}
</div>` </div>`
: nothing} : nothing
}
<div <div
style=${currentStyle} style=${currentStyle}
@@ -99,9 +99,11 @@ export class EdgelessNoteShadowPanel extends WithDisposable(LitElement) {
(shadow, index) => (shadow, index) =>
html`<style> html`<style>
.item-icon svg rect:first-of-type { .item-icon svg rect:first-of-type {
fill: ${this.background.startsWith('--') fill: ${
this.background.startsWith('--')
? `var(${this.background})` ? `var(${this.background})`
: this.background}; : this.background
};
} }
</style> </style>
<div <div
@@ -184,12 +184,14 @@ export class EdgelessNoteSeniorButton extends EdgelessToolbarToolMixin(
return html`<edgeless-toolbar-button return html`<edgeless-toolbar-button
class="edgeless-note-button" class="edgeless-note-button"
.tooltip=${this.popper .tooltip=${
this.popper
? '' ? ''
: html`<affine-tooltip-content-with-shortcut : html`<affine-tooltip-content-with-shortcut
data-tip="${'Note'}" data-tip="${'Note'}"
data-shortcut="${'N'}" data-shortcut="${'N'}"
></affine-tooltip-content-with-shortcut>`} ></affine-tooltip-content-with-shortcut>`
}
.tooltipOffset=${5} .tooltipOffset=${5}
> >
<div <div
@@ -89,12 +89,14 @@ export class EdgelessNoteToolButton extends QuickToolMixin(LitElement) {
return html` return html`
<edgeless-tool-icon-button <edgeless-tool-icon-button
class="edgeless-note-button" class="edgeless-note-button"
.tooltip=${this._noteMenu .tooltip=${
this._noteMenu
? '' ? ''
: html`<affine-tooltip-content-with-shortcut : html`<affine-tooltip-content-with-shortcut
data-tip="${'Note'}" data-tip="${'Note'}"
data-shortcut="${'N'}" data-shortcut="${'N'}"
></affine-tooltip-content-with-shortcut>`} ></affine-tooltip-content-with-shortcut>`
}
.tooltipOffset=${17} .tooltipOffset=${17}
.active=${active} .active=${active}
.iconContainerPadding=${6} .iconContainerPadding=${6}
@@ -47,9 +47,9 @@ export class EdgelessShapePanel extends LitElement {
this._onSelect(name); this._onSelect(name);
}} }}
> >
${this.shapeStyle === ShapeStyle.General ${
? generalIcon this.shapeStyle === ShapeStyle.General ? generalIcon : scribbledIcon
: scribbledIcon} }
</edgeless-tool-icon-button>` </edgeless-tool-icon-button>`
); );
} }
@@ -308,7 +308,8 @@ export class EdgelessToolbarShapeDraggable extends EdgelessToolbarToolMixin(
opacity: isBeingDragged ? 0 : 1, opacity: isBeingDragged ? 0 : 1,
}); });
const nextStyle = styleMap(baseStyle); const nextStyle = styleMap(baseStyle);
return html`${isBeingDragged return html`${
isBeingDragged
? html`<div ? html`<div
style=${nextStyle} style=${nextStyle}
class=${classMap({ class=${classMap({
@@ -319,7 +320,8 @@ export class EdgelessToolbarShapeDraggable extends EdgelessToolbarToolMixin(
> >
${shape.svg} ${shape.svg}
</div>` </div>`
: nothing} : nothing
}
<div <div
style=${currStyle} style=${currStyle}
class=${classMap({ class=${classMap({
Loaded 100 of 291 files, more files were not shown because too many files have changed in this diff. Show more