Use svg icons

Signed-off-by: Louis Chemineau <louis@chmn.me>
pull/34769/head
Louis Chemineau 2 years ago
parent 8829019101
commit a28838b866

@ -20,14 +20,14 @@
*
*/
import MessageReplyText from 'vue-material-design-icons/MessageReplyText.vue'
import MessageReplyText from '@mdi/svg/svg/message-reply-text.svg?raw'
// Init Comments tab component
let TabInstance = null
const commentTab = new OCA.Files.Sidebar.Tab({
id: 'comments',
name: t('comments', 'Comments'),
icon: 'icon-comment',
iconSvg: MessageReplyText,
async mount(el, fileInfo, context) {
if (TabInstance) {
@ -53,7 +53,7 @@ const commentTab = new OCA.Files.Sidebar.Tab({
},
})
window.addEventListener('DOMContentLoaded', function() {
window.addEventListener('DOMContentLoaded', function () {
if (OCA.Files && OCA.Files.Sidebar) {
OCA.Files.Sidebar.registerTab(commentTab)
}

@ -19,12 +19,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import { sanitizeSVG } from '@skjnldsv/sanitize-svg'
export default class Tab {
_id
_name
_icon
_iconSvgSanitized
_mount
_update
_destroy
@ -37,19 +39,20 @@ export default class Tab {
* @param {object} options destructuring object
* @param {string} options.id the unique id of this tab
* @param {string} options.name the translated tab name
* @param {string} options.icon the vue component
* @param {?string} options.icon the icon css class
* @param {?string} options.iconSvg the icon in svg format
* @param {Function} options.mount function to mount the tab
* @param {Function} options.update function to update the tab
* @param {Function} options.destroy function to destroy the tab
* @param {Function} [options.enabled] define conditions whether this tab is active. Must returns a boolean
* @param {Function} [options.scrollBottomReached] executed when the tab is scrolled to the bottom
*/
constructor({ id, name, icon, mount, update, destroy, enabled, scrollBottomReached } = {}) {
constructor({ id, name, icon, iconSvg, mount, update, destroy, enabled, scrollBottomReached } = {}) {
if (enabled === undefined) {
enabled = () => true
}
if (scrollBottomReached === undefined) {
scrollBottomReached = () => {}
scrollBottomReached = () => { }
}
// Sanity checks
@ -59,8 +62,8 @@ export default class Tab {
if (typeof name !== 'string' || name.trim() === '') {
throw new Error('The name argument is not a valid string')
}
if ((typeof icon !== 'string' || icon.trim() === '') && typeof icon !== 'object') {
throw new Error('The icon argument is not a valid string or vuejs component')
if ((typeof icon !== 'string' || icon.trim() === '') && typeof iconSvg !== 'string') {
throw new Error('Missing valid string for icon or iconSvg argument')
}
if (typeof mount !== 'function') {
throw new Error('The mount argument should be a function')
@ -81,12 +84,20 @@ export default class Tab {
this._id = id
this._name = name
this._icon = icon
this._iconSvg = iconSvg
this._mount = mount
this._update = update
this._destroy = destroy
this._enabled = enabled
this._scrollBottomReached = scrollBottomReached
if (typeof iconSvg === 'string') {
sanitizeSVG(iconSvg)
.then(sanitizedSvg => {
this._iconSvgSanitized = sanitizedSvg
})
}
}
get id() {
@ -97,14 +108,14 @@ export default class Tab {
return this._name
}
get isIconClass() {
return typeof this._icon === 'string'
}
get icon() {
return this._icon
}
get iconSvg() {
return this._iconSvgSanitized
}
get mount() {
return this._mount
}

@ -67,14 +67,15 @@
:id="tab.id"
:key="tab.id"
:name="tab.name"
:icon="tab.isIconClass ? tab.icon : undefined"
:icon="tab.icon"
:on-mount="tab.mount"
:on-update="tab.update"
:on-destroy="tab.destroy"
:on-scroll-bottom-reached="tab.scrollBottomReached"
:file-info="fileInfo">
<template #icon v-if="!tab.isIconClass">
<component :is="tab.icon" />
<template v-if="tab.iconSvg !== undefined" #icon>
<!-- eslint-disable-next-line vue/no-v-html -->
<span class="svg-icon" v-html="tab.iconSvg" />
</template>
</SidebarTab>
</template>
@ -512,5 +513,13 @@ export default {
top: 0 !important;
height: 100% !important;
}
.svg-icon {
::v-deep svg {
width: 20px;
height: 20px;
fill: var(--color-main-text);
}
}
}
</style>

@ -31,7 +31,7 @@ import ExternalLinkActions from './services/ExternalLinkActions.js'
import ExternalShareActions from './services/ExternalShareActions.js'
import TabSections from './services/TabSections.js'
import ShareVariant from 'vue-material-design-icons/ShareVariant.vue'
import ShareVariant from '@mdi/svg/svg/share-variant.svg?raw'
// Init Sharing Tab Service
if (!window.OCA.Sharing) {
@ -50,12 +50,12 @@ Vue.use(VueClipboard)
const View = Vue.extend(SharingTab)
let TabInstance = null
window.addEventListener('DOMContentLoaded', function() {
window.addEventListener('DOMContentLoaded', function () {
if (OCA.Files && OCA.Files.Sidebar) {
OCA.Files.Sidebar.registerTab(new OCA.Files.Sidebar.Tab({
id: 'sharing',
name: t('files_sharing', 'Sharing'),
icon: ShareVariant,
iconSvg: ShareVariant,
async mount(el, fileInfo, context) {
if (TabInstance) {

@ -22,7 +22,7 @@ import { translate as t, translatePlural as n } from '@nextcloud/l10n'
import VersionTab from './views/VersionTab.vue'
import VTooltip from 'v-tooltip'
import BackupRestore from 'vue-material-design-icons/BackupRestore.vue'
import BackupRestore from '@mdi/svg/svg/backup-restore.svg?raw'
Vue.prototype.t = t
Vue.prototype.n = n
@ -33,12 +33,12 @@ Vue.use(VTooltip)
const View = Vue.extend(VersionTab)
let TabInstance = null
window.addEventListener('DOMContentLoaded', function() {
window.addEventListener('DOMContentLoaded', function () {
if (OCA.Files && OCA.Files.Sidebar) {
OCA.Files.Sidebar.registerTab(new OCA.Files.Sidebar.Tab({
id: 'version_vue',
name: t('files_versions', 'Version'),
icon: BackupRestore,
iconSvg: BackupRestore,
async mount(el, fileInfo, context) {
if (TabInstance) {

@ -19,8 +19,8 @@
<div>
<ul>
<NcListItem v-for="version in versions"
:key="version.dateTime.unix()"
class="version"
key="version.url"
:title="version.title"
:href="version.url">
<template #icon>
@ -47,7 +47,7 @@
</template>
{{ t('files_versions', 'Download version') }}
</NcActionLink>
<NcActionButton @click="restoreVersion(version)" v-if="!version.isCurrent">
<NcActionButton v-if="!version.isCurrent" @click="restoreVersion(version)">
<template #icon>
<BackupRestore :size="22" />
</template>
@ -73,7 +73,6 @@ import { generateRemoteUrl, generateUrl } from '@nextcloud/router'
import { getCurrentUser } from '@nextcloud/auth'
import BackupRestore from 'vue-material-design-icons/BackupRestore.vue'
import Download from 'vue-material-design-icons/Download.vue'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
import NcActionLink from '@nextcloud/vue/dist/Components/NcActionLink.js'
import NcListItem from '@nextcloud/vue/dist/Components/NcListItem.js'
@ -108,6 +107,9 @@ function getDavRequest() {
/**
* Format version
*
* @param version
* @param fileInfo
*/
function formatVersion(version, fileInfo) {
const fileVersion = basename(version.filename)
@ -117,7 +119,8 @@ function formatVersion(version, fileInfo) {
? generateUrl('/core/preview?fileId={fileId}&c={fileEtag}&x=250&y=250&forceIcon=0&a=0', {
fileId: fileInfo.id,
fileEtag: fileInfo.etag,
}) : generateUrl('/apps/files_versions/preview?file={file}&version={fileVersion}', {
})
: generateUrl('/apps/files_versions/preview?file={file}&version={fileVersion}', {
file: joinPaths(fileInfo.path, fileInfo.name),
fileVersion,
})
@ -151,7 +154,6 @@ const client = createClient(remote)
export default {
name: 'VersionTab',
components: {
NcButton,
NcEmptyContent,
NcActionLink,
NcActionButton,
@ -192,7 +194,7 @@ export default {
this.versions = response.map(version => formatVersion(version, this.fileInfo))
this.loading = false
} catch (exception) {
logger.error('Could not fetch version', {exception})
logger.error('Could not fetch version', { exception })
this.loading = false
}
},
@ -205,14 +207,14 @@ export default {
async restoreVersion(version) {
try {
logger.debug('restoring version', version.url)
const response = await client.moveFile(
await client.moveFile(
`/versions/${getCurrentUser().uid}/versions/${this.fileInfo.id}/${version.fileVersion}`,
`/versions/${getCurrentUser().uid}/restore/target`
)
showSuccess(t('files_versions', 'Version restored'))
await this.fetchVersions()
} catch (exception) {
logger.error('Could not restore version', {exception})
logger.error('Could not restore version', { exception })
showError(t('files_versions', 'Could not restore version'))
}
},

54
package-lock.json generated

@ -10,6 +10,7 @@
"license": "AGPL-3.0-or-later",
"dependencies": {
"@chenfengyuan/vue-qrcode": "^1.0.2",
"@mdi/svg": "^7.0.96",
"@nextcloud/auth": "^1.3.0",
"@nextcloud/axios": "^1.10.0",
"@nextcloud/browser-storage": "^0.1.1",
@ -29,6 +30,7 @@
"@nextcloud/sharing": "^0.1.0",
"@nextcloud/vue": "^7.1.0-beta.2",
"@nextcloud/vue-dashboard": "^2.0.1",
"@skjnldsv/sanitize-svg": "^1.0.2",
"autosize": "^5.0.1",
"backbone": "^1.4.1",
"blueimp-md5": "^2.19.0",
@ -3469,6 +3471,11 @@
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@mdi/svg": {
"version": "7.0.96",
"resolved": "https://registry.npmjs.org/@mdi/svg/-/svg-7.0.96.tgz",
"integrity": "sha512-5DC+w7Kl2C82j4aTWCUf6wtHzgY60WBf1gT1qrpkLaMNcH6Vj9FpYPAXdSmtdkmSMvVMs8i1Rtv9cXWcHFQYpw=="
},
"node_modules/@nextcloud/auth": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@nextcloud/auth/-/auth-1.3.0.tgz",
@ -4433,6 +4440,18 @@
"integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==",
"dev": true
},
"node_modules/@skjnldsv/sanitize-svg": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@skjnldsv/sanitize-svg/-/sanitize-svg-1.0.2.tgz",
"integrity": "sha512-blfdQZ9jr4K9IOhifF0FVhKf9LCFH0L8wWR/vEgdA53q8DGNEbjUGMNo4VU1QugglaoQdFy65O2abODRFflsSg==",
"dependencies": {
"is-svg": "^4.3.2"
},
"engines": {
"node": "^14.0.0",
"npm": "^7.0.0"
}
},
"node_modules/@socket.io/component-emitter": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
@ -10711,6 +10730,20 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-svg": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/is-svg/-/is-svg-4.3.2.tgz",
"integrity": "sha512-mM90duy00JGMyjqIVHu9gNTjywdZV+8qNasX8cm/EEYZ53PHDgajvbBwNVvty5dwSAxLUD3p3bdo+7sR/UMrpw==",
"dependencies": {
"fast-xml-parser": "^3.19.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-symbol": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
@ -22697,6 +22730,11 @@
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"@mdi/svg": {
"version": "7.0.96",
"resolved": "https://registry.npmjs.org/@mdi/svg/-/svg-7.0.96.tgz",
"integrity": "sha512-5DC+w7Kl2C82j4aTWCUf6wtHzgY60WBf1gT1qrpkLaMNcH6Vj9FpYPAXdSmtdkmSMvVMs8i1Rtv9cXWcHFQYpw=="
},
"@nextcloud/auth": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@nextcloud/auth/-/auth-1.3.0.tgz",
@ -23453,6 +23491,14 @@
"integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==",
"dev": true
},
"@skjnldsv/sanitize-svg": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@skjnldsv/sanitize-svg/-/sanitize-svg-1.0.2.tgz",
"integrity": "sha512-blfdQZ9jr4K9IOhifF0FVhKf9LCFH0L8wWR/vEgdA53q8DGNEbjUGMNo4VU1QugglaoQdFy65O2abODRFflsSg==",
"requires": {
"is-svg": "^4.3.2"
}
},
"@socket.io/component-emitter": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
@ -28314,6 +28360,14 @@
"has-tostringtag": "^1.0.0"
}
},
"is-svg": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/is-svg/-/is-svg-4.3.2.tgz",
"integrity": "sha512-mM90duy00JGMyjqIVHu9gNTjywdZV+8qNasX8cm/EEYZ53PHDgajvbBwNVvty5dwSAxLUD3p3bdo+7sR/UMrpw==",
"requires": {
"fast-xml-parser": "^3.19.0"
}
},
"is-symbol": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",

@ -30,6 +30,7 @@
"license": "AGPL-3.0-or-later",
"dependencies": {
"@chenfengyuan/vue-qrcode": "^1.0.2",
"@mdi/svg": "^7.0.96",
"@nextcloud/auth": "^1.3.0",
"@nextcloud/axios": "^1.10.0",
"@nextcloud/browser-storage": "^0.1.1",
@ -49,6 +50,7 @@
"@nextcloud/sharing": "^0.1.0",
"@nextcloud/vue": "^7.1.0-beta.2",
"@nextcloud/vue-dashboard": "^2.0.1",
"@skjnldsv/sanitize-svg": "^1.0.2",
"autosize": "^5.0.1",
"backbone": "^1.4.1",
"blueimp-md5": "^2.19.0",

@ -116,7 +116,10 @@ module.exports = {
test: /\.handlebars/,
loader: 'handlebars-loader',
},
{
resourceQuery: /raw/,
type: 'asset/source',
},
],
},

Loading…
Cancel
Save