Skip to content

Commit 26465e9

Browse files
committed
feat(editor): insert shortcuts
1 parent 577146c commit 26465e9

File tree

16 files changed

+229
-127
lines changed

16 files changed

+229
-127
lines changed

packages/better-write-app/src/components/page/editor/project/preferences/EditorProjectPreferencesAside.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<template>
22
<aside
3-
class="flex wb-text items-center justify-between flex-col w-full sm:w-40 shadow h-full"
3+
class="flex wb-text items-center justify-between flex-col w-full sm:w-40 shadow-xl h-full"
44
>
55
<div
6-
class="flex transition-colors flex-1 gap-2 justify-between px-3 items-center w-full cursor-pointer hover:bg-theme-background-opacity-1"
6+
class="flex shadow transition-colors flex-1 gap-2 justify-between px-3 items-center w-full cursor-pointer hover:bg-theme-background-opacity-1"
77
@click="emit('section', 0)"
88
>
99
<div>
@@ -12,7 +12,7 @@
1212
<p>{{ t('editor.preferences.project.title') }}</p>
1313
</div>
1414
<div
15-
class="flex transition-colors flex-1 gap-2 justify-between px-3 items-center w-full cursor-pointer hover:bg-theme-background-opacity-1"
15+
class="flex shadow transition-colors flex-1 gap-2 justify-between px-3 items-center w-full cursor-pointer hover:bg-theme-background-opacity-1"
1616
@click="emit('section', 1)"
1717
>
1818
<div>
@@ -21,7 +21,7 @@
2121
<p>{{ t('editor.preferences.configuration.title') }}</p>
2222
</div>
2323
<div
24-
class="flex transition-colors flex-1 gap-2 justify-between px-3 items-center w-full cursor-pointer hover:bg-theme-background-opacity-1"
24+
class="flex shadow transition-colors flex-1 gap-2 justify-between px-3 items-center w-full cursor-pointer hover:bg-theme-background-opacity-1"
2525
@click="emit('section', 2)"
2626
>
2727
<div>
@@ -30,7 +30,7 @@
3030
<p>{{ t('editor.preferences.styles.title') }}</p>
3131
</div>
3232
<div
33-
class="flex transition-colors flex-1 gap-2 justify-between px-3 items-center w-full cursor-pointer hover:bg-theme-background-opacity-1"
33+
class="flex shadow transition-colors flex-1 gap-2 justify-between px-3 items-center w-full cursor-pointer hover:bg-theme-background-opacity-1"
3434
@click="emit('section', 3)"
3535
>
3636
<div>

packages/better-write-app/src/components/page/editor/project/preferences/container/EditorProjectPreferencesContainerKeyboard.vue

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,30 @@
6161
shortcut="CTRL + 9"
6262
/>
6363
</div>
64+
<PreferencesContainerTitle>
65+
{{ t('editor.preferences.shortcuts.inserts.title') }}
66+
</PreferencesContainerTitle>
67+
<p>{{ t('editor.preferences.shortcuts.inserts.description') }}</p>
68+
<div class="flex flex-col gap-2 w-full px-2">
69+
<EditorProjectPreferencesKeyboardInsertAdd />
70+
<draggable :list="PROJECT.shortcuts.inserts" item-key="id">
71+
<template #item="{ element, index }">
72+
<EditorProjectPreferencesKeyboardInsertItem
73+
:key="index"
74+
:insert="element"
75+
/>
76+
</template>
77+
</draggable>
78+
</div>
6479
</EditorProjectPreferencesContainerSlot>
6580
</template>
6681

6782
<script setup lang="ts">
83+
import { useProjectStore } from '@/store/project'
6884
import { useI18n } from 'vue-i18n'
85+
import draggable from 'vuedraggable'
86+
87+
const PROJECT = useProjectStore()
6988
7089
const { t } = useI18n()
7190
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<template>
2+
<div class="flex items-center w-full gap-5 wb-text my-6 wb-text">
3+
<InputText
4+
v-model="state.key"
5+
class="p-2 shadow-lg bg-theme-background-2 rounded-xl tracking-wider placeholder-theme-text-1 w-full"
6+
:placeholder="t('editor.preferences.shortcuts.inserts.key')"
7+
@keydown="onInputKey"
8+
/>
9+
<InputText
10+
v-model="state.value"
11+
class="p-2 shadow-lg bg-theme-background-2 rounded-xl tracking-wider placeholder-theme-text-1 w-full"
12+
:placeholder="t('editor.preferences.shortcuts.inserts.value')"
13+
@keyup.enter="add"
14+
/>
15+
<IconAdd class="w-18 h-18 wb-icon" @click.prevent.stop="add" />
16+
</div>
17+
</template>
18+
19+
<script setup lang="ts">
20+
import { reactive } from 'vue'
21+
import { useProjectStore } from '@/store/project'
22+
import { useI18n } from 'vue-i18n'
23+
24+
const PROJECT = useProjectStore()
25+
26+
const { t } = useI18n()
27+
28+
const state = reactive({
29+
key: '',
30+
value: '',
31+
})
32+
33+
const add = () => {
34+
if (!state.key || !state.value) return
35+
36+
PROJECT.shortcuts.inserts.unshift({
37+
key: state.key,
38+
value: state.value,
39+
})
40+
41+
state.key = ''
42+
state.value = ''
43+
}
44+
45+
const onInputKey = (e: KeyboardEvent) => {
46+
e.preventDefault()
47+
e.stopPropagation()
48+
49+
if (e.key) state.key = e.key
50+
}
51+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<template>
2+
<div class="flex items-center w-full gap-5 wb-text wb-text my-2">
3+
<p
4+
class="px-3 py-1 rounded-full font-bold bg-theme-background-2 text-theme-text-2 shadow-lg w-24"
5+
>
6+
Alt
7+
</p>
8+
<p class="text-2xl">+</p>
9+
<InputText
10+
v-model="props.insert.key"
11+
class="p-2 shadow-lg bg-theme-background-2 rounded-xl tracking-wider placeholder-theme-text-1 w-full"
12+
:placeholder="t('editor.preferences.shortcuts.inserts.key')"
13+
@keydown="onInputKey"
14+
/>
15+
<p class="text-2xl">=</p>
16+
<InputText
17+
v-model="props.insert.value"
18+
class="p-2 shadow-lg bg-theme-background-2 rounded-xl tracking-wider placeholder-theme-text-1 w-full"
19+
:placeholder="t('editor.preferences.shortcuts.inserts.value')"
20+
/>
21+
<div class="flex items-center gap-0 md:gap-2">
22+
<IconDelete
23+
v-motion
24+
:initial="{ opacity: 0, y: 30 }"
25+
:enter="{ opacity: 1, y: 0 }"
26+
:delay="50"
27+
class="w-7 h-7 wb-icon"
28+
@click.prevent.stop="remove"
29+
/>
30+
</div>
31+
</div>
32+
</template>
33+
34+
<script setup lang="ts">
35+
import { useProjectStore } from '@/store/project'
36+
import { ProjectStateShortcutsInserts } from 'better-write-types'
37+
import { useI18n } from 'vue-i18n'
38+
39+
const props = defineProps<{
40+
insert: ProjectStateShortcutsInserts
41+
}>()
42+
43+
const PROJECT = useProjectStore()
44+
45+
const { t } = useI18n()
46+
47+
const remove = () => {
48+
PROJECT.shortcuts.inserts = PROJECT.shortcuts.inserts.filter(
49+
(t) => t !== props.insert
50+
)
51+
}
52+
53+
const onInputKey = (e: KeyboardEvent) => {
54+
e.preventDefault()
55+
e.stopPropagation()
56+
57+
if (e.key) props.insert.key = e.key
58+
}
59+
</script>

