Skip to content

Commit

Permalink
Merge pull request #4587 from nextcloud/feat/slash-command
Browse files Browse the repository at this point in the history
  • Loading branch information
juliusknorr authored Aug 9, 2023
2 parents 67bc06e + e51ce5a commit fe0d548
Show file tree
Hide file tree
Showing 20 changed files with 181 additions and 40 deletions.
4 changes: 2 additions & 2 deletions js/editor.js

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions js/editor.js.LICENSE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,27 @@
*
*/

/*
* @copyright Copyright (c) 2022 Julius Härtl <[email protected]>
*
* @author Julius Härtl <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/*
* @copyright Copyright (c) 2022 Max <[email protected]>
*
Expand Down
2 changes: 1 addition & 1 deletion js/editor.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/text-editors.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/text-editors.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/text-files.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/text-files.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/text-public.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/text-public.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/text-text.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/text-text.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/text-viewer.js

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions js/text-viewer.js.LICENSE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,27 @@
*
*/

/*
* @copyright Copyright (c) 2022 Julius Härtl <[email protected]>
*
* @author Julius Härtl <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/*
* @copyright Copyright (c) 2022 Max <[email protected]>
*
Expand Down Expand Up @@ -242,6 +263,14 @@
* @license MIT
*/

/*!
* Toastify js 1.12.0
* https://github.com/apvarun/toastify-js
* @license MIT licensed
*
* Copyright (C) 2018 Varun A P
*/

/*!
* Vue.js v2.7.14
* (c) 2014-2022 Evan You
Expand Down
2 changes: 1 addition & 1 deletion js/text-viewer.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/vendors.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/vendors.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@
],
"moduleNameMapper": {
"^@/(.*)$": "<rootDir>/src/$1",
"\\.(css)$": "identity-obj-proxy"
"^.+\\.(css|less|scss)$": "identity-obj-proxy"
},
"testPathIgnorePatterns": [
"<rootDir>/src/tests/fixtures/",
Expand Down
5 changes: 3 additions & 2 deletions src/components/Suggestion/LinkPicker/LinkPickerList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@
:items="items"
@select="(item) => $emit('select', item)">
<template #default="{ item }">
<div class="link-picker__item">
<img :src="item.icon">
<div class="link-picker__item" :data-key="item.key">
<compoent :is="item.icon" v-if="typeof item.icon !== 'string'" />
<img v-else :src="item.icon">
<div>{{ item.label }}</div>
</div>
</template>
Expand Down
67 changes: 57 additions & 10 deletions src/components/Suggestion/LinkPicker/suggestions.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,50 @@

import createSuggestions from '../suggestions.js'
import LinkPickerList from './LinkPickerList.vue'

import { searchProvider, getLinkWithPicker } from '@nextcloud/vue/dist/Components/NcRichText.js'
import menuEntries from './../../Menu/entries.js'
import { getIsActive } from '../../Menu/utils.js'

const suggestGroupFormat = t('text', 'Formatting')
const suggestGroupPicker = t('text', 'Smart picker')

const filterOut = (e) => {
return ['undo', 'redo', 'outline', 'emoji-picker'].indexOf(e.key) > -1
}

const important = ['task-list', 'table']

const sortImportantFirst = (list) => {
return [
...list.filter(e => important.indexOf(e.key) > -1),
...list.filter(e => important.indexOf(e.key) === -1),
]
}

const formattingSuggestions = (query) => {
return sortImportantFirst(
[
...menuEntries.find(e => e.key === 'headings').children,
...menuEntries.filter(e => e.action && !filterOut(e)),
...menuEntries.find(e => e.key === 'callouts').children,
{
...menuEntries.find(e => e.key === 'emoji-picker'),
action: (command) => command.insertContent(':'),
},
].filter(e => e?.label?.toLowerCase?.()?.includes(query.toLowerCase()))
.map(e => ({ ...e, suggestGroup: suggestGroupFormat })),
)
}

export default () => createSuggestions({
listComponent: LinkPickerList,
command: ({ editor, range, props }) => {
if (props.action) {
const commandChain = editor.chain().deleteRange(range)
props.action(commandChain)
commandChain.run()
return
}
getLinkWithPicker(props.providerId, true)
.then(link => {
editor
Expand All @@ -39,14 +77,23 @@ export default () => createSuggestions({
console.error('Smart picker promise rejected', error)
})
},
items: ({ query }) => {
return searchProvider(query)
.map(p => {
return {
label: p.title,
icon: p.icon_url,
providerId: p.id,
}
})
items: ({ editor, query }) => {
return [
...formattingSuggestions(query)
.filter(({ action, isActive }) => {
const canRunState = action(editor?.can())
const isActiveState = isActive && getIsActive({ isActive }, editor)
return canRunState && !isActiveState
}),
...searchProvider(query)
.map(p => {
return {
suggestGroup: suggestGroupPicker,
label: p.title,
icon: p.icon_url,
providerId: p.id,
}
}),
]
},
})
55 changes: 49 additions & 6 deletions src/components/Suggestion/SuggestionListWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,17 @@
<template>
<div class="suggestion-list">
<template v-if="hasResults">
<div v-for="(item, index) in items"
:key="index"
class="suggestion-list__item"
:class="{ 'is-selected': index === selectedIndex }"
@click="selectItem(index)">
<slot :item="item" :active="index === selectedIndex" />
<div v-for="(groupItems, key, groupIndex) in itemGroups" :key="key">
<div v-if="hasGroups" class="suggestion-list__group">
{{ key }}
</div>
<div v-for="(item, index) in groupItems"
:key="combineIndex(groupIndex, index)"
class="suggestion-list__item"
:class="{ 'is-selected': combineIndex(groupIndex, index) === selectedIndex }"
@click="selectItem(combineIndex(groupIndex, index))">
<slot :item="item" :active="combineIndex(groupIndex, index) === selectedIndex" />
</div>
</div>
</template>
<div v-else class="suggestion-list__item is-empty">
Expand Down Expand Up @@ -56,6 +61,9 @@ export default {
}
},
computed: {
hasGroups() {
return Object.keys(this.itemGroups).includes(undefined)
},
hasResults() {
return this.items.length > 0
},
Expand All @@ -68,6 +76,26 @@ export default {
return this.selectedIndex * this.itemHeight >= this.$el.scrollTop
&& (this.selectedIndex + 1) * this.itemHeight <= this.$el.scrollTop + this.$el.clientHeight
},
itemGroups() {
const groups = {}
this.items.forEach((item) => {
if (!groups[item.suggestGroup]) {
groups[item.suggestGroup] = []
}
groups[item.suggestGroup].push(item)
})
return groups
},
combineIndex() {
return (groupIndex, index) => {
const previousItemCount = Object.values(this.itemGroups)
.slice(0, groupIndex)
.reduce((sum, items) => {
return sum + items.length
}, 0)
return previousItemCount + index
}
},
},
watch: {
items() {
Expand Down Expand Up @@ -128,11 +156,26 @@ export default {
min-width: 200px;
max-width: 400px;
width: 80vw;
padding: 4px;
// Show maximum 5 entries and a half to show scroll
max-height: 35.5px * 5 + 18px;
margin: 5px 0;
&__group {
font-weight: bold;
color: var(--color-primary-element);
font-size: var(--default-font-size);
line-height: 44px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
opacity: .7;
box-shadow: none !important;
flex-shrink: 0;
padding-left: 8px;
}
&__item {
border-radius: 8px;
padding: 4px 8px;
Expand Down

0 comments on commit fe0d548

Please sign in to comment.