mirror of
https://github.com/go-vikunja/vikunja.git
synced 2026-04-24 22:25:15 +00:00
chore: fix indentation
This commit is contained in:
committed by
kolaente
parent
6d53adb37c
commit
454418ee63
@@ -5,13 +5,13 @@ import {createRouter, createMemoryHistory} from 'vue-router'
|
||||
import BaseButton from './BaseButton.vue'
|
||||
|
||||
function setupApp({ app }) {
|
||||
// Router mock
|
||||
app.use(createRouter({
|
||||
history: createMemoryHistory(),
|
||||
routes: [
|
||||
{ path: '/', name: 'home', component: { render: () => null } },
|
||||
],
|
||||
}))
|
||||
// Router mock
|
||||
app.use(createRouter({
|
||||
history: createMemoryHistory(),
|
||||
routes: [
|
||||
{ path: '/', name: 'home', component: { render: () => null } },
|
||||
],
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -43,29 +43,29 @@ const props = withDefaults(defineProps<{
|
||||
* Makes only sense if `initialHeight` is set. */
|
||||
backgroundColor?: string
|
||||
}>(), {
|
||||
open: false,
|
||||
initialHeight: undefined,
|
||||
open: false,
|
||||
initialHeight: undefined,
|
||||
backgroundColor: undefined,
|
||||
})
|
||||
|
||||
const wrapper = ref<HTMLElement | null>(null)
|
||||
|
||||
const computedBackgroundColor = computed(() => {
|
||||
if (wrapper.value === null) {
|
||||
return props.backgroundColor || '#fff'
|
||||
}
|
||||
return props.backgroundColor || getInheritedBackgroundColor(wrapper.value)
|
||||
if (wrapper.value === null) {
|
||||
return props.backgroundColor || '#fff'
|
||||
}
|
||||
return props.backgroundColor || getInheritedBackgroundColor(wrapper.value)
|
||||
})
|
||||
|
||||
/**
|
||||
* Get the natural height of the element
|
||||
*/
|
||||
function getHeight(el: HTMLElement) {
|
||||
const { display } = el.style // save display property
|
||||
el.style.display = 'block' // Make it visible
|
||||
const height = `${el.scrollHeight}px` // Get its height
|
||||
el.style.display = display // revert to original display property
|
||||
return height
|
||||
const { display } = el.style // save display property
|
||||
el.style.display = 'block' // Make it visible
|
||||
const height = `${el.scrollHeight}px` // Get its height
|
||||
el.style.display = display // revert to original display property
|
||||
return height
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,8 +73,8 @@ function getHeight(el: HTMLElement) {
|
||||
* https://gist.github.com/paulirish/5d52fb081b3570c81e3a
|
||||
*/
|
||||
function forceLayout(el: HTMLElement) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
el.offsetTop
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
el.offsetTop
|
||||
}
|
||||
|
||||
/* ######################################################################
|
||||
@@ -84,50 +84,50 @@ function forceLayout(el: HTMLElement) {
|
||||
###################################################################### */
|
||||
|
||||
function beforeEnter(el: HTMLElement) {
|
||||
el.style.height = '0'
|
||||
el.style.willChange = 'height'
|
||||
el.style.backfaceVisibility = 'hidden'
|
||||
forceLayout(el)
|
||||
el.style.height = '0'
|
||||
el.style.willChange = 'height'
|
||||
el.style.backfaceVisibility = 'hidden'
|
||||
forceLayout(el)
|
||||
}
|
||||
|
||||
// the done callback is optional when
|
||||
// used in combination with CSS
|
||||
function enter(el: HTMLElement) {
|
||||
const height = getHeight(el) // Get the natural height
|
||||
el.style.height = height // Update the height
|
||||
const height = getHeight(el) // Get the natural height
|
||||
el.style.height = height // Update the height
|
||||
}
|
||||
|
||||
function afterEnter(el: HTMLElement) {
|
||||
removeHeight(el)
|
||||
removeHeight(el)
|
||||
}
|
||||
|
||||
function enterCancelled(el: HTMLElement) {
|
||||
removeHeight(el)
|
||||
removeHeight(el)
|
||||
}
|
||||
|
||||
function beforeLeave(el: HTMLElement) {
|
||||
// Give the element a height to change from
|
||||
el.style.height = `${el.scrollHeight}px`
|
||||
forceLayout(el)
|
||||
// Give the element a height to change from
|
||||
el.style.height = `${el.scrollHeight}px`
|
||||
forceLayout(el)
|
||||
}
|
||||
|
||||
function leave(el: HTMLElement) {
|
||||
// Set the height back to 0
|
||||
el.style.height = '0'
|
||||
el.style.willChange = ''
|
||||
el.style.backfaceVisibility = ''
|
||||
// Set the height back to 0
|
||||
el.style.height = '0'
|
||||
el.style.willChange = ''
|
||||
el.style.backfaceVisibility = ''
|
||||
}
|
||||
|
||||
function afterLeave(el: HTMLElement) {
|
||||
removeHeight(el)
|
||||
removeHeight(el)
|
||||
}
|
||||
|
||||
function leaveCancelled(el: HTMLElement) {
|
||||
removeHeight(el)
|
||||
removeHeight(el)
|
||||
}
|
||||
|
||||
function removeHeight(el: HTMLElement) {
|
||||
el.style.height = ''
|
||||
el.style.height = ''
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -468,12 +468,12 @@ const extensions : Extensions = [
|
||||
},
|
||||
}),
|
||||
|
||||
Commands.configure({
|
||||
suggestion: suggestionSetup(t),
|
||||
}),
|
||||
Commands.configure({
|
||||
suggestion: suggestionSetup(t),
|
||||
}),
|
||||
|
||||
PasteHandler,
|
||||
StopLinkOnSpace,
|
||||
PasteHandler,
|
||||
StopLinkOnSpace,
|
||||
]
|
||||
|
||||
// Add a custom extension for the Escape key
|
||||
|
||||
@@ -4,25 +4,25 @@ import Suggestion from '@tiptap/suggestion'
|
||||
// Copied and adjusted from https://github.com/ueberdosis/tiptap/tree/252acb32d27a0f9af14813eeed83d8a50059a43a/demos/src/Experiments/Commands/Vue
|
||||
|
||||
export default Extension.create({
|
||||
name: 'slash-menu-commands',
|
||||
name: 'slash-menu-commands',
|
||||
|
||||
addOptions() {
|
||||
return {
|
||||
suggestion: {
|
||||
char: '/',
|
||||
command: ({editor, range, props}) => {
|
||||
props.command({editor, range})
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
addOptions() {
|
||||
return {
|
||||
suggestion: {
|
||||
char: '/',
|
||||
command: ({editor, range, props}) => {
|
||||
props.command({editor, range})
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
addProseMirrorPlugins() {
|
||||
return [
|
||||
Suggestion({
|
||||
editor: this.editor,
|
||||
...this.options.suggestion,
|
||||
}),
|
||||
]
|
||||
},
|
||||
addProseMirrorPlugins() {
|
||||
return [
|
||||
Suggestion({
|
||||
editor: this.editor,
|
||||
...this.options.suggestion,
|
||||
}),
|
||||
]
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import {Extension} from '@tiptap/core'
|
||||
|
||||
export default Extension.create({
|
||||
name: 'stopLinkOnSpace',
|
||||
name: 'stopLinkOnSpace',
|
||||
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
Space: ({editor}) => {
|
||||
if (editor.isActive('link')) {
|
||||
editor.commands.unsetLink()
|
||||
}
|
||||
return false
|
||||
},
|
||||
}
|
||||
},
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
Space: ({editor}) => {
|
||||
if (editor.isActive('link')) {
|
||||
editor.commands.unsetLink()
|
||||
}
|
||||
return false
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@@ -4,211 +4,211 @@ import tippy from 'tippy.js'
|
||||
import CommandsList from './CommandsList.vue'
|
||||
|
||||
export default function suggestionSetup(t) {
|
||||
return {
|
||||
items: ({query}: { query: string }) => {
|
||||
return [
|
||||
{
|
||||
title: t('input.editor.text'),
|
||||
description: t('input.editor.textTooltip'),
|
||||
icon: 'fa-font',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setNode('paragraph', {level: 1})
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.heading1'),
|
||||
description: t('input.editor.heading1Tooltip'),
|
||||
icon: 'fa-header',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setNode('heading', {level: 1})
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.heading2'),
|
||||
description: t('input.editor.heading2Tooltip'),
|
||||
icon: 'fa-header',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setNode('heading', {level: 2})
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.heading3'),
|
||||
description: t('input.editor.heading3Tooltip'),
|
||||
icon: 'fa-header',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setNode('heading', {level: 2})
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.bulletList'),
|
||||
description: t('input.editor.bulletListTooltip'),
|
||||
icon: 'fa-list-ul',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.toggleBulletList()
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.orderedList'),
|
||||
description: t('input.editor.orderedListTooltip'),
|
||||
icon: 'fa-list-ol',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.toggleOrderedList()
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.taskList'),
|
||||
description: t('input.editor.taskListTooltip'),
|
||||
icon: 'fa-list-check',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.toggleTaskList()
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.quote'),
|
||||
description: t('input.editor.quoteTooltip'),
|
||||
icon: 'fa-quote-right',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.toggleBlockquote()
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.code'),
|
||||
description: t('input.editor.codeTooltip'),
|
||||
icon: 'fa-code',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.toggleCodeBlock()
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.image'),
|
||||
description: t('input.editor.imageTooltip'),
|
||||
icon: 'fa-image',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.run()
|
||||
document.getElementById('tiptap__image-upload').click()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.horizontalRule'),
|
||||
description: t('input.editor.horizontalRuleTooltip'),
|
||||
icon: 'fa-ruler-horizontal',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setHorizontalRule()
|
||||
.run()
|
||||
},
|
||||
},
|
||||
].filter(item => item.title.toLowerCase().startsWith(query.toLowerCase()))
|
||||
},
|
||||
return {
|
||||
items: ({query}: { query: string }) => {
|
||||
return [
|
||||
{
|
||||
title: t('input.editor.text'),
|
||||
description: t('input.editor.textTooltip'),
|
||||
icon: 'fa-font',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setNode('paragraph', {level: 1})
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.heading1'),
|
||||
description: t('input.editor.heading1Tooltip'),
|
||||
icon: 'fa-header',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setNode('heading', {level: 1})
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.heading2'),
|
||||
description: t('input.editor.heading2Tooltip'),
|
||||
icon: 'fa-header',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setNode('heading', {level: 2})
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.heading3'),
|
||||
description: t('input.editor.heading3Tooltip'),
|
||||
icon: 'fa-header',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setNode('heading', {level: 2})
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.bulletList'),
|
||||
description: t('input.editor.bulletListTooltip'),
|
||||
icon: 'fa-list-ul',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.toggleBulletList()
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.orderedList'),
|
||||
description: t('input.editor.orderedListTooltip'),
|
||||
icon: 'fa-list-ol',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.toggleOrderedList()
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.taskList'),
|
||||
description: t('input.editor.taskListTooltip'),
|
||||
icon: 'fa-list-check',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.toggleTaskList()
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.quote'),
|
||||
description: t('input.editor.quoteTooltip'),
|
||||
icon: 'fa-quote-right',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.toggleBlockquote()
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.code'),
|
||||
description: t('input.editor.codeTooltip'),
|
||||
icon: 'fa-code',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.toggleCodeBlock()
|
||||
.run()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.image'),
|
||||
description: t('input.editor.imageTooltip'),
|
||||
icon: 'fa-image',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.run()
|
||||
document.getElementById('tiptap__image-upload').click()
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('input.editor.horizontalRule'),
|
||||
description: t('input.editor.horizontalRuleTooltip'),
|
||||
icon: 'fa-ruler-horizontal',
|
||||
command: ({editor, range}) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setHorizontalRule()
|
||||
.run()
|
||||
},
|
||||
},
|
||||
].filter(item => item.title.toLowerCase().startsWith(query.toLowerCase()))
|
||||
},
|
||||
|
||||
render: () => {
|
||||
let component: VueRenderer
|
||||
let popup
|
||||
render: () => {
|
||||
let component: VueRenderer
|
||||
let popup
|
||||
|
||||
return {
|
||||
onStart: props => {
|
||||
component = new VueRenderer(CommandsList, {
|
||||
// using vue 2:
|
||||
// parent: this,
|
||||
// propsData: props,
|
||||
props,
|
||||
editor: props.editor,
|
||||
})
|
||||
return {
|
||||
onStart: props => {
|
||||
component = new VueRenderer(CommandsList, {
|
||||
// using vue 2:
|
||||
// parent: this,
|
||||
// propsData: props,
|
||||
props,
|
||||
editor: props.editor,
|
||||
})
|
||||
|
||||
if (!props.clientRect) {
|
||||
return
|
||||
}
|
||||
if (!props.clientRect) {
|
||||
return
|
||||
}
|
||||
|
||||
popup = tippy('body', {
|
||||
getReferenceClientRect: props.clientRect,
|
||||
appendTo: () => document.body,
|
||||
content: component.element,
|
||||
showOnCreate: true,
|
||||
interactive: true,
|
||||
trigger: 'manual',
|
||||
placement: 'bottom-start',
|
||||
})
|
||||
},
|
||||
popup = tippy('body', {
|
||||
getReferenceClientRect: props.clientRect,
|
||||
appendTo: () => document.body,
|
||||
content: component.element,
|
||||
showOnCreate: true,
|
||||
interactive: true,
|
||||
trigger: 'manual',
|
||||
placement: 'bottom-start',
|
||||
})
|
||||
},
|
||||
|
||||
onUpdate(props) {
|
||||
component.updateProps(props)
|
||||
onUpdate(props) {
|
||||
component.updateProps(props)
|
||||
|
||||
if (!props.clientRect) {
|
||||
return
|
||||
}
|
||||
if (!props.clientRect) {
|
||||
return
|
||||
}
|
||||
|
||||
popup[0].setProps({
|
||||
getReferenceClientRect: props.clientRect,
|
||||
})
|
||||
},
|
||||
popup[0].setProps({
|
||||
getReferenceClientRect: props.clientRect,
|
||||
})
|
||||
},
|
||||
|
||||
onKeyDown(props) {
|
||||
if (props.event.key === 'Escape') {
|
||||
popup[0].hide()
|
||||
onKeyDown(props) {
|
||||
if (props.event.key === 'Escape') {
|
||||
popup[0].hide()
|
||||
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return component.ref?.onKeyDown(props)
|
||||
},
|
||||
return component.ref?.onKeyDown(props)
|
||||
},
|
||||
|
||||
onExit() {
|
||||
popup[0].destroy()
|
||||
component.destroy()
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
onExit() {
|
||||
popup[0].destroy()
|
||||
component.destroy()
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ const modal = ref<HTMLElement | null>(null)
|
||||
const scrollLock = useScrollLock(modal)
|
||||
|
||||
watchEffect(() => {
|
||||
scrollLock.value = props.enabled
|
||||
scrollLock.value = props.enabled
|
||||
})
|
||||
|
||||
function onKeydown(e: KeyboardEvent) {
|
||||
|
||||
@@ -73,8 +73,8 @@ const tooltipText = computed(() => {
|
||||
return t('task.subscription.subscribedTaskThroughParentProject')
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
switch (props.entity) {
|
||||
case 'project':
|
||||
|
||||
@@ -194,7 +194,7 @@ function updateDateInQuery(newDate: string) {
|
||||
// Need to escape and unescape the query because the positions are based on the escaped query
|
||||
let escaped = escapeHtml(filterQuery.value)
|
||||
escaped = escaped
|
||||
.substring(0, currentDatepickerPos.value)
|
||||
.substring(0, currentDatepickerPos.value)
|
||||
+ escaped
|
||||
.substring(currentDatepickerPos.value)
|
||||
.replace(currentOldDatepickerValue.value, newDate)
|
||||
|
||||
@@ -329,9 +329,9 @@ function getShareLink(hash: string, viewId: IProjectView['id']|null) {
|
||||
|
||||
const shareLinks = computed(() => {
|
||||
return linkShares.value.reduce((links, linkShare) => {
|
||||
links[linkShare.id] = getShareLink(linkShare.hash, selectedViews.value[linkShare.id] ?? null)
|
||||
return links
|
||||
}, {} as {[id: string]: string },
|
||||
links[linkShare.id] = getShareLink(linkShare.hash, selectedViews.value[linkShare.id] ?? null)
|
||||
return links
|
||||
}, {} as {[id: string]: string },
|
||||
)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -110,8 +110,8 @@ const errorMessage = ref('')
|
||||
|
||||
function resetEmptyTitleError() {
|
||||
if (!newTaskTitle.value) {
|
||||
errorMessage.value = ''
|
||||
}
|
||||
errorMessage.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
const loading = computed(() => taskStore.isLoading)
|
||||
|
||||
@@ -60,7 +60,7 @@ const emit = defineEmits<{
|
||||
|
||||
const description = ref<string>('')
|
||||
watchEffect(() => {
|
||||
description.value = props.modelValue.description
|
||||
description.value = props.modelValue.description
|
||||
})
|
||||
|
||||
const saved = ref(false)
|
||||
|
||||
@@ -133,8 +133,8 @@ async function save(title: string) {
|
||||
}
|
||||
|
||||
async function cancel(element: HTMLInputElement) {
|
||||
element.textContent = props.task.title
|
||||
element.blur()
|
||||
element.textContent = props.task.title
|
||||
element.blur()
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -238,7 +238,7 @@ watch(
|
||||
(value) => {
|
||||
relatedTasks.value = value
|
||||
},
|
||||
{immediate: true},
|
||||
{immediate: true},
|
||||
)
|
||||
|
||||
const showNewRelationForm = ref(false)
|
||||
|
||||
@@ -32,13 +32,13 @@ export const useColorScheme = createSharedComposable(() => {
|
||||
return autoColorScheme === 'dark'
|
||||
})
|
||||
|
||||
function onChanged(v: boolean) {
|
||||
function onChanged(v: boolean) {
|
||||
const el = window?.document.querySelector('html')
|
||||
el?.classList.toggle(CLASS_DARK, v)
|
||||
el?.classList.toggle(CLASS_LIGHT, !v)
|
||||
}
|
||||
|
||||
watch(isDark, onChanged, { flush: 'post' })
|
||||
watch(isDark, onChanged, { flush: 'post' })
|
||||
|
||||
tryOnMounted(() => onChanged(isDark.value))
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ export function useProjectBackground(project: MaybeRefOrGetter<IProject | null>)
|
||||
|
||||
watch(
|
||||
() => [
|
||||
toValue(project)?.id ?? null,
|
||||
toValue(project)?.backgroundBlurHash ?? null,
|
||||
toValue(project)?.id ?? null,
|
||||
toValue(project)?.backgroundBlurHash ?? null,
|
||||
] as [IProject['id'] | null, IProject['backgroundBlurHash'] | null],
|
||||
async ([projectId, blurHash], oldValue) => {
|
||||
const projectValue = toValue(project)
|
||||
|
||||
@@ -34,27 +34,27 @@ const SORT_BY_DEFAULT: SortBy = {
|
||||
id: 'desc',
|
||||
}
|
||||
|
||||
// This makes sure an id sort order is always sorted last.
|
||||
// When tasks would be sorted first by id and then by whatever else was specified, the id sort takes
|
||||
// precedence over everything else, making any other sort columns pretty useless.
|
||||
function formatSortOrder(sortBy, params) {
|
||||
let hasIdFilter = false
|
||||
const sortKeys = Object.keys(sortBy)
|
||||
for (const s of sortKeys) {
|
||||
if (s === 'id') {
|
||||
sortKeys.splice(s, 1)
|
||||
hasIdFilter = true
|
||||
break
|
||||
}
|
||||
// This makes sure an id sort order is always sorted last.
|
||||
// When tasks would be sorted first by id and then by whatever else was specified, the id sort takes
|
||||
// precedence over everything else, making any other sort columns pretty useless.
|
||||
function formatSortOrder(sortBy, params) {
|
||||
let hasIdFilter = false
|
||||
const sortKeys = Object.keys(sortBy)
|
||||
for (const s of sortKeys) {
|
||||
if (s === 'id') {
|
||||
sortKeys.splice(s, 1)
|
||||
hasIdFilter = true
|
||||
break
|
||||
}
|
||||
if (hasIdFilter) {
|
||||
sortKeys.push('id')
|
||||
}
|
||||
params.sort_by = sortKeys
|
||||
params.order_by = sortKeys.map(s => sortBy[s])
|
||||
|
||||
return params
|
||||
}
|
||||
if (hasIdFilter) {
|
||||
sortKeys.push('id')
|
||||
}
|
||||
params.sort_by = sortKeys
|
||||
params.order_by = sortKeys.map(s => sortBy[s])
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
/**
|
||||
* This mixin provides a base set of methods and properties to get tasks.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export const RIGHTS = {
|
||||
'READ': 0,
|
||||
'READ_WRITE': 1,
|
||||
'ADMIN': 2,
|
||||
'READ': 0,
|
||||
'READ_WRITE': 1,
|
||||
'ADMIN': 2,
|
||||
} as const
|
||||
|
||||
export type Right = typeof RIGHTS[keyof typeof RIGHTS]
|
||||
|
||||
@@ -8,9 +8,9 @@ const DEFAULT_TIMEOUT = 60000
|
||||
export function createAsyncComponent<T extends Component = {
|
||||
new (): ComponentPublicInstance;
|
||||
}>(source: AsyncComponentLoader<T> | AsyncComponentOptions<T>): T {
|
||||
if (typeof source === 'function') {
|
||||
source = { loader: source }
|
||||
}
|
||||
if (typeof source === 'function') {
|
||||
source = { loader: source }
|
||||
}
|
||||
|
||||
return defineAsyncComponent({
|
||||
...source,
|
||||
|
||||
@@ -4,7 +4,7 @@ const SIZES = [
|
||||
'MB',
|
||||
'GB',
|
||||
'TB',
|
||||
] as const
|
||||
] as const
|
||||
|
||||
export function getHumanSize(inputSize: number) {
|
||||
let iterator = 0
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
function getDefaultBackground() {
|
||||
const div = document.createElement('div')
|
||||
document.head.appendChild(div)
|
||||
const bg = window.getComputedStyle(div).backgroundColor
|
||||
document.head.removeChild(div)
|
||||
return bg
|
||||
const div = document.createElement('div')
|
||||
document.head.appendChild(div)
|
||||
const bg = window.getComputedStyle(div).backgroundColor
|
||||
document.head.removeChild(div)
|
||||
return bg
|
||||
}
|
||||
|
||||
// get default style for current browser
|
||||
@@ -11,14 +11,14 @@ const defaultStyle = getDefaultBackground() // typically "rgba(0, 0, 0, 0)"
|
||||
|
||||
// based on https://stackoverflow.com/a/62630563/15522256
|
||||
export function getInheritedBackgroundColor(el: HTMLElement): string {
|
||||
const backgroundColor = window.getComputedStyle(el).backgroundColor
|
||||
const backgroundColor = window.getComputedStyle(el).backgroundColor
|
||||
|
||||
if (backgroundColor !== defaultStyle) return backgroundColor
|
||||
if (backgroundColor !== defaultStyle) return backgroundColor
|
||||
|
||||
if (!el.parentElement) {
|
||||
if (!el.parentElement) {
|
||||
// we reached the top parent el without getting an explicit color
|
||||
return defaultStyle
|
||||
}
|
||||
|
||||
return getInheritedBackgroundColor(el.parentElement)
|
||||
return getInheritedBackgroundColor(el.parentElement)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import type {DateKebab} from '@/types/DateKebab'
|
||||
|
||||
// ✅ Format a date to YYYY-MM-DD (or any other format)
|
||||
function padTo2Digits(num: number) {
|
||||
return num.toString().padStart(2, '0')
|
||||
return num.toString().padStart(2, '0')
|
||||
}
|
||||
|
||||
export function isoToKebabDate(isoDate: DateISO) {
|
||||
|
||||
@@ -15,8 +15,8 @@ import Card from '@/components/misc/Card.vue'
|
||||
|
||||
export const setupVue3 = defineSetupVue3(({ app }) => {
|
||||
// Add Pinia store
|
||||
const pinia = createPinia()
|
||||
app.use(pinia)
|
||||
const pinia = createPinia()
|
||||
app.use(pinia)
|
||||
app.use(i18n)
|
||||
|
||||
app.directive('cy', cypress)
|
||||
|
||||
@@ -37,8 +37,8 @@ export const createNewIndexer = (name: string, fieldsToIndex: string[]) => {
|
||||
}
|
||||
|
||||
return index.search(query)
|
||||
?.flatMap(r => r.result)
|
||||
.filter((value, index, self) => self.indexOf(value) === index) as number[]
|
||||
?.flatMap(r => r.result)
|
||||
.filter((value, index, self) => self.indexOf(value) === index) as number[]
|
||||
|| null
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { nativeEnum, number, object, preprocess } from 'zod'
|
||||
/**
|
||||
* Parses `repeatAfterSeconds` into a usable js object.
|
||||
*/
|
||||
export function parseRepeatAfter(repeatAfterSeconds: number): IRepeatAfter {
|
||||
export function parseRepeatAfter(repeatAfterSeconds: number): IRepeatAfter {
|
||||
let repeatAfter: IRepeatAfter = {type: 'hours', amount: repeatAfterSeconds / SECONDS_A_HOUR}
|
||||
|
||||
// if its dividable by 24, its something with days, otherwise hours
|
||||
|
||||
@@ -408,13 +408,13 @@ export async function getAuthForRoute(to: RouteLocation, authStore) {
|
||||
// Check if the route the user wants to go to is a route which needs authentication. We use this to
|
||||
// redirect the user after successful login.
|
||||
const isValidUserAppRoute = ![
|
||||
'user.login',
|
||||
'user.password-reset.request',
|
||||
'user.password-reset.reset',
|
||||
'user.register',
|
||||
'link-share.auth',
|
||||
'openid.auth',
|
||||
].includes(to.name as string) &&
|
||||
'user.login',
|
||||
'user.password-reset.request',
|
||||
'user.password-reset.reset',
|
||||
'user.register',
|
||||
'link-share.auth',
|
||||
'openid.auth',
|
||||
].includes(to.name as string) &&
|
||||
localStorage.getItem('emailConfirmToken') === null
|
||||
|
||||
if (isValidUserAppRoute) {
|
||||
|
||||
@@ -36,5 +36,5 @@ export const useAttachmentStore = defineStore('attachment', () => {
|
||||
|
||||
// support hot reloading
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot.accept(acceptHMRUpdate(useAttachmentStore, import.meta.hot))
|
||||
import.meta.hot.accept(acceptHMRUpdate(useAttachmentStore, import.meta.hot))
|
||||
}
|
||||
|
||||
@@ -400,7 +400,7 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
/**
|
||||
* Renews the api token and saves it to local storage
|
||||
*/
|
||||
function renewToken() {
|
||||
function renewToken() {
|
||||
// FIXME: Timeout to avoid race conditions when authenticated as a user (=auth token in localStorage) and as a
|
||||
// link share in another tab. Without the timeout both the token renew and link share auth are executed at
|
||||
// the same time and one might win over the other.
|
||||
@@ -481,5 +481,5 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
|
||||
// support hot reloading
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot.accept(acceptHMRUpdate(useAuthStore, import.meta.hot))
|
||||
import.meta.hot.accept(acceptHMRUpdate(useAuthStore, import.meta.hot))
|
||||
}
|
||||
|
||||
@@ -191,5 +191,5 @@ export const useBaseStore = defineStore('base', () => {
|
||||
|
||||
// support hot reloading
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot.accept(acceptHMRUpdate(useBaseStore, import.meta.hot))
|
||||
import.meta.hot.accept(acceptHMRUpdate(useBaseStore, import.meta.hot))
|
||||
}
|
||||
|
||||
@@ -103,10 +103,10 @@ export const useKanbanStore = defineStore('kanban', () => {
|
||||
}
|
||||
|
||||
function setTaskInBucketByIndex({
|
||||
bucketIndex,
|
||||
taskIndex,
|
||||
task,
|
||||
}: {
|
||||
bucketIndex,
|
||||
taskIndex,
|
||||
task,
|
||||
}: {
|
||||
bucketIndex: number,
|
||||
taskIndex: number,
|
||||
task: ITask
|
||||
|
||||
@@ -51,8 +51,8 @@ export const useLabelStore = defineStore('label', () => {
|
||||
const labelIdsToHide: number[] = labelsToHide.map(({id}) => id)
|
||||
|
||||
return search(query)
|
||||
?.filter(value => !labelIdsToHide.includes(value))
|
||||
.map(id => labels.value[id])
|
||||
?.filter(value => !labelIdsToHide.includes(value))
|
||||
.map(id => labels.value[id])
|
||||
|| []
|
||||
}
|
||||
})
|
||||
@@ -169,5 +169,5 @@ export const useLabelStore = defineStore('label', () => {
|
||||
|
||||
// support hot reloading
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot.accept(acceptHMRUpdate(useLabelStore, import.meta.hot))
|
||||
import.meta.hot.accept(acceptHMRUpdate(useLabelStore, import.meta.hot))
|
||||
}
|
||||
|
||||
@@ -83,8 +83,8 @@ export const useProjectStore = defineStore('project', () => {
|
||||
const searchProjectAndFilter = computed(() => {
|
||||
return (query: string, includeArchived = false) => {
|
||||
return search(query)
|
||||
?.map(id => projects.value[id])
|
||||
.filter(project => project?.isArchived === includeArchived)
|
||||
?.map(id => projects.value[id])
|
||||
.filter(project => project?.isArchived === includeArchived)
|
||||
|| []
|
||||
}
|
||||
})
|
||||
@@ -102,9 +102,9 @@ export const useProjectStore = defineStore('project', () => {
|
||||
const searchSavedFilter = computed(() => {
|
||||
return (query: string, includeArchived = false) => {
|
||||
return search(query)
|
||||
?.filter(value => getSavedFilterIdFromProjectId(value) > 0)
|
||||
.map(id => projects.value[id])
|
||||
.filter(project => project?.isArchived === includeArchived)
|
||||
?.filter(value => getSavedFilterIdFromProjectId(value) > 0)
|
||||
.map(id => projects.value[id])
|
||||
.filter(project => project?.isArchived === includeArchived)
|
||||
|| []
|
||||
}
|
||||
})
|
||||
|
||||
@@ -538,5 +538,5 @@ export const useTaskStore = defineStore('task', () => {
|
||||
|
||||
// support hot reloading
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot.accept(acceptHMRUpdate(useTaskStore, import.meta.hot))
|
||||
import.meta.hot.accept(acceptHMRUpdate(useTaskStore, import.meta.hot))
|
||||
}
|
||||
|
||||
@@ -334,17 +334,17 @@ function useAvailableTimezones(settingsRef: Ref<IUserSettings>) {
|
||||
.filter(tz => tz.label.toLowerCase().includes(query.toLowerCase()))
|
||||
}
|
||||
|
||||
const timezoneObject = computed({
|
||||
get: () => ({
|
||||
value: settingsRef.value.timezone,
|
||||
label: settingsRef.value.timezone?.replace(/_/g, ' '),
|
||||
}),
|
||||
set: (obj) => {
|
||||
if (obj && typeof obj === 'object' && 'value' in obj) {
|
||||
settingsRef.value.timezone = obj.value
|
||||
}
|
||||
},
|
||||
})
|
||||
const timezoneObject = computed({
|
||||
get: () => ({
|
||||
value: settingsRef.value.timezone,
|
||||
label: settingsRef.value.timezone?.replace(/_/g, ' '),
|
||||
}),
|
||||
set: (obj) => {
|
||||
if (obj && typeof obj === 'object' && 'value' in obj) {
|
||||
settingsRef.value.timezone = obj.value
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
availableTimezones,
|
||||
|
||||
Reference in New Issue
Block a user