packages/better-write-app/src/store/project.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ export const useProjectStore = defineStore('project', {
5454
bold: [],
5555
},
5656
},
57+
shortcuts: {
58+
inserts: [
59+
{
60+
key: 'D',
61+
value: '— ',
62+
},
63+
],
64+
},
5765
}
5866
},
5967
actions: {
@@ -77,6 +85,7 @@ export const useProjectStore = defineStore('project', {
7785
this.templates = payload.templates
7886
this.bw.platform = payload.bw.platform
7987
this.bw.version = payload.bw.version
88+
this.shortcuts = payload.shortcuts
8089
},
8190
create(payload: ProjectState, title: string) {
8291
const global = useGlobalStore()

packages/better-write-app/src/use/block/text.ts

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { useRaw } from '../raw'
1212
import { useStorage } from '../storage/storage'
1313
import { useUtils } from '../utils'
1414
import { html } from '../raw'
15+
import { useProjectStore } from '@/store/project'
1516

1617
export const useBlockText = ({
1718
props,
@@ -29,6 +30,7 @@ export const useBlockText = ({
2930
const CONTEXT = useContextStore()
3031
const EDITOR = useEditorStore()
3132
const ABSOLUTE = useAbsoluteStore()
33+
const PROJECT = useProjectStore()
3234

3335
const emitter = useEmitter()
3436
const entity = useEntity()
@@ -112,25 +114,26 @@ export const useBlockText = ({
112114
}
113115

114116
const onDynamicInserts = (e: KeyboardEvent, offset: number) => {
115-
const value = input.value.innerHTML
117+
const value = utils.text().defaultWhitespace(input.value.innerHTML)
116118

117-
if (e.altKey && e.key.toLowerCase() === 'd') {
118-
e.preventDefault()
119-
e.stopPropagation()
119+
PROJECT.shortcuts.inserts.forEach(({ key, value: insert }) => {
120+
if (e.altKey && e.key.toLowerCase() === key.toLowerCase()) {
121+
e.preventDefault()
122+
e.stopPropagation()
120123

121-
const insert = '— '
122-
const sub = html().insert(value, offset, insert)
124+
const sub = html().insert(value, offset, insert)
123125

124-
setData(sub)
126+
setData(sub)
125127

126-
const _offset = insert.length + offset
128+
const _offset = insert.length + offset
127129

128-
emitter.emit('entity-text-focus', {
129-
target: index.value,
130-
position: 'offset',
131-
positionOffset: _offset,
132-
})
133-
}
130+
emitter.emit('entity-text-focus', {
131+
target: index.value,
132+
position: 'offset',
133+
positionOffset: _offset,
134+
})
135+
}
136+
})
134137
}
135138

136139
const onKeyboard = async (e: KeyboardEvent) => {

packages/better-write-app/src/use/populate.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ export const usePopulate = () => {
6767
bold: useDefines().generator().substitutions().bold(),
6868
},
6969
},
70+
shortcuts: {
71+
inserts: [
72+
{
73+
key: 'D',
74+
value: '— ',
75+
},
76+
],
77+
},
7078
},
7179
blank: {
7280
name: useUtils().text().kebab(project.name),
@@ -122,6 +130,14 @@ export const usePopulate = () => {
122130
bold: useDefines().generator().substitutions().bold(),
123131
},
124132
},
133+
shortcuts: {
134+
inserts: [
135+
{
136+
key: 'D',
137+
value: '— ',
138+
},
139+
],
140+
},
125141
},
126142
}[project.type] as ProjectState
127143
}

0 commit comments

Comments
 (0)