mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-27 03:54:57 +02:00
Text & Table cell color styling features (#7624)
Signed-off-by: Victor Ilyushchenko <alt13ri@gmail.com>
This commit is contained in:
Generated
+11
-1
@@ -6254,6 +6254,14 @@ packages:
|
||||
'@tiptap/core': 2.6.6(@tiptap/pm@2.6.6)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-text-style@2.11.0(@tiptap/core@2.6.6):
|
||||
resolution: {integrity: sha512-vuA16wMZ6J3fboL7FObwV2f5uN9Vg0WYmqU7971vxzJyaRj9VE1eeH8Kh5fq4RgwDzc13MZGvZZV4HcE1R8o8A==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.6.6(@tiptap/pm@2.6.6)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-text@2.6.6(@tiptap/core@2.6.6):
|
||||
resolution: {integrity: sha512-e84uILnRzNzcwK1DVQNpXVmBG1Cq3BJipTOIDl1LHifOok7MBjhI/X+/NR0bd3N2t6gmDTWi63+4GuJ5EeDmsg==}
|
||||
peerDependencies:
|
||||
@@ -32495,6 +32503,7 @@ packages:
|
||||
'@tiptap/extension-table-header': 2.6.6(@tiptap/core@2.6.6)
|
||||
'@tiptap/extension-table-row': 2.6.6(@tiptap/core@2.6.6)
|
||||
'@tiptap/extension-text-align': 2.11.0(@tiptap/core@2.6.6)
|
||||
'@tiptap/extension-text-style': 2.11.0(@tiptap/core@2.6.6)
|
||||
'@tiptap/extension-typography': 2.6.6(@tiptap/core@2.6.6)
|
||||
'@tiptap/extension-underline': 2.6.6(@tiptap/core@2.6.6)
|
||||
'@tiptap/pm': 2.6.6
|
||||
@@ -32639,7 +32648,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/text.tgz(@types/node@20.11.19)(bufferutil@4.0.8)(esbuild@0.24.2)(ts-node@10.9.2)(utf-8-validate@6.0.4):
|
||||
resolution: {integrity: sha512-zmM6GDzeNuMbMA7iWwhg8hBc43fylNW7cEmk0fSWw9+G9NqD2MLv2dVb5dnAcPAioj9WBdDakWcrLAAHUBJyMw==, tarball: file:projects/text.tgz}
|
||||
resolution: {integrity: sha512-p2TRL6FgtqVBooDf+E5A4HB+45VS03IvNxudhC9gCotewS726ZLOxl2XdfeuYB2rHYbzdmmiG2zb8GbPwqTkOw==, tarball: file:projects/text.tgz}
|
||||
id: file:projects/text.tgz
|
||||
name: '@rush-temp/text'
|
||||
version: 0.0.0
|
||||
@@ -32660,6 +32669,7 @@ packages:
|
||||
'@tiptap/extension-task-item': 2.6.6(@tiptap/core@2.6.6)(@tiptap/pm@2.6.6)
|
||||
'@tiptap/extension-task-list': 2.6.6(@tiptap/core@2.6.6)
|
||||
'@tiptap/extension-text-align': 2.11.0(@tiptap/core@2.6.6)
|
||||
'@tiptap/extension-text-style': 2.11.0(@tiptap/core@2.6.6)
|
||||
'@tiptap/extension-typography': 2.6.6(@tiptap/core@2.6.6)
|
||||
'@tiptap/extension-underline': 2.6.6(@tiptap/core@2.6.6)
|
||||
'@tiptap/html': 2.6.6(@tiptap/core@2.6.6)(@tiptap/pm@2.6.6)
|
||||
|
||||
@@ -247,6 +247,18 @@ export function createModel (builder: Builder): void {
|
||||
index: 20
|
||||
})
|
||||
|
||||
builder.createDoc(textEditor.class.TextEditorAction, core.space.Model, {
|
||||
action: textEditor.function.SetTextColor,
|
||||
icon: textEditor.icon.TextStyle,
|
||||
visibilityTester: textEditor.function.IsTextStylingEnabled,
|
||||
isActive: {
|
||||
name: 'textStyle'
|
||||
},
|
||||
label: textEditor.string.SetTextColor,
|
||||
category: 20,
|
||||
index: 25
|
||||
})
|
||||
|
||||
// Link category
|
||||
builder.createDoc(textEditor.class.TextEditorAction, core.space.Model, {
|
||||
action: textEditor.function.FormatLink,
|
||||
@@ -338,23 +350,36 @@ export function createModel (builder: Builder): void {
|
||||
index: 10
|
||||
})
|
||||
|
||||
// Table cell category
|
||||
builder.createDoc(textEditor.class.TextEditorAction, core.space.Model, {
|
||||
kind: 'table',
|
||||
action: textEditor.function.SetBackgroundColor,
|
||||
icon: textEditor.icon.Brush,
|
||||
visibilityTester: textEditor.function.IsTableToolbarContext,
|
||||
label: textEditor.string.SetCellHighlightColor,
|
||||
category: 65,
|
||||
index: 5
|
||||
})
|
||||
|
||||
// Table category
|
||||
builder.createDoc(textEditor.class.TextEditorAction, core.space.Model, {
|
||||
kind: 'table',
|
||||
action: textEditor.function.SelectTable,
|
||||
icon: textEditor.icon.SelectTable,
|
||||
visibilityTester: textEditor.function.IsTableToolbarContext,
|
||||
label: textEditor.string.SelectTable,
|
||||
category: 70,
|
||||
index: 5
|
||||
index: 15
|
||||
})
|
||||
|
||||
builder.createDoc(textEditor.class.TextEditorAction, core.space.Model, {
|
||||
kind: 'table',
|
||||
action: textEditor.function.OpenTableOptions,
|
||||
icon: textEditor.icon.TableProps,
|
||||
visibilityTester: textEditor.function.IsTableToolbarContext,
|
||||
label: textEditor.string.TableOptions,
|
||||
category: 70,
|
||||
index: 10
|
||||
index: 20
|
||||
})
|
||||
|
||||
// Image align category
|
||||
|
||||
@@ -36,9 +36,13 @@ export default mergeIds(textEditorId, textEditor, {
|
||||
IsTableToolbarContext: '' as Resource<TextActionVisibleFunction>,
|
||||
IsEditableNote: '' as Resource<TextActionVisibleFunction>,
|
||||
IsEditable: '' as Resource<TextActionVisibleFunction>,
|
||||
IsTextStylingEnabled: '' as Resource<TextActionVisibleFunction>,
|
||||
IsHeadingVisible: '' as Resource<TextActionVisibleFunction>,
|
||||
|
||||
CreateInlineComment: '' as Resource<TextActionFunction>,
|
||||
ShouldShowCreateInlineCommentAction: '' as Resource<TextActionVisibleFunction>
|
||||
ShouldShowCreateInlineCommentAction: '' as Resource<TextActionVisibleFunction>,
|
||||
|
||||
SetBackgroundColor: '' as Resource<TextActionFunction>,
|
||||
SetTextColor: '' as Resource<TextActionFunction>
|
||||
}
|
||||
})
|
||||
|
||||
@@ -64,7 +64,8 @@
|
||||
"prosemirror-codemark": "^0.4.2",
|
||||
"markdown-it": "^14.0.0",
|
||||
"fast-equals": "^5.0.1",
|
||||
"@tiptap/extension-text-align": "~2.11.0"
|
||||
"@tiptap/extension-text-align": "~2.11.0",
|
||||
"@tiptap/extension-text-style": "~2.11.0"
|
||||
},
|
||||
"repository": "https://github.com/hcengineering/platform",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -22,6 +22,7 @@ export * from './markup/utils'
|
||||
export * from './nodes'
|
||||
// export * from './ydoc'
|
||||
export * from './marks/code'
|
||||
export * from './marks/colors'
|
||||
export * from './marks/noteBase'
|
||||
export * from './markdown'
|
||||
export * from './markdown/serializer'
|
||||
@@ -31,3 +32,5 @@ export * from './markdown/node'
|
||||
|
||||
export * from './kits/default-kit'
|
||||
export * from './kits/server-kit'
|
||||
|
||||
export { TextStyle, type TextStyleOptions } from '@tiptap/extension-text-style'
|
||||
|
||||
@@ -34,6 +34,8 @@ import { CodeExtension, codeOptions } from '../marks/code'
|
||||
import { NoteBaseExtension } from '../marks/noteBase'
|
||||
import { CommentNode } from '../nodes/comment'
|
||||
import TextAlign from '@tiptap/extension-text-align'
|
||||
import TextStyle from '@tiptap/extension-text-style'
|
||||
import { BackgroundColor, TextColor } from '../marks/colors'
|
||||
|
||||
const headingLevels: Level[] = [1, 2, 3, 4, 5, 6]
|
||||
|
||||
@@ -97,7 +99,10 @@ export const ServerKit = Extension.create<ServerKitOptions>({
|
||||
ReferenceNode,
|
||||
CommentNode,
|
||||
NodeUuid,
|
||||
NoteBaseExtension
|
||||
NoteBaseExtension,
|
||||
TextStyle.configure({}),
|
||||
TextColor.configure({}),
|
||||
BackgroundColor.configure({ types: ['tableCell'] })
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
//
|
||||
// Copyright © 2025 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Extension } from '@tiptap/core'
|
||||
import '@tiptap/extension-text-style'
|
||||
|
||||
export interface BackgroundColorOptions {
|
||||
types: string[]
|
||||
}
|
||||
|
||||
declare module '@tiptap/core' {
|
||||
interface Commands<ReturnType> {
|
||||
colors: {
|
||||
setTextColor: (color: string) => ReturnType
|
||||
unsetTextColor: () => ReturnType
|
||||
setBackgroundColor: (color: string) => ReturnType
|
||||
unsetBackgroundColor: () => ReturnType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const BackgroundColor = Extension.create<BackgroundColorOptions>({
|
||||
name: 'backgroundColor',
|
||||
|
||||
addOptions () {
|
||||
return {
|
||||
types: []
|
||||
}
|
||||
},
|
||||
|
||||
addGlobalAttributes () {
|
||||
return [
|
||||
{
|
||||
types: this.options.types,
|
||||
attributes: {
|
||||
backgroundColor: {
|
||||
parseHTML: (element) => {
|
||||
return element.getAttribute('data-background-color') ?? undefined
|
||||
},
|
||||
renderHTML: (attributes) => {
|
||||
if (typeof attributes.backgroundColor !== 'string') {
|
||||
return {}
|
||||
}
|
||||
|
||||
return {
|
||||
'data-background-color': attributes.backgroundColor,
|
||||
style: `background-color: ${attributes.backgroundColor}`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
addCommands () {
|
||||
return {
|
||||
setBackgroundColor:
|
||||
(backgroundColor: string) =>
|
||||
({ commands }) => {
|
||||
return this.options.types
|
||||
.map((type) => commands.updateAttributes(type, { backgroundColor }))
|
||||
.every((response) => response)
|
||||
},
|
||||
|
||||
unsetBackgroundColor:
|
||||
() =>
|
||||
({ commands }) => {
|
||||
return this.options.types
|
||||
.map((type) => commands.resetAttributes(type, 'backgroundColor'))
|
||||
.every((response) => response)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export interface TextColorOptions {
|
||||
types: string[]
|
||||
}
|
||||
|
||||
export const TextColor = Extension.create<TextColorOptions>({
|
||||
name: 'textColor',
|
||||
|
||||
addOptions () {
|
||||
return {
|
||||
types: ['textStyle']
|
||||
}
|
||||
},
|
||||
|
||||
addGlobalAttributes () {
|
||||
return [
|
||||
{
|
||||
types: this.options.types,
|
||||
attributes: {
|
||||
color: {
|
||||
parseHTML: (element) => {
|
||||
return element.getAttribute('data-color') ?? undefined
|
||||
},
|
||||
renderHTML: (attributes) => {
|
||||
if (typeof attributes.color !== 'string') {
|
||||
return {}
|
||||
}
|
||||
|
||||
return {
|
||||
'data-color': attributes.color,
|
||||
style: `color: ${attributes.color}`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
addCommands () {
|
||||
return {
|
||||
setTextColor:
|
||||
(color: string) =>
|
||||
({ chain }) => {
|
||||
return chain().setMark('textStyle', { color }).run()
|
||||
},
|
||||
|
||||
unsetTextColor:
|
||||
() =>
|
||||
({ chain }) => {
|
||||
return chain().setMark('textStyle', { color: null }).removeEmptyTextStyle().run()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -248,6 +248,28 @@
|
||||
--theme-text-editor-note-anchor-bg-primary: #688797;
|
||||
--theme-text-editor-note-anchor-bg-primary-light: #747C81;
|
||||
|
||||
--text-editor-table-border-color: hsl(220, 6%, 40%);
|
||||
|
||||
--theme-text-editor-palette-text-gray: rgba(155, 155, 155, 1);
|
||||
--theme-text-editor-palette-text-brown: rgba(186, 133, 111, 1);
|
||||
--theme-text-editor-palette-text-orange: rgba(199, 125, 72, 1);
|
||||
--theme-text-editor-palette-text-yellow: rgba(202, 152, 73, 1);
|
||||
--theme-text-editor-palette-text-green: rgba(82, 158, 114, 1);
|
||||
--theme-text-editor-palette-text-blue: rgba(94, 135, 201, 1);
|
||||
--theme-text-editor-palette-text-purple: rgba(157, 104, 211, 1);
|
||||
--theme-text-editor-palette-text-pink: rgba(209, 87, 150, 1);
|
||||
--theme-text-editor-palette-text-red: rgba(223, 84, 82, 1);
|
||||
|
||||
--theme-text-editor-palette-bg-gray: rgba(47, 47, 47, 1);
|
||||
--theme-text-editor-palette-bg-brown: rgba(74, 50, 40, 1);
|
||||
--theme-text-editor-palette-bg-orange: rgba(92, 59, 35, 1);
|
||||
--theme-text-editor-palette-bg-yellow: rgba(86, 67, 40, 1);
|
||||
--theme-text-editor-palette-bg-green: rgba(36, 61, 48, 1);
|
||||
--theme-text-editor-palette-bg-blue: rgba(20, 58, 78, 1);
|
||||
--theme-text-editor-palette-bg-purple: rgba(60, 45, 73, 1);
|
||||
--theme-text-editor-palette-bg-pink: rgba(78, 44, 60, 1);
|
||||
--theme-text-editor-palette-bg-red:rgba(82, 46, 42, 1);
|
||||
|
||||
--accent-bg-color: #27282b;
|
||||
--accent-shadow: rgb(0 0 0 / 10%) 0px 2px 4px;
|
||||
|
||||
@@ -507,6 +529,28 @@
|
||||
--theme-text-editor-note-anchor-bg-primary: #AAC5E9;
|
||||
--theme-text-editor-note-anchor-bg-primary-light: #D5E5F5;
|
||||
|
||||
--text-editor-table-border-color: #c9cbcd;
|
||||
|
||||
--theme-text-editor-palette-text-gray: rgba(120, 119, 116, 1);
|
||||
--theme-text-editor-palette-text-brown: rgba(159, 107, 83, 1);
|
||||
--theme-text-editor-palette-text-orange: rgba(217, 115, 13, 1);
|
||||
--theme-text-editor-palette-text-yellow: rgba(203, 145, 47, 1);
|
||||
--theme-text-editor-palette-text-green: rgba(68, 131, 97, 1);
|
||||
--theme-text-editor-palette-text-blue: rgba(51, 126, 169, 1);
|
||||
--theme-text-editor-palette-text-purple: rgba(144, 101, 176, 1);
|
||||
--theme-text-editor-palette-text-pink: rgba(193, 76, 138, 1);
|
||||
--theme-text-editor-palette-text-red: rgba(212, 76, 71, 1);
|
||||
|
||||
--theme-text-editor-palette-bg-gray: rgba(241, 241, 239, 1);
|
||||
--theme-text-editor-palette-bg-brown: rgba(244, 238, 238, 1);
|
||||
--theme-text-editor-palette-bg-orange: rgba(251, 236, 221, 1);
|
||||
--theme-text-editor-palette-bg-yellow: rgba(251, 243, 219, 1);
|
||||
--theme-text-editor-palette-bg-green: rgba(237, 243, 236, 1);
|
||||
--theme-text-editor-palette-bg-blue: rgba(231, 243, 248, 1);
|
||||
--theme-text-editor-palette-bg-purple: rgba(244, 240, 247, 0.8);
|
||||
--theme-text-editor-palette-bg-pink: rgba(249, 238, 243, 0.8);
|
||||
--theme-text-editor-palette-bg-red: rgba(253, 235, 236, 1);
|
||||
|
||||
--accent-bg-color: #eff0f2; // HZ
|
||||
--accent-shadow: rgb(0 0 0 / 10%) 0px 2px 4px; // Dark
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ table.proseTable {
|
||||
th {
|
||||
min-width: 1rem;
|
||||
height: 2rem;
|
||||
border: 1px solid var(--button-border-hover);
|
||||
border: 1px solid var(--text-editor-table-border-color);
|
||||
padding: .25rem .5rem;
|
||||
vertical-align: top;
|
||||
box-sizing: border-box;
|
||||
|
||||
@@ -214,4 +214,11 @@
|
||||
<path d="M3 6C3 4.34315 4.34315 3 6 3H17C18.6569 3 20 4.34315 20 6V10.5556V17C20 18.6569 18.6569 20 17 20H10.5556H6C4.34314 20 3 18.6569 3 17V6Z" stroke="currentColor" stroke-width="2"/>
|
||||
<path d="M12 15C12 13.3431 13.3431 12 15 12H26C27.6569 12 29 13.3431 29 15V26C29 27.6569 27.6569 29 26 29H15C13.3431 29 12 27.6569 12 26V15Z" stroke="currentColor" stroke-width="2"/>
|
||||
</symbol>
|
||||
<symbol id="brush" viewBox="0 0 14 14" fill="none">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.9142 1.08579L13.4142 2.58579C14.1952 3.36683 14.1952 4.63316 13.4142 5.41421L6.91416 11.9142C6.52365 12.3047 6.01183 12.5 5.5 12.5H4L2.5 13.5L0.5 12.5L2 10.5V9C2 8.48816 2.19526 7.97631 2.58579 7.58579L9.08579 1.08579C9.86684 0.304738 11.1332 0.304738 11.9142 1.08579ZM6.20705 11.2071C6.01161 11.4025 5.75745 11.5 5.5 11.5H4H3V9C3 8.74253 3.09744 8.48835 3.29289 8.29289L4.43936 7.14643L7.35354 10.0606L6.20705 11.2071ZM8.06065 9.35351L5.14646 6.43932L9.79289 1.79289C10.1834 1.40237 10.8166 1.40238 11.2071 1.79289L12.707 3.29289C13.0976 3.68342 13.0976 4.31658 12.707 4.70711L8.06065 9.35351Z" fill="currentColor"/>
|
||||
</symbol>
|
||||
<symbol id="textStyle" viewBox="0 0 16 16" fill="none">
|
||||
<path d="M13 12H3V14H13V12Z" fill="currentColor"/>
|
||||
<path d="M11 10.5H12L8.69037 2.46234C8.57518 2.18258 8.30254 2 8 2C7.69746 2 7.42482 2.18258 7.30963 2.46234L4 10.5H5L5.805 8.5H10.175L11 10.5ZM6.215 7.5L7.935 3.315H8.065L9.77 7.5H6.215Z" fill="currentColor"/>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 24 KiB |
@@ -66,6 +66,8 @@
|
||||
"MermaidDiargram": "Diagram",
|
||||
"Comment": "Comment",
|
||||
"AddComment": "Add a comment",
|
||||
"AddCommentPlaceholder": "Add a comment..."
|
||||
"AddCommentPlaceholder": "Add a comment...",
|
||||
"SetCellHighlightColor": "Set cell color",
|
||||
"SetTextColor": "Set text color"
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,8 @@
|
||||
"MermaidDiargram": "Диаграмма",
|
||||
"Comment": "Комментарий",
|
||||
"AddComment": "Добавить комментарий",
|
||||
"AddCommentPlaceholder": "Добавьте комментарий..."
|
||||
"AddCommentPlaceholder": "Добавьте комментарий...",
|
||||
"SetCellHighlightColor": "Изменить цвет ячеек",
|
||||
"SetTextColor": "Изменить цвет текста"
|
||||
}
|
||||
}
|
||||
@@ -43,5 +43,7 @@ loadMetadata(textEditor.icon, {
|
||||
Comment: `${icons}#comment`,
|
||||
SelectTable: `${icons}#move`,
|
||||
MergeCells: `${icons}#union`,
|
||||
SplitCells: `${icons}#divide`
|
||||
SplitCells: `${icons}#divide`,
|
||||
Brush: `${icons}#brush`,
|
||||
TextStyle: `${icons}#textStyle`
|
||||
})
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// Copyright © 2025 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { getEventPositionElement, showPopup } from '@hcengineering/ui'
|
||||
import { type Editor } from '@tiptap/core'
|
||||
import ColorPicker from './popups/ColorPicker.svelte'
|
||||
import { type ActionContext } from '@hcengineering/text-editor'
|
||||
|
||||
export interface BackgroundColorOptions {
|
||||
types: string[]
|
||||
}
|
||||
|
||||
interface ColorSpec {
|
||||
color: string
|
||||
preview?: string
|
||||
}
|
||||
|
||||
function colorVar (tag: string, prefix = 'text'): string {
|
||||
return `var(--theme-text-editor-palette-${prefix}-${tag})`
|
||||
}
|
||||
|
||||
function colorSpec (tag: string, prefix = 'text'): ColorSpec {
|
||||
const color = colorVar(tag, prefix)
|
||||
return { color, preview: colorVar(tag) }
|
||||
}
|
||||
|
||||
const palette = {
|
||||
background: [
|
||||
{ color: 'transparent' },
|
||||
colorSpec('gray', 'bg'),
|
||||
colorSpec('brown', 'bg'),
|
||||
colorSpec('orange', 'bg'),
|
||||
colorSpec('yellow', 'bg'),
|
||||
colorSpec('green', 'bg'),
|
||||
colorSpec('blue', 'bg'),
|
||||
colorSpec('purple', 'bg'),
|
||||
colorSpec('pink', 'bg'),
|
||||
colorSpec('red', 'bg')
|
||||
],
|
||||
text: [
|
||||
{ color: 'var(--theme-text-color-primary)' },
|
||||
colorSpec('gray'),
|
||||
colorSpec('brown'),
|
||||
colorSpec('orange'),
|
||||
colorSpec('yellow'),
|
||||
colorSpec('green'),
|
||||
colorSpec('blue'),
|
||||
colorSpec('purple'),
|
||||
colorSpec('pink'),
|
||||
colorSpec('red')
|
||||
]
|
||||
}
|
||||
|
||||
export async function openBackgroundColorOptions (editor: Editor, event: MouseEvent): Promise<void> {
|
||||
await new Promise<void>((resolve) => {
|
||||
showPopup(ColorPicker, { palette: palette.background }, getEventPositionElement(event), (val) => {
|
||||
const color: string | undefined = val?.color
|
||||
if (color === undefined) return
|
||||
|
||||
if (color === 'transparent') {
|
||||
editor.commands.unsetBackgroundColor()
|
||||
} else {
|
||||
editor.commands.setBackgroundColor(color)
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export async function openTextColorOptions (editor: Editor, event: MouseEvent): Promise<void> {
|
||||
await new Promise<void>((resolve) => {
|
||||
showPopup(ColorPicker, { palette: palette.text }, getEventPositionElement(event), (val) => {
|
||||
const color: string | undefined = val?.color
|
||||
if (color === undefined) return
|
||||
|
||||
if (color === 'var(--theme-text-color-primary)') {
|
||||
editor.commands.unsetTextColor()
|
||||
} else {
|
||||
editor.commands.setTextColor(color)
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export async function isTextStylingEnabled (editor: Editor, context: ActionContext): Promise<boolean> {
|
||||
return editor.isEditable && editor.commands.setTextColor !== undefined
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<!--
|
||||
// Copyright © 2025 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { Card } from '@hcengineering/presentation'
|
||||
|
||||
export let palette: Array<{ color: string, preview?: string }> = [{ color: 'transparent' }]
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function handleSubmit (color: { color: string }): void {
|
||||
dispatch('close', color)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="picker">
|
||||
<div class="palette">
|
||||
{#each palette as k}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="colorBox"
|
||||
style:background-color={k.preview ?? k.color}
|
||||
on:click={() => {
|
||||
handleSubmit(k)
|
||||
}}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.picker {
|
||||
background: var(--theme-popup-color);
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: var(--theme-popup-shadow);
|
||||
padding: 0.5rem;
|
||||
margin-left: -4rem;
|
||||
}
|
||||
|
||||
.palette {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.colorBox {
|
||||
position: relative;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
border: 1px solid var(--theme-button-border);
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@@ -200,7 +200,7 @@
|
||||
.table-toolbar-container {
|
||||
position: absolute;
|
||||
top: -1.5rem;
|
||||
right: 0;
|
||||
right: var(--table-offscreen-spacing);
|
||||
z-index: 200;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -50,15 +50,34 @@
|
||||
actions = out
|
||||
}
|
||||
|
||||
$: actionsQuery.query(textEditor.class.TextEditorAction, { category: 70 }, (result) => {
|
||||
$: actionsQuery.query(textEditor.class.TextEditorAction, { kind: 'table' }, (result) => {
|
||||
void updateActions([...result], actionCtx)
|
||||
})
|
||||
|
||||
$: categories = actions.reduce<[number, TextEditorAction][][]>((acc, action) => {
|
||||
const { category, index } = action
|
||||
if (acc[category] === undefined) acc[category] = []
|
||||
acc[category].push([index, action])
|
||||
return acc
|
||||
}, [])
|
||||
|
||||
$: categories.forEach((category) => {
|
||||
category.sort((a, b) => a[0] - b[0])
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="table-toolbar flex" contenteditable="false">
|
||||
{#each actions as action}
|
||||
<TextActionButton {action} {editor} size="small" {actionCtx} blockMouseEvents={false} />
|
||||
{/each}
|
||||
<div class="text-editor-toolbar buttons-group xsmall-gap">
|
||||
{#each Object.values(categories) as category, index}
|
||||
{#if index > 0}
|
||||
<div class="buttons-divider" />
|
||||
{/if}
|
||||
|
||||
{#each category as [_, action]}
|
||||
<TextActionButton {action} {editor} size="small" {actionCtx} blockMouseEvents={false} />
|
||||
{/each}
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
import { openImage, downloadImage, expandImage, moreImageActions } from './components/extension/imageExt'
|
||||
import { configureNote, isEditableNote } from './components/extension/note'
|
||||
import { createInlineComment, shouldShowCreateInlineCommentAction } from './components/extension/inlineComment'
|
||||
import { isTextStylingEnabled, openBackgroundColorOptions, openTextColorOptions } from './components/extension/colors'
|
||||
|
||||
export * from '@hcengineering/presentation/src/types'
|
||||
export type { EditorKitOptions } from './kits/editor-kit'
|
||||
@@ -97,8 +98,12 @@ export default async (): Promise<Resources> => ({
|
||||
IsEditableNote: isEditableNote,
|
||||
IsEditable: isEditable,
|
||||
IsHeadingVisible: isHeadingVisible,
|
||||
IsTextStylingEnabled: isTextStylingEnabled,
|
||||
|
||||
CreateInlineComment: createInlineComment,
|
||||
ShouldShowCreateInlineCommentAction: shouldShowCreateInlineCommentAction
|
||||
ShouldShowCreateInlineCommentAction: shouldShowCreateInlineCommentAction,
|
||||
|
||||
SetBackgroundColor: openBackgroundColorOptions,
|
||||
SetTextColor: openTextColorOptions
|
||||
}
|
||||
})
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import { type Class, type Doc, type Ref, type Space } from '@hcengineering/core'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import { getBlobRef, getClient } from '@hcengineering/presentation'
|
||||
import { CodeExtension, codeOptions } from '@hcengineering/text'
|
||||
import { BackgroundColor, CodeExtension, codeOptions, TextColor, TextStyle } from '@hcengineering/text'
|
||||
import textEditor, { type ActionContext, type ExtensionCreator, type TextEditorMode } from '@hcengineering/text-editor'
|
||||
import { type AnyExtension, type Editor, Extension } from '@tiptap/core'
|
||||
import { type Level } from '@tiptap/extension-heading'
|
||||
@@ -201,6 +201,12 @@ async function buildEditorKit (): Promise<Extension<EditorKitOptions, any>> {
|
||||
staticKitExtensions.push([400, ParagraphExtension.configure()])
|
||||
}
|
||||
|
||||
if (mode === 'full') {
|
||||
staticKitExtensions.push([410, TextStyle.configure({})])
|
||||
staticKitExtensions.push([420, TextColor.configure({})])
|
||||
staticKitExtensions.push([430, BackgroundColor.configure({ types: ['tableCell'] })])
|
||||
}
|
||||
|
||||
staticKitExtensions.push([
|
||||
500,
|
||||
ListKeymapExtension.configure({
|
||||
|
||||
@@ -93,8 +93,6 @@ export default plugin(textEditorId, {
|
||||
CategoryColumn: '' as IntlString,
|
||||
CategoryCell: '' as IntlString,
|
||||
Table: '' as IntlString,
|
||||
TableOptions: '' as IntlString,
|
||||
SelectTable: '' as IntlString,
|
||||
Width: '' as IntlString,
|
||||
Height: '' as IntlString,
|
||||
Unset: '' as IntlString,
|
||||
@@ -102,7 +100,12 @@ export default plugin(textEditorId, {
|
||||
SeparatorLine: '' as IntlString,
|
||||
TodoList: '' as IntlString,
|
||||
DrawingBoard: '' as IntlString,
|
||||
MermaidDiargram: '' as IntlString
|
||||
MermaidDiargram: '' as IntlString,
|
||||
|
||||
TableOptions: '' as IntlString,
|
||||
SelectTable: '' as IntlString,
|
||||
SetCellHighlightColor: '' as IntlString,
|
||||
SetTextColor: '' as IntlString
|
||||
},
|
||||
icon: {
|
||||
Header1: '' as Asset,
|
||||
@@ -130,6 +133,8 @@ export default plugin(textEditorId, {
|
||||
Comment: '' as Asset,
|
||||
SelectTable: '' as Asset,
|
||||
MergeCells: '' as Asset,
|
||||
SplitCells: '' as Asset
|
||||
SplitCells: '' as Asset,
|
||||
Brush: '' as Asset,
|
||||
TextStyle: '' as Asset
|
||||
}
|
||||
})
|
||||
|
||||
@@ -186,7 +186,7 @@ export interface ActiveDescriptor {
|
||||
params?: any
|
||||
}
|
||||
|
||||
export type TextEditorActionKind = 'text' | 'image'
|
||||
export type TextEditorActionKind = 'text' | 'image' | 'table'
|
||||
|
||||
/**
|
||||
* Defines a text action for text action editor
|
||||
|
||||
Reference in New Issue
Block a user