mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-04 16:44:56 +00:00
Compare commits
2 Commits
0.23.0-bet
...
preview-al
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
914e4baf82 | ||
|
|
bd268044b4 |
@@ -1,4 +1,4 @@
|
||||
import { ImageBlockModel } from '@blocksuite/affine-model';
|
||||
import { ImageBlockModel, TextAlign } from '@blocksuite/affine-model';
|
||||
import {
|
||||
ActionPlacement,
|
||||
type ToolbarModuleConfig,
|
||||
@@ -11,6 +11,9 @@ import {
|
||||
DeleteIcon,
|
||||
DownloadIcon,
|
||||
DuplicateIcon,
|
||||
TextAlignCenterIcon,
|
||||
TextAlignLeftIcon,
|
||||
TextAlignRightIcon,
|
||||
} from '@blocksuite/icons/lit';
|
||||
import { BlockFlavourIdentifier } from '@blocksuite/std';
|
||||
import type { ExtensionType } from '@blocksuite/store';
|
||||
@@ -49,6 +52,45 @@ const builtinToolbarConfig = {
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'c.1.align-left',
|
||||
tooltip: 'Align left',
|
||||
icon: TextAlignLeftIcon(),
|
||||
run(ctx) {
|
||||
const block = ctx.getCurrentBlockByType(ImageBlockComponent);
|
||||
if (block) {
|
||||
ctx.std.host.doc.updateBlock(block.model, {
|
||||
textAlign: TextAlign.Left,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'c.2.align-center',
|
||||
tooltip: 'Align center',
|
||||
icon: TextAlignCenterIcon(),
|
||||
run(ctx) {
|
||||
const block = ctx.getCurrentBlockByType(ImageBlockComponent);
|
||||
if (block) {
|
||||
ctx.std.host.doc.updateBlock(block.model, {
|
||||
textAlign: TextAlign.Center,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'c.3.align-right',
|
||||
tooltip: 'Align right',
|
||||
icon: TextAlignRightIcon(),
|
||||
run(ctx) {
|
||||
const block = ctx.getCurrentBlockByType(ImageBlockComponent);
|
||||
if (block) {
|
||||
ctx.std.host.doc.updateBlock(block.model, {
|
||||
textAlign: TextAlign.Right,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
placement: ActionPlacement.More,
|
||||
id: 'a.clipboard',
|
||||
|
||||
@@ -112,6 +112,15 @@ export class ImageBlockComponent extends CaptionedBlockComponent<ImageBlockModel
|
||||
width: '100%',
|
||||
});
|
||||
|
||||
const alignItemsStyleMap = styleMap({
|
||||
alignItems:
|
||||
this.model.props.textAlign$.value === 'left'
|
||||
? 'flex-start'
|
||||
: this.model.props.textAlign$.value === 'right'
|
||||
? 'flex-end'
|
||||
: undefined,
|
||||
});
|
||||
|
||||
return html`
|
||||
<div class="affine-image-container" style=${containerStyleMap}>
|
||||
${when(
|
||||
@@ -122,7 +131,11 @@ export class ImageBlockComponent extends CaptionedBlockComponent<ImageBlockModel
|
||||
.loading=${this.loading}
|
||||
.mode=${'page'}
|
||||
></affine-image-fallback-card>`,
|
||||
() => html`<affine-page-image .block=${this}></affine-page-image>`
|
||||
() =>
|
||||
html`<affine-page-image
|
||||
.block=${this}
|
||||
style="${alignItemsStyleMap}"
|
||||
></affine-page-image>`
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -144,6 +144,10 @@ export class ListBlockComponent extends CaptionedBlockComponent<ListBlockModel>
|
||||
|
||||
const listIcon = getListIcon(model, !collapsed, _onClickIcon);
|
||||
|
||||
const textAlignStyle = styleMap({
|
||||
textAlign: this.model.props.textAlign$?.value,
|
||||
});
|
||||
|
||||
const children = html`<div
|
||||
class="affine-block-children-container"
|
||||
style=${styleMap({
|
||||
@@ -155,7 +159,7 @@ export class ListBlockComponent extends CaptionedBlockComponent<ListBlockModel>
|
||||
</div>`;
|
||||
|
||||
return html`
|
||||
<div class=${'affine-list-block-container'}>
|
||||
<div class=${'affine-list-block-container'} style="${textAlignStyle}">
|
||||
<div
|
||||
class=${classMap({
|
||||
'affine-list-rich-text-wrapper': true,
|
||||
|
||||
@@ -4,9 +4,15 @@ import {
|
||||
textFormatConfigs,
|
||||
} from '@blocksuite/affine-inline-preset';
|
||||
import {
|
||||
type TextAlignConfig,
|
||||
textAlignConfigs,
|
||||
type TextConversionConfig,
|
||||
textConversionConfigs,
|
||||
} from '@blocksuite/affine-rich-text';
|
||||
import {
|
||||
getSelectedModelsCommand,
|
||||
getTextSelectionCommand,
|
||||
} from '@blocksuite/affine-shared/commands';
|
||||
import { isInsideBlockByFlavour } from '@blocksuite/affine-shared/utils';
|
||||
import {
|
||||
type SlashMenuActionItem,
|
||||
@@ -56,6 +62,10 @@ const noteSlashMenuConfig: SlashMenuConfig = {
|
||||
createConversionItem(config, `1_List@${index++}`)
|
||||
),
|
||||
|
||||
...textAlignConfigs.map((config, index) =>
|
||||
createAlignItem(config, `2_Align@${index++}`)
|
||||
),
|
||||
|
||||
...textFormatConfigs
|
||||
.filter(i => !['Code', 'Link'].includes(i.name))
|
||||
.map((config, index) =>
|
||||
@@ -85,6 +95,31 @@ function createConversionItem(
|
||||
};
|
||||
}
|
||||
|
||||
function createAlignItem(
|
||||
config: TextAlignConfig,
|
||||
group?: SlashMenuItem['group']
|
||||
): SlashMenuActionItem {
|
||||
const { textAlign, name, icon } = config;
|
||||
return {
|
||||
name,
|
||||
group,
|
||||
icon,
|
||||
action: ({ std }) => {
|
||||
std.command
|
||||
.chain()
|
||||
.pipe(getTextSelectionCommand)
|
||||
.pipe(getSelectedModelsCommand, { types: ['text'] })
|
||||
.pipe((ctx, next) => {
|
||||
ctx.selectedModels.forEach(model => {
|
||||
ctx.std.host.doc.updateBlock(model, { textAlign });
|
||||
});
|
||||
return next();
|
||||
})
|
||||
.run();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function createTextFormatItem(
|
||||
config: TextFormatConfig,
|
||||
group?: SlashMenuItem['group']
|
||||
|
||||
@@ -5,13 +5,17 @@ import {
|
||||
NoteBlockSchema,
|
||||
ParagraphBlockModel,
|
||||
} from '@blocksuite/affine-model';
|
||||
import { textConversionConfigs } from '@blocksuite/affine-rich-text';
|
||||
import {
|
||||
textAlignConfigs,
|
||||
textConversionConfigs,
|
||||
} from '@blocksuite/affine-rich-text';
|
||||
import {
|
||||
focusBlockEnd,
|
||||
focusBlockStart,
|
||||
getBlockSelectionsCommand,
|
||||
getNextBlockCommand,
|
||||
getPrevBlockCommand,
|
||||
getSelectedModelsCommand,
|
||||
getTextSelectionCommand,
|
||||
} from '@blocksuite/affine-shared/commands';
|
||||
import {
|
||||
@@ -157,6 +161,48 @@ class NoteKeymap {
|
||||
);
|
||||
};
|
||||
|
||||
private readonly _bindTextAlignHotKey = () => {
|
||||
return textAlignConfigs.reduce(
|
||||
(acc, item) => {
|
||||
const keymap = item.hotkey!.reduce(
|
||||
(acc, key) => {
|
||||
return {
|
||||
...acc,
|
||||
[key]: ctx => {
|
||||
ctx.get('defaultState').event.preventDefault();
|
||||
const [result] = this._std.command
|
||||
.chain()
|
||||
.tryAll(chain => [
|
||||
chain.pipe(getTextSelectionCommand),
|
||||
chain.pipe(getBlockSelectionsCommand),
|
||||
])
|
||||
.pipe(getSelectedModelsCommand, { types: ['text', 'block'] })
|
||||
.pipe((ctx, next) => {
|
||||
ctx.selectedModels.forEach(model => {
|
||||
ctx.std.host.doc.updateBlock(model, {
|
||||
textAlign: item.textAlign,
|
||||
});
|
||||
});
|
||||
return next();
|
||||
})
|
||||
.run();
|
||||
|
||||
return result;
|
||||
},
|
||||
};
|
||||
},
|
||||
{} as Record<string, UIEventHandler>
|
||||
);
|
||||
|
||||
return {
|
||||
...acc,
|
||||
...keymap,
|
||||
};
|
||||
},
|
||||
{} as Record<string, UIEventHandler>
|
||||
);
|
||||
};
|
||||
|
||||
private _focusBlock: BlockComponent | null = null;
|
||||
|
||||
private readonly _getClosestNoteByBlockId = (blockId: string) => {
|
||||
@@ -568,6 +614,7 @@ class NoteKeymap {
|
||||
...this._bindMoveBlockHotKey(),
|
||||
...this._bindQuickActionHotKey(),
|
||||
...this._bindTextConversionHotKey(),
|
||||
...this._bindTextAlignHotKey(),
|
||||
Tab: ctx => {
|
||||
const [success] = this.std.command.exec(indentBlocks);
|
||||
|
||||
|
||||
@@ -235,6 +235,10 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent<ParagraphBl
|
||||
`;
|
||||
}
|
||||
|
||||
const textAlignStyle = styleMap({
|
||||
textAlign: this.model.props.textAlign$?.value,
|
||||
});
|
||||
|
||||
const children = html`<div
|
||||
class="affine-block-children-container"
|
||||
style=${styleMap({
|
||||
@@ -256,6 +260,7 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent<ParagraphBl
|
||||
</style>
|
||||
<div
|
||||
class="affine-paragraph-block-container"
|
||||
style="${textAlignStyle}"
|
||||
data-has-collapsed-siblings="${collapsedSiblings.length > 0}"
|
||||
>
|
||||
<div
|
||||
|
||||
@@ -19,7 +19,11 @@ import {
|
||||
isFormatSupported,
|
||||
textFormatConfigs,
|
||||
} from '@blocksuite/affine-inline-preset';
|
||||
import { textConversionConfigs } from '@blocksuite/affine-rich-text';
|
||||
import type { TextAlign } from '@blocksuite/affine-model';
|
||||
import {
|
||||
textAlignConfigs,
|
||||
textConversionConfigs,
|
||||
} from '@blocksuite/affine-rich-text';
|
||||
import {
|
||||
copySelectedModelsCommand,
|
||||
deleteSelectedModelsCommand,
|
||||
@@ -39,6 +43,7 @@ import type {
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import { ActionPlacement } from '@blocksuite/affine-shared/services';
|
||||
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
||||
import { getMostCommonValue } from '@blocksuite/affine-shared/utils';
|
||||
import { tableViewMeta } from '@blocksuite/data-view/view-presets';
|
||||
import {
|
||||
CopyIcon,
|
||||
@@ -119,6 +124,72 @@ const conversionsActionGroup = {
|
||||
},
|
||||
} as const satisfies ToolbarActionGenerator;
|
||||
|
||||
const alignActionGroup = {
|
||||
id: 'b.align',
|
||||
when: ({ chain }) => isFormatSupported(chain).run()[0],
|
||||
generate({ chain }) {
|
||||
const [ok, { selectedModels = [] }] = chain
|
||||
.tryAll(chain => [
|
||||
chain.pipe(getTextSelectionCommand),
|
||||
chain.pipe(getBlockSelectionsCommand),
|
||||
])
|
||||
.pipe(getSelectedModelsCommand, { types: ['text', 'block'] })
|
||||
.run();
|
||||
if (!ok) return null;
|
||||
|
||||
const alignment =
|
||||
textAlignConfigs.find(
|
||||
({ textAlign }) =>
|
||||
textAlign ===
|
||||
getMostCommonValue(
|
||||
selectedModels.map(
|
||||
({ props }) => props as { textAlign?: TextAlign }
|
||||
),
|
||||
'textAlign'
|
||||
)
|
||||
) ?? textAlignConfigs[0];
|
||||
const update = (textAlign: TextAlign) => {
|
||||
chain
|
||||
.pipe((ctx, next) => {
|
||||
selectedModels.forEach(model => {
|
||||
ctx.std.host.doc.updateBlock(model, { textAlign });
|
||||
});
|
||||
return next();
|
||||
})
|
||||
.run();
|
||||
};
|
||||
|
||||
return {
|
||||
content: html`
|
||||
<editor-menu-button
|
||||
.contentPadding="${'8px'}"
|
||||
.button=${html`
|
||||
<editor-icon-button aria-label="Align" .tooltip="${'Align'}">
|
||||
${alignment.icon} ${ArrowDownSmallIcon()}
|
||||
</editor-icon-button>
|
||||
`}
|
||||
>
|
||||
<div data-size="large" data-orientation="vertical">
|
||||
${repeat(
|
||||
textAlignConfigs,
|
||||
item => item.name,
|
||||
({ textAlign, name, icon }) => html`
|
||||
<editor-menu-action
|
||||
aria-label=${name}
|
||||
?data-selected=${alignment.textAlign === textAlign}
|
||||
@click=${() => update(textAlign)}
|
||||
>
|
||||
${icon}<span class="label">${name}</span>
|
||||
</editor-menu-action>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
</editor-menu-button>
|
||||
`,
|
||||
};
|
||||
},
|
||||
} as const satisfies ToolbarActionGenerator;
|
||||
|
||||
const inlineTextActionGroup = {
|
||||
id: 'b.inline-text',
|
||||
when: ({ chain }) => isFormatSupported(chain).run()[0],
|
||||
@@ -269,6 +340,7 @@ const turnIntoLinkedDoc = {
|
||||
export const builtinToolbarConfig = {
|
||||
actions: [
|
||||
conversionsActionGroup,
|
||||
alignActionGroup,
|
||||
inlineTextActionGroup,
|
||||
highlightActionGroup,
|
||||
turnIntoDatabase,
|
||||
|
||||
@@ -144,6 +144,14 @@ export class TableBlockComponent extends CaptionedBlockComponent<TableBlockModel
|
||||
style=${styleMap({
|
||||
paddingLeft: `${virtualPadding}px`,
|
||||
paddingRight: `${virtualPadding}px`,
|
||||
marginLeft:
|
||||
this.model.props.textAlign$?.value === 'left'
|
||||
? undefined
|
||||
: 'auto',
|
||||
marginRight:
|
||||
this.model.props.textAlign$?.value === 'right'
|
||||
? undefined
|
||||
: 'auto',
|
||||
width: 'max-content',
|
||||
})}
|
||||
>
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
defineBlockSchema,
|
||||
} from '@blocksuite/store';
|
||||
|
||||
import type { TextAlign } from '../../consts';
|
||||
import type { BlockMeta } from '../../utils/types.js';
|
||||
import { ImageBlockTransformer } from './image-transformer.js';
|
||||
|
||||
@@ -19,6 +20,7 @@ export type ImageBlockProps = {
|
||||
height?: number;
|
||||
rotate: number;
|
||||
size?: number;
|
||||
textAlign?: TextAlign;
|
||||
} & Omit<GfxCommonBlockProps, 'scale'> &
|
||||
BlockMeta;
|
||||
|
||||
@@ -32,6 +34,7 @@ const defaultImageProps: ImageBlockProps = {
|
||||
lockedBySelf: false,
|
||||
rotate: 0,
|
||||
size: -1,
|
||||
textAlign: undefined,
|
||||
'meta:createdAt': undefined,
|
||||
'meta:createdBy': undefined,
|
||||
'meta:updatedAt': undefined,
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
defineBlockSchema,
|
||||
} from '@blocksuite/store';
|
||||
|
||||
import type { TextAlign } from '../../consts';
|
||||
import type { BlockMeta } from '../../utils/types';
|
||||
|
||||
// `toggle` type has been deprecated, do not use it
|
||||
@@ -13,6 +14,7 @@ export type ListType = 'bulleted' | 'numbered' | 'todo' | 'toggle';
|
||||
export type ListProps = {
|
||||
type: ListType;
|
||||
text: Text;
|
||||
textAlign?: TextAlign;
|
||||
checked: boolean;
|
||||
collapsed: boolean;
|
||||
order: number | null;
|
||||
@@ -24,6 +26,7 @@ export const ListBlockSchema = defineBlockSchema({
|
||||
({
|
||||
type: 'bulleted',
|
||||
text: internal.Text(),
|
||||
textAlign: undefined,
|
||||
checked: false,
|
||||
collapsed: false,
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
type Text,
|
||||
} from '@blocksuite/store';
|
||||
|
||||
import type { TextAlign } from '../../consts';
|
||||
import type { BlockMeta } from '../../utils/types';
|
||||
|
||||
export type ParagraphType =
|
||||
@@ -19,6 +20,7 @@ export type ParagraphType =
|
||||
|
||||
export type ParagraphProps = {
|
||||
type: ParagraphType;
|
||||
textAlign?: TextAlign;
|
||||
text: Text;
|
||||
collapsed: boolean;
|
||||
} & BlockMeta;
|
||||
@@ -28,6 +30,7 @@ export const ParagraphBlockSchema = defineBlockSchema({
|
||||
props: (internal): ParagraphProps => ({
|
||||
type: 'text',
|
||||
text: internal.Text(),
|
||||
textAlign: undefined,
|
||||
collapsed: false,
|
||||
'meta:createdAt': undefined,
|
||||
'meta:createdBy': undefined,
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
defineBlockSchema,
|
||||
} from '@blocksuite/store';
|
||||
|
||||
import type { TextAlign } from '../../consts';
|
||||
import type { BlockMeta } from '../../utils/types';
|
||||
|
||||
export type TableCell = {
|
||||
@@ -29,6 +30,7 @@ export interface TableBlockProps extends BlockMeta {
|
||||
columns: Record<string, TableColumn>;
|
||||
// key = `${rowId}:${columnId}`
|
||||
cells: Record<string, TableCell>;
|
||||
textAlign?: TextAlign;
|
||||
}
|
||||
|
||||
export interface TableCellSerialized {
|
||||
@@ -51,6 +53,7 @@ export const TableBlockSchema = defineBlockSchema({
|
||||
rows: {},
|
||||
columns: {},
|
||||
cells: {},
|
||||
textAlign: undefined,
|
||||
'meta:createdAt': undefined,
|
||||
'meta:createdBy': undefined,
|
||||
'meta:updatedAt': undefined,
|
||||
|
||||
35
blocksuite/affine/rich-text/src/align.ts
Normal file
35
blocksuite/affine/rich-text/src/align.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { TextAlign } from '@blocksuite/affine-model';
|
||||
import {
|
||||
TextAlignCenterIcon,
|
||||
TextAlignLeftIcon,
|
||||
TextAlignRightIcon,
|
||||
} from '@blocksuite/icons/lit';
|
||||
import type { TemplateResult } from 'lit';
|
||||
|
||||
export interface TextAlignConfig {
|
||||
textAlign: TextAlign;
|
||||
name: string;
|
||||
hotkey: string[] | null;
|
||||
icon: TemplateResult<1>;
|
||||
}
|
||||
|
||||
export const textAlignConfigs: TextAlignConfig[] = [
|
||||
{
|
||||
textAlign: TextAlign.Left,
|
||||
name: 'Align left',
|
||||
hotkey: [`Mod-Shift-L`],
|
||||
icon: TextAlignLeftIcon(),
|
||||
},
|
||||
{
|
||||
textAlign: TextAlign.Center,
|
||||
name: 'Align center',
|
||||
hotkey: [`Mod-Shift-E`],
|
||||
icon: TextAlignCenterIcon(),
|
||||
},
|
||||
{
|
||||
textAlign: TextAlign.Right,
|
||||
name: 'Align right',
|
||||
hotkey: [`Mod-Shift-R`],
|
||||
icon: TextAlignRightIcon(),
|
||||
},
|
||||
];
|
||||
@@ -1,3 +1,4 @@
|
||||
export { type TextAlignConfig, textAlignConfigs } from './align';
|
||||
export { type TextConversionConfig, textConversionConfigs } from './conversion';
|
||||
export {
|
||||
asyncGetRichText,
|
||||
|
||||
@@ -38,6 +38,9 @@ type KeyboardShortcutsI18NKeys =
|
||||
| 'bodyText'
|
||||
| 'increaseIndent'
|
||||
| 'reduceIndent'
|
||||
| 'alignLeft'
|
||||
| 'alignCenter'
|
||||
| 'alignRight'
|
||||
| 'groupDatabase'
|
||||
| 'moveUp'
|
||||
| 'moveDown'
|
||||
@@ -185,6 +188,9 @@ export const useMacPageKeyboardShortcuts = (): ShortcutMap => {
|
||||
[tH('6')]: ['⌘', '⌥', '6'],
|
||||
[t('increaseIndent')]: ['Tab'],
|
||||
[t('reduceIndent')]: ['⇧', 'Tab'],
|
||||
[t('alignLeft')]: ['⌘', '⇧', 'L'],
|
||||
[t('alignCenter')]: ['⌘', '⇧', 'E'],
|
||||
[t('alignRight')]: ['⌘', '⇧', 'R'],
|
||||
[t('groupDatabase')]: ['⌘', 'G'],
|
||||
[t('switch')]: ['⌥', 'S'],
|
||||
// not implement yet
|
||||
@@ -242,6 +248,9 @@ export const useWinPageKeyboardShortcuts = (): ShortcutMap => {
|
||||
[tH('6')]: ['Ctrl', 'Shift', '6'],
|
||||
[t('increaseIndent')]: ['Tab'],
|
||||
[t('reduceIndent')]: ['Shift+Tab'],
|
||||
[t('alignLeft')]: ['Ctrl', 'Shift', 'L'],
|
||||
[t('alignCenter')]: ['Ctrl', 'Shift', 'E'],
|
||||
[t('alignRight')]: ['Ctrl', 'Shift', 'R'],
|
||||
[t('groupDatabase')]: ['Ctrl + G'],
|
||||
['Switch']: ['Alt + S'],
|
||||
// not implement yet
|
||||
|
||||
@@ -2401,6 +2401,18 @@ export function useAFFiNEI18N(): {
|
||||
* `Just now`
|
||||
*/
|
||||
["com.affine.just-now"](): string;
|
||||
/**
|
||||
* `Align center`
|
||||
*/
|
||||
["com.affine.keyboardShortcuts.alignCenter"](): string;
|
||||
/**
|
||||
* `Align left`
|
||||
*/
|
||||
["com.affine.keyboardShortcuts.alignLeft"](): string;
|
||||
/**
|
||||
* `Align right`
|
||||
*/
|
||||
["com.affine.keyboardShortcuts.alignRight"](): string;
|
||||
/**
|
||||
* `Append to daily note`
|
||||
*/
|
||||
|
||||
@@ -600,6 +600,9 @@
|
||||
"com.affine.journal.daily-count-updated-empty-tips": "You haven't updated anything yet",
|
||||
"com.affine.journal.updated-today": "Updated",
|
||||
"com.affine.just-now": "Just now",
|
||||
"com.affine.keyboardShortcuts.alignCenter": "Align center",
|
||||
"com.affine.keyboardShortcuts.alignLeft": "Align left",
|
||||
"com.affine.keyboardShortcuts.alignRight": "Align right",
|
||||
"com.affine.keyboardShortcuts.appendDailyNote": "Append to daily note",
|
||||
"com.affine.keyboardShortcuts.bodyText": "Body text",
|
||||
"com.affine.keyboardShortcuts.bold": "Bold",
|
||||
|
||||
@@ -593,6 +593,9 @@
|
||||
"com.affine.journal.daily-count-updated-empty-tips": "你还没有任何更新",
|
||||
"com.affine.journal.updated-today": "更新",
|
||||
"com.affine.just-now": "就是现在",
|
||||
"com.affine.keyboardShortcuts.alignCenter": "居中对齐",
|
||||
"com.affine.keyboardShortcuts.alignLeft": "左对齐",
|
||||
"com.affine.keyboardShortcuts.alignRight": "右对齐",
|
||||
"com.affine.keyboardShortcuts.appendDailyNote": "添加日常笔记快捷键",
|
||||
"com.affine.keyboardShortcuts.bodyText": "正文",
|
||||
"com.affine.keyboardShortcuts.bold": "粗体",
|
||||
|
||||
@@ -593,6 +593,9 @@
|
||||
"com.affine.journal.daily-count-updated-empty-tips": "你還沒有任何更新",
|
||||
"com.affine.journal.updated-today": "更新",
|
||||
"com.affine.just-now": "就是現在",
|
||||
"com.affine.keyboardShortcuts.alignCenter": "置中對齊",
|
||||
"com.affine.keyboardShortcuts.alignLeft": "靠左對齊",
|
||||
"com.affine.keyboardShortcuts.alignRight": "靠右對齊",
|
||||
"com.affine.keyboardShortcuts.appendDailyNote": "附加到隨筆",
|
||||
"com.affine.keyboardShortcuts.bodyText": "正文",
|
||||
"com.affine.keyboardShortcuts.bold": "粗體",
|
||||
|
||||
Reference in New Issue
Block a user