Merge branch 'main' into feature/search-in-quick-actions

# Conflicts:
#	src/i18n/lang/en.json
This commit is contained in:
kolaente 2021-11-13 17:00:34 +01:00
commit 329b1cd646
Signed by: konrad
GPG Key ID: F40E70337AB24C9B
56 changed files with 8394 additions and 718 deletions

View File

@ -1,8 +1,7 @@
---
kind: pipeline
name: build
# TODO: update translations only nightly
trigger:
branch:
include:
@ -138,6 +137,25 @@ steps:
- failure
- success
- name: deploy-preview
image: node:16
pull: true
environment:
NETLIFY_AUTH_TOKEN:
from_secret: netlify_auth_token
NETLIFY_SITE_ID:
from_secret: netlify_site_id
GITEA_TOKEN:
from_secret: gitea_token
commands:
- node ./scripts/deploy-preview-netlify.js
depends_on:
- build-prod
when:
event:
include:
- pull_request
---
kind: pipeline
name: release-latest
@ -635,3 +653,8 @@ steps:
environment:
CROWDIN_KEY:
from_secret: crowdin_key
---
kind: signature
hmac: 15df446c7e93a881249d46273485183386157229ee6a37b1ed0fcb2a0b32bbe2
...

View File

@ -21,5 +21,9 @@ indent_size = 2
indent_style = space
indent_size = 2
[*.{scss,css}]
indent_style = space
indent_size = 2
[.nvmrc]
insert_final_newline = false

3
.gitignore vendored
View File

@ -26,3 +26,6 @@ stats.html
# Test files
cypress/screenshots
cypress/videos
# Local Netlify folder
.netlify

View File

@ -7,7 +7,7 @@ describe('The Menu', () => {
})
it('Can be hidden on desktop', () => {
cy.get('a.menu-show-button:visible')
cy.get('button.menu-show-button:visible')
.click()
cy.get('.namespace-container')
.should('not.have.class', 'is-active')
@ -21,7 +21,7 @@ describe('The Menu', () => {
it('Is can be shown on mobile', () => {
cy.viewport('iphone-8')
cy.get('a.menu-show-button:visible')
cy.get('button.menu-show-button:visible')
.click()
cy.get('.namespace-container')
.should('have.class', 'is-active')

15
netlify.toml Normal file
View File

@ -0,0 +1,15 @@
[build]
command = "yarn build"
publish = "dist"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
X-XSS-Protection = "1; mode=block"
X-Robots-Tag = "noindex"

View File

@ -69,10 +69,15 @@ http {
ssl_certificate /etc/nginx/ssl/dummy.crt;
ssl_certificate_key /etc/nginx/ssl/dummy.key;
location ~* .(txt|webmanifest|css|js|mjs|map|svg|jpg|jpeg|png|ico|ttf|woff|woff2|wav)$ {
root /usr/share/nginx/html;
try_files $uri $uri/ =404;
}
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /;
index index.html index.htm;
try_files $uri $uri/ /index.html;
index index.html;
}
error_page 500 502 503 504 /50x.html;

View File

@ -10,6 +10,7 @@
"build:modern-only": "BUILD_MODERN_ONLY=true vite build && workbox copyLibraries dist/",
"build:dev": "vite build -m development --outDir dist-dev/",
"lint": "eslint --ignore-pattern '*.test.*' ./src --ext .vue,.js,.ts",
"lint:markup": "vue-tsc --noEmit",
"cypress:open": "cypress open",
"test:unit": "jest",
"test:frontend": "cypress run",
@ -17,8 +18,8 @@
},
"dependencies": {
"@kyvg/vue3-notification": "2.3.4",
"@sentry/tracing": "6.14.0",
"@sentry/vue": "6.14.0",
"@sentry/tracing": "6.14.3",
"@sentry/vue": "6.14.3",
"@vue/compat": "3.2.21",
"bulma": "0.9.3",
"camel-case": "4.1.2",
@ -32,7 +33,7 @@
"is-touch-device": "1.0.1",
"lodash.clonedeep": "4.5.0",
"lodash.debounce": "4.0.8",
"marked": "4.0.0",
"marked": "4.0.3",
"register-service-worker": "1.7.2",
"snake-case": "3.0.4",
"ufo": "0.7.9",
@ -40,7 +41,7 @@
"vue-advanced-cropper": "2.6.3",
"vue-drag-resize": "2.0.3",
"vue-flatpickr-component": "9.0.5",
"vue-i18n": "9.2.0-beta.17",
"vue-i18n": "9.2.0-beta.18",
"vue-router": "4.0.12",
"vuedraggable": "4.1.0",
"vuex": "4.0.2",
@ -53,30 +54,34 @@
"@fortawesome/free-solid-svg-icons": "5.15.4",
"@fortawesome/vue-fontawesome": "3.0.0-5",
"@types/jest": "27.0.2",
"@typescript-eslint/eslint-plugin": "5.3.0",
"@typescript-eslint/parser": "5.3.0",
"@typescript-eslint/eslint-plugin": "5.3.1",
"@typescript-eslint/parser": "5.3.1",
"@vitejs/plugin-legacy": "1.6.2",
"@vitejs/plugin-vue": "1.9.4",
"@vue/eslint-config-typescript": "9.0.1",
"autoprefixer": "10.4.0",
"axios": "0.24.0",
"browserslist": "4.17.6",
"cypress": "8.7.0",
"cypress": "9.0.0",
"cypress-file-upload": "5.0.8",
"esbuild": "0.13.12",
"eslint": "8.1.0",
"esbuild": "0.13.13",
"eslint": "8.2.0",
"eslint-plugin-vue": "8.0.3",
"express": "4.17.1",
"faker": "5.5.3",
"jest": "27.3.1",
"netlify-cli": "6.14.23",
"postcss": "8.3.11",
"rollup": "2.59.0",
"rollup": "2.60.0",
"rollup-plugin-visualizer": "5.5.2",
"sass": "1.43.4",
"slugify": "1.6.2",
"ts-jest": "27.0.7",
"typescript": "4.4.4",
"vite": "2.6.13",
"vite": "2.6.14",
"vite-plugin-pwa": "0.11.3",
"vue-tsc": "0.29.4",
"vite-svg-loader": "3.1.0",
"wait-on": "6.0.0",
"workbox-cli": "6.3.0"
},

View File

@ -0,0 +1,66 @@
const slugify = require('slugify')
const {exec} = require('child_process')
const axios = require('axios')
const BOT_USER_ID = 513
const giteaToken = process.env.GITEA_TOKEN
const siteId = process.env.NETLIFY_SITE_ID
const branchSlug = slugify(process.env.DRONE_SOURCE_BRANCH)
const prNumber = process.env.DRONE_PULL_REQUEST
const prIssueCommentsUrl = `https://kolaente.dev/api/v1/repos/vikunja/frontend/issues/${prNumber}/comments`
const alias = `${prNumber}-${branchSlug}`
const fullPreviewUrl = `https://${alias}--vikunja-frontend-preview.netlify.app`
const promiseExec = cmd => {
return new Promise((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => {
if (error) {
reject(error)
return
}
resolve(stdout)
})
})
}
(async function () {
let stdout = await promiseExec(`./node_modules/.bin/netlify link --id ${siteId}`)
console.log(stdout)
stdout = await promiseExec(`./node_modules/.bin/netlify deploy --alias ${alias}`)
console.log(stdout)
const {data} = await axios.get(prIssueCommentsUrl)
const hasComment = data.some(c => c.user.id === BOT_USER_ID)
if (hasComment) {
console.log(`PR #${prNumber} already has a comment with a link, not sending another comment.`)
return
}
await axios.post(prIssueCommentsUrl, {
body: `
Hi ${process.env.DRONE_COMMIT_AUTHOR}!
Thank you for creating a PR!
I've deployed the changes of this PR on a preview environment under this URL: ${fullPreviewUrl}
You can use this url to view the changes live and test them out.
You will need to manually connect this to an api running somehwere. The easiest to use is https://try.vikunja.io/.
Have a nice day!
> Beep boop, I'm a bot.
`,
}, {
headers: {
'Content-Type': 'application/json',
'accept': 'application/json',
'Authorization': `token ${giteaToken}`,
},
})
console.log(`Preview comment sent successfully to PR #${prNumber}!`)
})()

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
import { computed } from 'vue'
import LogoFull from '@/assets/logo-full.svg?component'
import LogoFullPride from '@/assets/logo-full-pride.svg?component'
const Logo = computed(() => new Date().getMonth() === 5 ? LogoFullPride : LogoFull)
</script>
<template>
<Logo alt="Vikunja" />
</template>

View File

@ -0,0 +1,75 @@
<template>
<button
type="button"
@click="$store.commit('toggleMenu')"
class="menu-show-button"
@shortkey="() => $store.commit('toggleMenu')"
v-shortkey="['ctrl', 'e']"
:aria-label="menuActive ? $t('misc.hideMenu') : $t('misc.showMenu')"
/>
</template>
<script setup>
import { computed} from 'vue'
import {store} from '@/store'
const menuActive = computed(() => store.menuActive)
</script>
<style lang="scss" scoped>
$lineWidth: 2rem;
$size: $lineWidth + 1rem;
.menu-show-button {
// FIXME: create general button component
appearance: none;
background-color: transparent;
border: 0;
min-height: $size;
width: $size;
position: relative;
$transformX: translateX(-50%);
&::before,
&::after {
content: '';
display: block;
position: absolute;
height: 3px;
width: $lineWidth;
left: 50%;
transform: $transformX;
background-color: $grey-400;
border-radius: 2px;
transition: all $transition;
}
&::before {
top: 50%;
transform: $transformX translateY(-0.4rem)
}
&::after {
bottom: 50%;
transform: $transformX translateY(0.4rem)
}
&:hover,
&:focus {
&::before,
&::after {
background-color: $grey-600;
}
&::before {
transform: $transformX translateY(-0.5rem);
}
&::after {
transform: $transformX translateY(0.5rem)
}
}
}
</style>

View File

@ -0,0 +1,20 @@
<template>
<a class="menu-bottom-link" :href="poweredByUrl" target="_blank" rel="noreferrer noopener nofollow">
{{ $t('misc.poweredBy') }}
</a>
</template>
<script setup lang="ts">
import {POWERED_BY as poweredByUrl} from '@/urls'
</script>
<style lang="scss">
.menu-bottom-link {
color: $grey-300;
text-align: center;
display: block;
padding-top: 1rem;
padding-bottom: 1rem;
font-size: .8rem;
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<div>
<a @click="$store.commit('menuActive', false)" class="menu-hide-button" v-if="menuActive">
<icon icon="times"></icon>
<icon icon="times" />
</a>
<div
:class="{'has-background': background}"
@ -134,6 +134,32 @@ export default {
</script>
<style lang="scss" scoped>
.menu-hide-button {
position: fixed;
top: 0.5rem;
right: 0.5rem;
z-index: 31;
width: 3rem;
height: 3rem;
display: flex;
justify-content: center;
align-items: center;
font-size: 2rem;
color: $grey-400;
line-height: 1;
transition: all $transition;
@media screen and (min-width: $tablet) {
display: none;
}
&:hover,
&:focus {
height: 1rem;
color: $grey-600;
}
}
.app-container {
min-height: calc(100vh - 65px);

View File

@ -6,7 +6,7 @@
>
<div class="container has-text-centered link-share-view">
<div class="column is-10 is-offset-1">
<img alt="Vikunja" class="logo" :src="logoUrl" />
<Logo class="logo" />
<h1
:style="{ 'opacity': currentList.title === '' ? '0': '1' }"
class="title">
@ -14,9 +14,7 @@
</h1>
<div class="box has-text-left view">
<router-view/>
<a class="menu-bottom-link" href="https://vikunja.io" target="_blank" rel="noreferrer noopener nofollow">
{{ $t('misc.poweredBy') }}
</a>
<PoweredByLink />
</div>
</div>
</div>
@ -25,51 +23,45 @@
<script>
import {mapState} from 'vuex'
import {CURRENT_LIST} from '@/store/mutation-types'
import logoUrl from '@/assets/logo-full.svg'
import Logo from '@/components/home/Logo.vue'
import PoweredByLink from './PoweredByLink.vue'
export default {
name: 'contentLinkShare',
data() {
return {
logoUrl,
}
components: {
Logo,
PoweredByLink,
},
computed: mapState({
currentList: CURRENT_LIST,
background: 'background',
}),
computed: mapState([
'currentList',
'background',
]),
}
</script>
<style lang="scss" scoped>
.link-share-container.has-background .view {
background: transparent;
background-color: transparent;
border: none;
.logout .button {
box-shadow: none;
}
}
.link-share-view {
.logo {
max-width: 300px;
width: 90%;
margin: 2rem 0 1.5rem;
}
.logo {
max-width: 300px;
width: 90%;
margin: 2rem 0 1.5rem;
}
.column {
max-width: 100%;
}
.column {
max-width: 100%;
}
.card {
background: $white;
}
.title {
.title {
text-shadow: 0 0 1rem $white;
}
}
// FIXME: this should be defined somewhere deep
.link-share-view .card {
background-color: $white;
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<div class="no-auth-wrapper">
<div class="noauth-container">
<img alt="Vikunja" :src="logoUrl" width="400" height="117" />
<Logo width="400" height="117" />
<div class="message is-info" v-if="motd !== ''">
<div class="message-header">
<p>{{ $t('misc.info') }}</p>
@ -18,16 +18,13 @@
<script>
import {mapState} from 'vuex'
import logoUrl from '@/assets/logo-full.svg'
import Logo from '@/components/home/Logo.vue'
import { saveLastVisited } from '@/helpers/saveLastVisited'
export default {
name: 'contentNoAuth',
data() {
return {
logoUrl,
}
},
components: { Logo },
computed: {
routeName() {
return this.$route.name
@ -68,7 +65,7 @@ export default {
<style lang="scss" scoped>
.no-auth-wrapper {
background: url('@/assets/llama.svg') no-repeat bottom left fixed $light-background;
background: url('@/assets/llama.svg?url') no-repeat bottom left fixed $light-background;
min-height: 100vh;
}

View File

@ -2,7 +2,7 @@
<div :class="{'is-active': menuActive}" class="namespace-container">
<div class="menu top-menu">
<router-link :to="{name: 'home'}" class="logo">
<img alt="Vikunja" :src="logoUrl" width="164" height="48"/>
<Logo width="164" height="48" />
</router-link>
<ul class="menu-list">
<li>
@ -146,25 +146,34 @@
</div>
</template>
</aside>
<a class="menu-bottom-link" :href="poweredByUrl" target="_blank" rel="noreferrer noopener nofollow">
{{ $t('misc.poweredBy') }}
</a>
<PoweredByLink />
</div>
</template>
<script>
import {mapState} from 'vuex'
import {CURRENT_LIST, MENU_ACTIVE, LOADING, LOADING_MODULE} from '@/store/mutation-types'
import draggable from 'vuedraggable'
import ListSettingsDropdown from '@/components/list/list-settings-dropdown.vue'
import NamespaceSettingsDropdown from '@/components/namespace/namespace-settings-dropdown.vue'
import draggable from 'vuedraggable'
import {calculateItemPosition} from '@/helpers/calculateItemPosition'
import {POWERED_BY} from '@/urls'
import PoweredByLink from '@/components/home/PoweredByLink.vue'
import Logo from '@/components/home/Logo.vue'
import {CURRENT_LIST, MENU_ACTIVE, LOADING, LOADING_MODULE} from '@/store/mutation-types'
import {calculateItemPosition} from '@/helpers/calculateItemPosition'
import logoUrl from '@/assets/logo-full.svg'
export default {
name: 'navigation',
components: {
ListSettingsDropdown,
NamespaceSettingsDropdown,
draggable,
Logo,
PoweredByLink,
},
data() {
return {
listsVisible: {},
@ -174,15 +183,8 @@ export default {
ghostClass: 'ghost',
},
listUpdating: {},
logoUrl,
poweredByUrl: POWERED_BY,
}
},
components: {
ListSettingsDropdown,
NamespaceSettingsDropdown,
draggable,
},
computed: {
...mapState({
namespaces: state => state.namespaces.namespaces.filter(n => !n.isArchived),
@ -517,10 +519,13 @@ $vikunja-nav-selected-width: 0.4rem;
}
.logo {
display: none;
display: block;
@media screen and (max-width: $tablet) {
display: block;
padding-left: 2rem;
margin-right: 1rem;
@media screen and (min-width: $tablet) {
display: none;
}
}

View File

@ -5,24 +5,11 @@
class="navbar main-theme is-fixed-top"
role="navigation"
>
<div class="navbar-brand">
<router-link :to="{name: 'home'}" class="navbar-item logo">
<img width="164" height="48" alt="Vikunja" :src="logoUrl" />
</router-link>
<a
@click="$store.commit('toggleMenu')"
class="menu-show-button"
@shortkey="() => $store.commit('toggleMenu')"
v-shortkey="['ctrl', 'e']"
>
</a>
</div>
<a
@click="$store.commit('toggleMenu')"
class="menu-show-button"
>
</a>
<div class="list-title" ref="listTitle" :style="{'display': currentList.id ? '': 'none'}">
<router-link :to="{name: 'home'}" class="logo">
<Logo width="164" height="48" />
</router-link>
<MenuButton class="menu-button" />
<div class="list-title" ref="listTitle" v-show="currentList.id">
<template v-if="currentList.id">
<h1
:style="{ 'opacity': currentList.title === '' ? '0': '1' }"
@ -101,9 +88,8 @@ import Update from '@/components/home/update.vue'
import ListSettingsDropdown from '@/components/list/list-settings-dropdown.vue'
import Dropdown from '@/components/misc/dropdown.vue'
import Notifications from '@/components/notifications/notifications.vue'
import logoUrl from '@/assets/logo-full.svg'
import logoFullPrideUrl from '@/assets/logo-full-pride.svg'
import Logo from '@/components/home/Logo.vue'
import MenuButton from '@/components/home/MenuButton.vue'
export default {
name: 'topNavigation',
@ -112,11 +98,10 @@ export default {
Dropdown,
ListSettingsDropdown,
Update,
Logo,
MenuButton,
},
computed: {
logoUrl() {
return (new Date()).getMonth() === 5 ? logoFullPrideUrl : logoUrl
},
...mapState({
userInfo: state => state.auth.info,
userAvatar: state => state.auth.avatarUrl,
@ -155,19 +140,26 @@ $vikunja-nav-logo-full-width: 164px;
.navbar {
z-index: 4 !important;
}
.navbar-brand {
.logo {
display: none;
@media screen and (min-width: $tablet) {
align-self: stretch;
display: flex;
align-items: center;
.logo img {
width: $vikunja-nav-logo-full-width;
}
padding-left: 2rem;
margin-right: 1.5rem;
}
&.is-dark .navbar-brand > .navbar-item {
@media screen and (max-width: $tablet) {
margin: 0 auto;
}
}
.menu-button {
align-self: stretch;
margin-right: auto;
@media screen and (max-width: $tablet) {
margin-left: $hamburger-menu-icon-spacing;
}
}
@ -197,10 +189,6 @@ $vikunja-nav-logo-full-width: 164px;
}
@media screen and (max-width: $tablet) {
.navbar-brand {
display: none;
}
.user {
width: $user-dropdown-width-mobile;
display: flex;

View File

@ -21,7 +21,14 @@
</svg>
</div>
<x-button :disabled="isEmpty" @click="reset" class="is-small ml-2" :shadow="false" type="secondary">
<x-button
v-if="!isEmpty"
:disabled="isEmpty"
@click="reset"
class="is-small ml-2"
:shadow="false"
type="secondary"
>
{{ $t('input.resetColor') }}
</x-button>
</div>

View File

@ -7,7 +7,9 @@
@focus="focus"
>
<div class="control" :class="{'is-loading': loading || localLoading}">
<div class="input-wrapper input" :class="{'has-multiple': multiple && Array.isArray(internalValue) && internalValue.length > 0}">
<div
class="input-wrapper input"
:class="{'has-multiple': hasMultiple}">
<template v-if="Array.isArray(internalValue)">
<template v-for="(item, key) in internalValue">
<slot name="tag" :item="item">
@ -81,7 +83,7 @@
</template>
<script>
import { i18n } from '@/i18n'
import {i18n} from '@/i18n'
import {closeWhenClickedOutside} from '@/helpers/closeWhenClickedOutside'
export default {
@ -134,9 +136,7 @@ export default {
// If true, will provide an "add this as a new value" entry which fires an @create event when clicking on it.
creatable: {
type: Boolean,
default() {
return false
},
default: false,
},
// The text shown next to the new value option.
createPlaceholder: {
@ -155,23 +155,17 @@ export default {
// If true, allows for selecting multiple items. v-model will be an array with all selected values in that case.
multiple: {
type: Boolean,
default() {
return false
},
default: false,
},
// If true, displays the search results inline instead of using a dropdown.
inline: {
type: Boolean,
default() {
return false
},
default: false,
},
// If true, shows search results when no query is specified.
showEmpty: {
type: Boolean,
default() {
return true
},
default: true,
},
// The delay in ms after which the search event will be fired. Used to avoid hitting the network on every keystroke.
searchDelay: {
@ -180,8 +174,12 @@ export default {
return 200
},
},
closeAfterSelect: {
type: Boolean,
default: true,
},
},
/**
* Available events:
* @search: Triggered every time the search query input changes
@ -234,6 +232,9 @@ export default {
return this.searchResults
},
hasMultiple() {
return this.multiple && Array.isArray(this.internalValue) && this.internalValue.length > 0
},
},
methods: {
// Searching will be triggered with a 200ms delay to avoid searching on every keyup event.
@ -285,7 +286,9 @@ export default {
this.$emit('update:modelValue', this.internalValue)
this.$emit('select', object)
this.setSelectedObject(object)
this.closeSearchResults()
if (this.closeAfterSelect && this.filteredSearchResults.length > 0 && !this.creatableAvailable) {
this.closeSearchResults()
}
},
setSelectedObject(object, resetOnly = false) {
this.internalValue = object

View File

@ -4,7 +4,13 @@
<p class="card-header-title">
{{ title }}
</p>
<a @click="$emit('close')" class="card-header-icon" v-if="hasClose">
<a
v-if="hasClose"
class="card-header-icon"
:aria-label="$t('misc.close')"
@click="$emit('close')"
v-tooltip="$t('misc.close')"
>
<span class="icon">
<icon :icon="closeIcon"/>
</span>
@ -36,7 +42,7 @@ export default {
},
closeIcon: {
type: String,
default: 'angle-right',
default: 'times',
},
shadow: {
type: Boolean,

View File

@ -6,7 +6,6 @@
:padding="false"
class="has-text-left has-overflow"
:has-close="true"
close-icon="times"
@close="$router.back()"
:loading="loading"
>

View File

@ -1,6 +1,6 @@
<template>
<modal @close="close()">
<card class="has-background-white has-no-shadow" :title="$t('keyboardShortcuts.title')">
<card class="has-no-shadow" :title="$t('keyboardShortcuts.title')">
<div class="message is-primary">
<div class="message-body">
{{ $t('keyboardShortcuts.allPages') }}

View File

@ -1,4 +1,10 @@
<template>
<card
class="taskedit"
:title="$t('list.list.editTask')"
@close="$emit('close')"
:has-close="true"
>
<form @submit.prevent="editTaskSubmit()">
<div class="field">
<label class="label" for="tasktext">{{ $t('task.attributes.title') }}</label>
@ -66,6 +72,7 @@
{{ $t('task.openDetail') }}
</router-link>
</form>
</card>
</template>
<script>

View File

@ -167,15 +167,13 @@
</x-button>
</form>
<transition name="fade">
<card
<edit-task
v-if="isTaskEdit"
class="taskedit"
:title="$t('list.list.editTask')"
@close="() => {isTaskEdit = false;taskToEdit = null}"
:has-close="true"
>
<edit-task :task="taskToEdit"/>
</card>
:task="taskToEdit"
/>
</transition>
</div>
</template>
@ -612,7 +610,6 @@ $gantt-vertical-border-color: $grey-100;
.taskedit {
position: fixed;
min-height: 0;
top: 10vh;
right: 10vw;
z-index: 5;

View File

@ -12,6 +12,7 @@
:create-placeholder="$t('task.label.createPlaceholder')"
v-model="labels"
:search-delay="10"
:close-after-select="false"
>
<template #tag="props">
<span
@ -148,3 +149,9 @@ export default {
},
}
</script>
<style lang="scss" scoped>
.tag {
margin: .5rem 0 0 .5rem;
}
</style>

View File

@ -11,7 +11,7 @@
:overflow="true"
variant="hint-modal"
>
<card class="has-background-white has-no-shadow" :title="$t('task.quickAddMagic.title')">
<card class="has-no-shadow" :title="$t('task.quickAddMagic.title')">
<p>{{ $t('task.quickAddMagic.intro') }}</p>
<h3>{{ $t('task.attributes.labels') }}</h3>

View File

@ -449,7 +449,9 @@
"saved": "Uloženo!",
"default": "Výchozí",
"close": "Zavřít",
"download": "Stáhnout"
"download": "Stáhnout",
"showMenu": "Show the menu",
"hideMenu": "Hide the menu"
},
"input": {
"resetColor": "Obnovit barvu",
@ -792,7 +794,7 @@
"quickActions": {
"commands": "Příkazy",
"placeholder": "Napište příkaz nebo vyhledávání…",
"hint": "Můžete použít # pro hledání úkolů, * pro hledání seznamů a @ pro hledání týmů.",
"hint": "You can use # to only search for tasks, * to only search for lists and @ to only search for teams.",
"tasks": "Úkoly",
"lists": "Seznamy",
"teams": "Týmy",

View File

@ -449,7 +449,9 @@
"saved": "Gespeichert!",
"default": "Standard",
"close": "Schließen",
"download": "Herunterladen"
"download": "Herunterladen",
"showMenu": "Show the menu",
"hideMenu": "Hide the menu"
},
"input": {
"resetColor": "Farbe zurücksetzen",
@ -792,7 +794,7 @@
"quickActions": {
"commands": "Befehle",
"placeholder": "Gib einen Befehl oder eine Suche ein …",
"hint": "Du kannst # verwenden, um nur nach Aufgaben zu suchen, *, um nur nach Listen zu suchen und @, um nur nach Teams zu suchen.",
"hint": "You can use # to only search for tasks, * to only search for lists and @ to only search for teams.",
"tasks": "Aufgaben",
"lists": "Listen",
"teams": "Teams",

View File

@ -449,7 +449,9 @@
"saved": "Gspeicheret!",
"default": "Standard",
"close": "Schlüüse",
"download": "Herunterladen"
"download": "Herunterladen",
"showMenu": "Show the menu",
"hideMenu": "Hide the menu"
},
"input": {
"resetColor": "Farb zruggsetze",
@ -792,7 +794,7 @@
"quickActions": {
"commands": "Befehl",
"placeholder": "Schriib en Befehl oder suech…",
"hint": "Du chasch en # benutze, um nur nach Uufgabe zsueche, * um nur nach Liste zsueche und @ um nur Teams z'sueche.",
"hint": "You can use # to only search for tasks, * to only search for lists and @ to only search for teams.",
"tasks": "Uufgabe",
"lists": "Listene",
"teams": "Teams",

View File

@ -449,7 +449,9 @@
"saved": "Saved!",
"default": "Default",
"close": "Close",
"download": "Download"
"download": "Download",
"showMenu": "Show the menu",
"hideMenu": "Hide the menu"
},
"input": {
"resetColor": "Reset Color",

View File

@ -449,7 +449,9 @@
"saved": "Saved!",
"default": "Default",
"close": "Close",
"download": "Download"
"download": "Download",
"showMenu": "Show the menu",
"hideMenu": "Hide the menu"
},
"input": {
"resetColor": "Reset Color",
@ -792,7 +794,7 @@
"quickActions": {
"commands": "Commands",
"placeholder": "Type a command or search…",
"hint": "You can use # to only seach for tasks, * to only search for lists and @ to only search for teams.",
"hint": "You can use # to only search for tasks, * to only search for lists and @ to only search for teams.",
"tasks": "Tasks",
"lists": "Lists",
"teams": "Teams",

View File

@ -449,7 +449,9 @@
"saved": "Enregistré !",
"default": "Par défaut",
"close": "Fermer",
"download": "Télécharger"
"download": "Télécharger",
"showMenu": "Show the menu",
"hideMenu": "Hide the menu"
},
"input": {
"resetColor": "Réinitialiser la couleur",
@ -792,7 +794,7 @@
"quickActions": {
"commands": "Commandes",
"placeholder": "Écris une commande ou une recherche…",
"hint": "Tu peux utiliser # pour rechercher uniquement les tâches, * pour rechercher uniquement les listes et @ pour rechercher uniquement les équipes.",
"hint": "You can use # to only search for tasks, * to only search for lists and @ to only search for teams.",
"tasks": "Tâches",
"lists": "Listes",
"teams": "Équipes",

View File

@ -105,7 +105,7 @@
}
},
"deletion": {
"title": "Elimina il tuo account Vikunja",
"title": "Delete your Vikunja Account",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, lists, tasks and everything associated with it.",
"text2": "Per continuare, inserisci la tua password. Riceverai un'e-mail con ulteriori istruzioni.",
"confirm": "Elimina il mio profilo",
@ -449,7 +449,9 @@
"saved": "Salvato!",
"default": "Predefinito",
"close": "Chiudi",
"download": "Scarica"
"download": "Scarica",
"showMenu": "Show the menu",
"hideMenu": "Hide the menu"
},
"input": {
"resetColor": "Ripristina Colore",
@ -506,7 +508,7 @@
"titleDates": "Attività dal {from} al {to}",
"noDates": "Mostra attività senza date",
"current": "Attività attuali",
"from": "Attività da",
"from": "Tasks from",
"until": "until",
"today": "Oggi",
"nextWeek": "Settimana Prossima",
@ -534,14 +536,14 @@
"text2": "Questo rimuoverà anche tutti gli allegati, i promemoria e le relazioni associati a questa attività e non può essere ripristinato!"
},
"actions": {
"assign": "Assegna questa attività a un utente",
"assign": "Assign this task to a user",
"label": "Aggiungi etichette",
"priority": "Imposta Priorità",
"dueDate": "Imposta data di scadenza",
"startDate": "Imposta una data di inizio",
"endDate": "Imposta una data di fine",
"reminders": "Imposta promemoria",
"repeatAfter": "Imposta un intervallo di ripetizione",
"repeatAfter": "Set a repeating interval",
"percentDone": "Imposta Percentuale Completata",
"attachments": "Aggiungi allegati",
"relatedTasks": "Aggiungi attività collegate",
@ -792,7 +794,7 @@
"quickActions": {
"commands": "Commands",
"placeholder": "Type a command or search…",
"hint": "You can use # to only seach for tasks, * to only search for lists and @ to only search for teams.",
"hint": "You can use # to only search for tasks, * to only search for lists and @ to only search for teams.",
"tasks": "Tasks",
"lists": "Liste",
"teams": "Teams",

View File

@ -449,7 +449,9 @@
"saved": "Saved!",
"default": "Default",
"close": "Close",
"download": "Download"
"download": "Download",
"showMenu": "Show the menu",
"hideMenu": "Hide the menu"
},
"input": {
"resetColor": "Reset Color",
@ -792,7 +794,7 @@
"quickActions": {
"commands": "Commands",
"placeholder": "Type a command or search…",
"hint": "You can use # to only seach for tasks, * to only search for lists and @ to only search for teams.",
"hint": "You can use # to only search for tasks, * to only search for lists and @ to only search for teams.",
"tasks": "Tasks",
"lists": "Lists",
"teams": "Teams",

View File

@ -449,7 +449,9 @@
"saved": "Saved!",
"default": "Default",
"close": "Close",
"download": "Download"
"download": "Download",
"showMenu": "Show the menu",
"hideMenu": "Hide the menu"
},
"input": {
"resetColor": "Reset Color",
@ -792,7 +794,7 @@
"quickActions": {
"commands": "Commands",
"placeholder": "Type a command or search…",
"hint": "You can use # to only seach for tasks, * to only search for lists and @ to only search for teams.",
"hint": "You can use # to only search for tasks, * to only search for lists and @ to only search for teams.",
"tasks": "Tasks",
"lists": "Lists",
"teams": "Teams",

View File

@ -449,7 +449,9 @@
"saved": "Saved!",
"default": "Default",
"close": "Close",
"download": "Download"
"download": "Download",
"showMenu": "Show the menu",
"hideMenu": "Hide the menu"
},
"input": {
"resetColor": "Reset Color",
@ -792,7 +794,7 @@
"quickActions": {
"commands": "Commands",
"placeholder": "Type a command or search…",
"hint": "You can use # to only seach for tasks, * to only search for lists and @ to only search for teams.",
"hint": "You can use # to only search for tasks, * to only search for lists and @ to only search for teams.",
"tasks": "Tasks",
"lists": "Lists",
"teams": "Teams",

View File

@ -449,7 +449,9 @@
"saved": "Saved!",
"default": "Default",
"close": "Close",
"download": "Download"
"download": "Download",
"showMenu": "Show the menu",
"hideMenu": "Hide the menu"
},
"input": {
"resetColor": "Reset Color",
@ -792,7 +794,7 @@
"quickActions": {
"commands": "Commands",
"placeholder": "Type a command or search…",
"hint": "You can use # to only seach for tasks, * to only search for lists and @ to only search for teams.",
"hint": "You can use # to only search for tasks, * to only search for lists and @ to only search for teams.",
"tasks": "Tasks",
"lists": "Lists",
"teams": "Teams",

View File

@ -449,7 +449,9 @@
"saved": "Сохранено!",
"default": "По умолчанию",
"close": "Закрыть",
"download": "Скачать"
"download": "Скачать",
"showMenu": "Show the menu",
"hideMenu": "Hide the menu"
},
"input": {
"resetColor": "Сбросить цвет",
@ -792,7 +794,7 @@
"quickActions": {
"commands": "Команды",
"placeholder": "Введи команду или поисковый запрос…",
"hint": "Используй # для поиска только задач, * для поиска только списков и @ для поиска только команд.",
"hint": "You can use # to only search for tasks, * to only search for lists and @ to only search for teams.",
"tasks": "Задачи",
"lists": "Списки",
"teams": "Команды",

902
src/i18n/lang/tr-TR.json Normal file
View File

@ -0,0 +1,902 @@
{
"home": {
"welcomeNight": "Good Night {username}",
"welcomeMorning": "Good Morning {username}",
"welcomeDay": "Hi {username}",
"welcomeEvening": "Good Evening {username}",
"lastViewed": "Last viewed",
"list": {
"newText": "You can create a new list for your new tasks:",
"new": "Create a new list",
"importText": "Or import your lists and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
"404": {
"title": "Not found",
"text": "The page you requested does not exist."
},
"user": {
"auth": {
"username": "Username",
"usernameEmail": "Username Or Email Address",
"usernamePlaceholder": "e.g. frederick",
"email": "E-mail address",
"emailPlaceholder": "e.g. frederic{'@'}vikunja.io",
"password": "Password",
"passwordRepeat": "Retype your password",
"passwordPlaceholder": "e.g. •••••••••••",
"resetPassword": "Reset your password",
"resetPasswordAction": "Send me a password reset link",
"resetPasswordSuccess": "Check your inbox! You should have an e-mail with instructions on how to reset your password.",
"passwordsDontMatch": "Passwords don't match",
"confirmEmailSuccess": "You successfully confirmed your email! You can log in now.",
"totpTitle": "Two Factor Authentication Code",
"totpPlaceholder": "e.g. 123456",
"login": "Login",
"register": "Register",
"loginWith": "Log in with {provider}",
"authenticating": "Authenticating…",
"openIdStateError": "State does not match, refusing to continue!",
"openIdGeneralError": "An error occured while authenticating against the third party.",
"logout": "Logout"
},
"settings": {
"title": "Settings",
"newPasswordTitle": "Update Your Password",
"newPassword": "New Password",
"newPasswordConfirm": "New Password Confirmation",
"currentPassword": "Current Password",
"currentPasswordPlaceholder": "Your current password",
"passwordsDontMatch": "The new password and its confirmation don't match.",
"passwordUpdateSuccess": "The password was successfully updated.",
"updateEmailTitle": "Update Your E-Mail Address",
"updateEmailNew": "New Email Address",
"updateEmailSuccess": "Your email address was successfully updated. We've sent you a link to confirm it.",
"general": {
"title": "General Settings",
"name": "Name",
"newName": "The new Name",
"savedSuccess": "The settings were successfully updated.",
"emailReminders": "Send me reminders for tasks via Email",
"overdueReminders": "Send me reminders for overdue undone tasks via email each morning",
"discoverableByName": "Let other users find me when they search for my name",
"discoverableByEmail": "Let other users find me when they search for my full email",
"playSoundWhenDone": "Play a sound when marking tasks as done",
"weekStart": "Week starts on",
"weekStartSunday": "Sunday",
"weekStartMonday": "Monday",
"language": "Language",
"defaultList": "Default List"
},
"totp": {
"title": "Two Factor Authentication",
"enroll": "Enroll",
"finishSetupPart1": "To finish your setup, use this secret in your totp app (Google Authenticator or similar):",
"finishSetupPart2": "After that, enter a code from your app below.",
"scanQR": "Alternatively you can scan this QR code:",
"passcode": "Passcode",
"passcodePlaceholder": "A code generated by your totp application",
"setupSuccess": "You've sucessfully set up two factor authentication!",
"enterPassword": "Please Enter Your Password",
"disable": "Disable two factor authentication",
"confirmSuccess": "You've successfully confirmed your totp setup and can use it from now on!",
"disableSuccess": "Two factor authentication was sucessfully disabled."
},
"caldav": {
"title": "Caldav",
"howTo": "You can connect Vikunja to caldav clients to view and manage all tasks from different clients. Enter this url into your client:",
"more": "More information about caldav in Vikunja"
},
"avatar": {
"title": "Avatar",
"initials": "Initials",
"gravatar": "Gravatar",
"upload": "Upload",
"uploadAvatar": "Upload Avatar",
"statusUpdateSuccess": "Avatar status was updated successfully!",
"setSuccess": "The avatar has been set successfully!"
},
"quickAddMagic": {
"title": "Quick Add Magic Mode",
"disabled": "Disabled",
"todoist": "Todoist",
"vikunja": "Vikunja"
}
},
"deletion": {
"title": "Delete your Vikunja Account",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, lists, tasks and everything associated with it.",
"text2": "To proceed, please enter your password. You will receive an email with further instructions.",
"confirm": "Delete my account",
"requestSuccess": "The request was successful. You'll receive an email with further instructions.",
"passwordRequired": "Please enter your password.",
"confirmSuccess": "You've successfully confirmed the deletion of your account. We will delete your account in three days.",
"scheduled": "We will delete your Vikunja account at {date} ({dateSince}).",
"scheduledCancel": "To cancel the deletion of your account, click here.",
"scheduledCancelText": "To cancel the deletion of your account, please enter your password below:",
"scheduledCancelConfirm": "Cancel the deletion of my account",
"scheduledCancelSuccess": "We will not delete your account."
},
"export": {
"title": "Export your Vikunja data",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Lists, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Please enter your password to proceed:",
"request": "Request a copy of my Vikunja Data",
"success": "You've successfully requested your Vikunja Data! We will send you an email once it's ready to download.",
"downloadTitle": "Download your exported Vikunja data"
}
},
"list": {
"archived": "This list is archived. It is not possible to create new or edit tasks for it.",
"title": "List Title",
"color": "Color",
"lists": "Lists",
"search": "Type to search for a list…",
"searchSelect": "Click or press enter to select this list",
"shared": "Shared Lists",
"create": {
"header": "Create a new list",
"titlePlaceholder": "The list's title goes here…",
"addTitleRequired": "Please specify a title.",
"createdSuccess": "The list was successfully created.",
"addListRequired": "Please specify a list or set a default list in the settings."
},
"archive": {
"title": "Archive \"{list}\"",
"archive": "Archive this list",
"unarchive": "Un-Archive this list",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this list or create new tasks until you un-archive it.",
"success": "The list was successfully archived."
},
"background": {
"title": "Set list background",
"remove": "Remove Background",
"upload": "Choose a background from your pc",
"searchPlaceholder": "Search for a background…",
"poweredByUnsplash": "Powered by Unsplash",
"loadMore": "Load more photos",
"success": "The background has been set successfully!",
"removeSuccess": "The background has been removed successfully!"
},
"delete": {
"title": "Delete \"{list}\"",
"header": "Delete this list",
"text1": "Are you sure you want to delete this list and all of its contents?",
"text2": "This includes all tasks and CANNOT BE UNDONE!",
"success": "The list was successfully deleted."
},
"duplicate": {
"title": "Duplicate this list",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated list:",
"success": "The list was successfully duplicated."
},
"edit": {
"header": "Edit This List",
"title": "Edit \"{list}\"",
"titlePlaceholder": "The list title goes here…",
"identifierTooltip": "The list identifier can be used to uniquely identify a task across lists. You can set it to empty to disable it.",
"identifier": "List Identifier",
"identifierPlaceholder": "The list identifier goes here…",
"description": "Description",
"descriptionPlaceholder": "The lists description goes here…",
"color": "Color",
"success": "The list was successfully updated."
},
"share": {
"header": "Share this list",
"title": "Share \"{list}\"",
"share": "Share",
"links": {
"title": "Share Links",
"what": "What is a share link?",
"explanation": "Share Links allow you to easily share a list with other users who don't have an account on Vikunja.",
"create": "Create a new link share",
"name": "Name (optional)",
"namePlaceholder": "e.g. Lorem Ipsum",
"nameExplanation": "All actions done by this link share will show up with the name.",
"password": "Password (optional)",
"passwordExplanation": "When authenticating, the user will be required to enter this password.",
"noName": "No name set",
"remove": "Remove a link share",
"removeText": "Are you sure you want to remove this link share? It will no longer be possible to access this list with this link share. This cannot be undone!",
"createSuccess": "The link share was successfully created.",
"deleteSuccess": "The link share was successfully deleted"
},
"userTeam": {
"typeUser": "user | users",
"typeTeam": "team | teams",
"shared": "Shared with these {type}",
"you": "You",
"notShared": "Not shared with any {type} yet.",
"removeHeader": "Remove a {type} from the {sharable}",
"removeText": "Are you sure you want to remove this {sharable} from the {type}? This cannot be undone!",
"removeSuccess": "The {sharable} was successfully removed from the {type}.",
"addedSuccess": "The {type} was successfully added.",
"updatedSuccess": "The {type} was successfully added."
},
"right": {
"title": "Right",
"read": "Read only",
"readWrite": "Read & write",
"admin": "Admin"
},
"attributes": {
"link": "Link",
"name": "Name",
"sharedBy": "Shared by",
"right": "Right",
"delete": "Delete"
}
},
"list": {
"title": "List",
"add": "Add",
"addPlaceholder": "Add a new task…",
"empty": "This list is currently empty.",
"newTaskCta": "Create a new task.",
"editTask": "Edit Task"
},
"gantt": {
"title": "Gantt",
"showTasksWithoutDates": "Show tasks which don't have dates set",
"size": "Size",
"default": "Default",
"month": "Month",
"day": "Day",
"from": "From",
"to": "To",
"noDates": "This task has no dates set."
},
"table": {
"title": "Table",
"columns": "Columns"
},
"kanban": {
"title": "Kanban",
"limit": "Limit: {limit}",
"noLimit": "Not Set",
"doneBucket": "Done bucket",
"doneBucketHint": "All tasks moved into this bucket will automatically marked as done.",
"doneBucketHintExtended": "All tasks moved into the done bucket will be marked as done automatically. All tasks marked as done from elsewhere will be moved as well.",
"doneBucketSavedSuccess": "The done bucket has been saved successfully.",
"deleteLast": "You cannot remove the last bucket.",
"addTaskPlaceholder": "Enter the new task title…",
"addTask": "Add a task",
"addAnotherTask": "Add another task",
"addBucket": "Create a new bucket",
"addBucketPlaceholder": "Enter the new bucket title…",
"deleteHeaderBucket": "Delete the bucket",
"deleteBucketText1": "Are you sure you want to delete this bucket?",
"deleteBucketText2": "This will not delete any tasks but move them into the default bucket.",
"deleteBucketSuccess": "The bucket has been deleted successfully.",
"bucketTitleSavedSuccess": "The bucket title has been saved successfully.",
"bucketLimitSavedSuccess": "The bucket limit been saved successfully.",
"collapse": "Collapse this bucket"
},
"pseudo": {
"favorites": {
"title": "Favorites"
}
}
},
"namespace": {
"title": "Namespaces & Lists",
"namespace": "Namespace",
"showArchived": "Show Archived",
"noneAvailable": "You don't have any namespaces right now.",
"unarchive": "Un-Archive",
"archived": "Archived",
"noLists": "This namespace does not contain any lists.",
"createList": "Create a new list in this namespace.",
"namespaces": "Namespaces",
"search": "Type to search for a namespace…",
"create": {
"title": "Create a new namespace",
"titleRequired": "Please specify a title.",
"explanation": "A namespace is a collection of lists you can share and use to organize your lists with. In fact, every list belongs to a namepace.",
"tooltip": "What's a namespace?",
"success": "The namespace was successfully created."
},
"archive": {
"titleArchive": "Archive \"{namespace}\"",
"titleUnarchive": "Un-Archive \"{namespace}\"",
"archiveText": "You won't be able to edit this namespace or create new lists until you un-archive it. This will also archive all lists in this namespace.",
"unarchiveText": "You will be able to create new lists or edit it.",
"success": "The namespace was successfully archived.",
"description": "If a namespace is archived, you cannot create new lists or edit it."
},
"delete": {
"title": "Delete \"{namespace}\"",
"text1": "Are you sure you want to delete this namespace and all of its contents?",
"text2": "This includes all lists and tasks and CANNOT BE UNDONE!",
"success": "The namespace was successfully deleted."
},
"edit": {
"title": "Edit \"{namespace}\"",
"success": "The namespace was successfully updated."
},
"share": {
"title": "Share \"{namespace}\""
},
"attributes": {
"title": "Namespace Title",
"titlePlaceholder": "The namespace title goes here…",
"description": "Description",
"descriptionPlaceholder": "The namespaces description goes here…",
"color": "Color",
"archived": "Is Archived",
"isArchived": "This namespace is archived"
},
"pseudo": {
"sharedLists": {
"title": "Shared Lists"
},
"favorites": {
"title": "Favorites"
},
"savedFilters": {
"title": "Filters"
}
}
},
"filters": {
"title": "Filters",
"attributes": {
"title": "Title",
"titlePlaceholder": "The saved filter title goes here…",
"description": "Description",
"descriptionPlaceholder": "The description goes here…",
"includeNulls": "Include Tasks which don't have a value set",
"requireAll": "Require all filters to be true for a task to show up",
"showDoneTasks": "Show Done Tasks",
"enablePriority": "Enable Filter By Priority",
"enablePercentDone": "Enable Filter By Percent Done",
"dueDateRange": "Due Date Range",
"startDateRange": "Start Date Range",
"endDateRange": "End Date Range",
"reminderRange": "Reminder Date Range"
},
"create": {
"title": "Create A Saved Filter",
"description": "A saved filter is a virtual list which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"action": "Create new saved filter"
},
"delete": {
"header": "Delete this saved filter",
"text": "Are you sure you want to delete this saved filter?",
"success": "The filter was deleted successfully."
},
"edit": {
"title": "Edit This Saved Filter",
"success": "The filter was saved successfully."
}
},
"migrate": {
"title": "Migrate from other services to Vikunja",
"titleService": "Import your data from {name} into Vikunja",
"import": "Import your data into Vikunja",
"description": "Click on the logo of one of the third-party services below to get started.",
"descriptionDo": "Vikunja will import all lists, tasks, notes, reminders and files you have access to.",
"authorize": "To authorize Vikunja to access your {name} Account, click the button below.",
"getStarted": "Get Started",
"inProgress": "Importing in progress…",
"alreadyMigrated1": "It looks like you've already imported your stuff from {name} at {date}.",
"alreadyMigrated2": "Importing again is possible, but might create duplicates. Are you sure?",
"confirm": "I am sure, please start migrating now!",
"importUpload": "To import data from {name} into Vikunja, click the button below to select a file.",
"upload": "Upload file"
},
"label": {
"title": "Labels",
"manage": "Manage labels",
"description": "Click on a label to edit it. You can edit all labels you created, you can use all labels which are associated with a task to whose list you have access.",
"newCTA": "You currently do not have any labels.",
"search": "Type to search for a label…",
"create": {
"header": "New label",
"title": "Create a new label",
"titleRequired": "Please specify a title.",
"success": "The label was successfully created."
},
"edit": {
"header": "Edit Label",
"forbidden": "You are not allowed to edit this label because you dont own it.",
"success": "The label was successfully updated."
},
"deleteSuccess": "The label was successfully deleted.",
"attributes": {
"title": "Title",
"titlePlaceholder": "The label title goes here…",
"description": "Description",
"descriptionPlaceholder": "Label description",
"color": "Color"
}
},
"sharing": {
"authenticating": "Authenticating…",
"passwordRequired": "This shared list requires a password. Please enter it below:",
"error": "An error occured.",
"invalidPassword": "The password is invalid."
},
"navigation": {
"overview": "Overview",
"upcoming": "Upcoming",
"settings": "Settings",
"imprint": "Imprint",
"privacy": "Privacy Policy"
},
"misc": {
"loading": "Loading…",
"save": "Save",
"delete": "Delete",
"confirm": "Confirm",
"cancel": "Cancel",
"refresh": "Refresh",
"disable": "Disable",
"copy": "Copy to clipboard",
"search": "Search",
"searchPlaceholder": "Type to search…",
"previous": "Previous",
"next": "Next",
"poweredBy": "Powered by Vikunja",
"info": "Info",
"create": "Create",
"doit": "Do it!",
"saving": "Saving…",
"saved": "Saved!",
"default": "Default",
"close": "Close",
"download": "Download",
"showMenu": "Show the menu",
"hideMenu": "Hide the menu"
},
"input": {
"resetColor": "Reset Color",
"datepicker": {
"today": "Today",
"tomorrow": "Tomorrow",
"nextMonday": "Next Monday",
"thisWeekend": "This Weekend",
"laterThisWeek": "Later This Week",
"nextWeek": "Next Week",
"chooseDate": "Choose a date"
},
"editor": {
"edit": "Edit",
"done": "Done",
"heading1": "Heading 1",
"heading2": "Heading 2",
"heading3": "Heading 3",
"headingSmaller": "Heading Smaller",
"headingBigger": "Heading Bigger",
"bold": "Bold",
"italic": "Italic",
"strikethrough": "Strikethrough",
"code": "Code",
"quote": "Quote",
"unorderedList": "Unordered List",
"orderedList": "Ordered List",
"cleanBlock": "Clean Block",
"link": "Link",
"image": "Image",
"table": "Table",
"horizontalRule": "Horizontal Rule",
"sideBySide": "Side By Side",
"guide": "Guide"
},
"multiselect": {
"createPlaceholder": "Create new",
"selectPlaceholder": "Click or press enter to select"
}
},
"task": {
"task": "Task",
"new": "Create a new task",
"delete": "Delete this task",
"createSuccess": "The task was successfully created.",
"addReminder": "Add a new reminder…",
"doneSuccess": "The task was successfully marked as done.",
"undoneSuccess": "The task was successfully un-marked as done.",
"openDetail": "Open task detail view",
"checklistTotal": "{checked} of {total} tasks",
"checklistAllDone": "{total} tasks",
"show": {
"titleCurrent": "Current Tasks",
"titleDates": "Tasks from {from} until {to}",
"noDates": "Show tasks without dates",
"current": "Current tasks",
"from": "Tasks from",
"until": "until",
"today": "Today",
"nextWeek": "Next Week",
"nextMonth": "Next Month",
"noTasks": "Nothing to do — Have a nice day!"
},
"detail": {
"chooseDueDate": "Click here to set a due date",
"chooseStartDate": "Click here to set a start date",
"chooseEndDate": "Click here to set an end date",
"move": "Move task to a different list",
"done": "Done!",
"undone": "Mark as undone",
"created": "Created {0} by {1}",
"updated": "Updated {0}",
"doneAt": "Done {0}",
"updateSuccess": "The task was saved successfully.",
"deleteSuccess": "The task has been deleted successfully.",
"belongsToList": "This task belongs to list '{list}'",
"due": "Due {at}",
"closePopup": "Close popup",
"delete": {
"header": "Delete this task",
"text1": "Are you sure you want to remove this task?",
"text2": "This will also remove all attachments, reminders and relations associated with this task and cannot be undone!"
},
"actions": {
"assign": "Assign this task to a user",
"label": "Add labels",
"priority": "Set Priority",
"dueDate": "Set Due Date",
"startDate": "Set a Start Date",
"endDate": "Set an End Date",
"reminders": "Set Reminders",
"repeatAfter": "Set a repeating interval",
"percentDone": "Set Percent Done",
"attachments": "Add attachments",
"relatedTasks": "Add task relations",
"moveList": "Move task",
"color": "Set task color",
"delete": "Delete task",
"favorite": "Save as favorite",
"unfavorite": "Remove from favorites"
}
},
"attributes": {
"assignees": "Assignees",
"color": "Color",
"created": "Created",
"createdBy": "Created By",
"description": "Description",
"done": "Done",
"dueDate": "Due Date",
"endDate": "End Date",
"labels": "Labels",
"percentDone": "% Done",
"priority": "Priority",
"relatedTasks": "Related Tasks",
"reminders": "Reminders",
"repeat": "Repeat",
"startDate": "Start Date",
"title": "Title",
"updated": "Updated"
},
"subscription": {
"subscribedThroughParent": "You can't unsubscribe here because you are subscribed to this {entity} through its {parent}.",
"subscribed": "You are currently subscribed to this {entity} and will receive notifications for changes.",
"notSubscribed": "You are not subscribed to this {entity} and won't receive notifications for changes.",
"subscribe": "Subscribe",
"unsubscribe": "Unsubscribe",
"subscribeSuccess": "You are now subscribed to this {entity}",
"unsubscribeSuccess": "You are now unsubscribed to this {entity}"
},
"attachment": {
"title": "Attachments",
"createdBy": "created {0} by {1}",
"downloadTooltip": "Download this attachment",
"upload": "Upload attachment",
"drop": "Drop files here to upload",
"delete": "Delete attachment",
"deleteTooltip": "Delete this attachment",
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
"deleteText2": "This cannot be undone!",
"copyUrl": "Copy URL",
"copyUrlTooltip": "Copy the url of this attachment for usage in text"
},
"comment": {
"title": "Comments",
"loading": "Loading comments…",
"edited": "edited {date}",
"creating": "Creating comment…",
"placeholder": "Add your comment…",
"comment": "Comment",
"delete": "Delete this comment",
"deleteText1": "Are you sure you want to delete this comment?",
"deleteText2": "This cannot be undone!",
"addedSuccess": "The comment was added successfully."
},
"deferDueDate": {
"title": "Defer due date",
"1day": "1 day",
"3days": "3 days",
"1week": "1 week"
},
"description": {
"placeholder": "Click here to enter a description…",
"empty": "No description available yet."
},
"assignee": {
"placeholder": "Type to assign a user…",
"selectPlaceholder": "Assign this user",
"assignSuccess": "The user has been assigned successfully.",
"unassignSuccess": "The user has been unassigned successfully."
},
"label": {
"placeholder": "Type to add a new label…",
"createPlaceholder": "Add this as new label",
"addSuccess": "The label has been added successfully.",
"createSuccess": "The label has been created successfully.",
"removeSuccess": "The label has been removed successfully.",
"addCreateSuccess": "The label has been created and added successfully."
},
"priority": {
"unset": "Unset",
"low": "Low",
"medium": "Medium",
"high": "high",
"urgent": "Urgent",
"doNow": "DO NOW"
},
"relation": {
"add": "Add a New Task Relation",
"new": "New Task Relation",
"searchPlaceholder": "Type search for a new task to add as related…",
"createPlaceholder": "Add this as new related task",
"differentList": "This task belongs to a different list.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
"deleteText1": "Are you sure you want to delete this task relation?",
"deleteText2": "This cannot be undone!",
"select": "Select a relation kind",
"kinds": {
"subtask": "Subtask | Subtasks",
"parenttask": "Parent Task | Parent Tasks",
"related": "Related Task | Related Tasks",
"duplicateof": "Duplicate Of | Duplicates Of",
"duplicates": "Duplicates | Duplicates",
"blocking": "Blocking | Blocking",
"blocked": "Blocked By | Blocked By",
"precedes": "Precedes | Precedes",
"follows": "Follows | Follows",
"copiedfrom": "Copied From | Copied From",
"copiedto": "Copied To | Copied To"
}
},
"repeat": {
"everyDay": "Every Day",
"everyWeek": "Every Week",
"everyMonth": "Every Month",
"mode": "Repeat mode",
"monthly": "Monthly",
"fromCurrentDate": "From Current Date",
"each": "Each",
"specifyAmount": "Specify an amount…",
"hours": "Hours",
"days": "Days",
"weeks": "Weeks",
"months": "Months",
"years": "Years"
},
"quickAddMagic": {
"hint": "You can use Quick Add Magic",
"what": "What?",
"title": "Quick Add Magic",
"intro": "When creating a task, you can use special keywords to directly add attributes to the newly created task. This allows to add commonly used attributes to tasks much faster.",
"multiple": "You can use this multiple times.",
"label1": "To add a label, simply prefix the name of the label with {prefix}.",
"label2": "Vikunja will first check if the label already exist and create it if not.",
"label3": "To use spaces, simply add a \" around the label name.",
"label4": "For example: {prefix}\"Label with spaces\".",
"priority1": "To set a task's priority, add a number 1-5, prefixed with a {prefix}.",
"priority2": "The higher the number, the higher the priority.",
"assignees": "To directly assign the task to a user, add their username prefixed with {prefix} to the task.",
"list1": "To set a list for the task to appear in, enter its name prefixed with {prefix}.",
"list2": "This will return an error if the list does not exist.",
"dateAndTime": "Date and time",
"date": "Any date will be used as the due date of the new task. You can use dates in any of these formats:",
"dateWeekday": "any weekday, will use the next date with that date",
"dateCurrentYear": "will use the current year",
"dateNth": "will use the {day}th of the current month",
"dateTime": "Combine any of the date formats with \"{time}\" (or {timePM}) to set a time."
}
},
"team": {
"title": "Teams",
"noTeams": "You are currently not part of any teams.",
"create": {
"title": "Create a new team",
"success": "The team was successfully created."
},
"edit": {
"title": "Edit Team \"{team}\"",
"members": "Team Members",
"search": "Type to search a user…",
"addUser": "Add to team",
"makeMember": "Make Member",
"makeAdmin": "Make Admin",
"success": "The team was successfully updated.",
"userAddedSuccess": "The team member was successfully added.",
"madeMember": "The team member was successfully made member.",
"madeAdmin": "The team member was successfully made admin.",
"delete": {
"header": "Delete the team",
"text1": "Are you sure you want to delete this team and all of its members?",
"text2": "All team members will lose access to lists and namespaces shared with this team. This CANNOT BE UNDONE!",
"success": "The team was successfully deleted."
},
"deleteUser": {
"header": "Remove a user from the team",
"text1": "Are you sure you want to remove this user from the team?",
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
"success": "The user was successfully deleted from the team."
}
},
"attributes": {
"name": "Team Name",
"namePlaceholder": "The team's name goes here…",
"nameRequired": "Please specify a name.",
"description": "Description",
"descriptionPlaceholder": "The teams description goes here…",
"admin": "Admin",
"member": "Member"
}
},
"keyboardShortcuts": {
"title": "Keyboard Shortcuts",
"allPages": "These shortcuts work on all pages.",
"currentPageOnly": "These shortcuts work only on the current page.",
"toggleMenu": "Toggle The Menu",
"quickSearch": "Open the search/quick action bar",
"task": {
"title": "Task Page",
"done": "Mark a task as done",
"assign": "Assign this task to a user",
"labels": "Add labels to this task",
"dueDate": "Change the due date of this task",
"attachment": "Add an attachment to this task",
"related": "Modify related tasks of this task"
}
},
"update": {
"available": "There is an update for Vikunja available!",
"do": "Update Now"
},
"menu": {
"edit": "Edit",
"archive": "Archive",
"duplicate": "Duplicate",
"delete": "Delete",
"unarchive": "Un-Archive",
"setBackground": "Set background",
"share": "Share",
"newList": "New list"
},
"apiConfig": {
"url": "Vikunja URL",
"urlPlaceholder": "eg. https://localhost:3456",
"change": "change",
"signInOn": "Sign in to your Vikunja account on {0}",
"error": "Could not find or use Vikunja installation at \"{domain}\".",
"success": "Using Vikunja installation at \"{domain}\"."
},
"loadingError": {
"failed": "Loading failed, please {0}. If the error persists, please {1}.",
"tryAgain": "try again",
"contact": "contact us"
},
"notification": {
"title": "Notifications",
"none": "You don't have any notifications. Have a nice day!",
"explainer": "Notifications will appear here when actions on namespaces, lists or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Commands",
"placeholder": "Type a command or search…",
"hint": "You can use # to only search for tasks, * to only search for lists and @ to only search for teams.",
"tasks": "Tasks",
"lists": "Lists",
"teams": "Teams",
"newList": "Enter the title of the new list…",
"newTask": "Enter the title of the new task…",
"newNamespace": "Enter the title of the new namespace…",
"newTeam": "Enter the name of the new team…",
"createTask": "Create a task in the current list ({title})",
"createList": "Create a list in the current namespace ({title})",
"cmds": {
"newTask": "New task",
"newList": "New list",
"newNamespace": "New namespace",
"newTeam": "New team"
}
},
"date": {
"locale": "en",
"altFormatLong": "j M Y H:i",
"altFormatShort": "j M Y"
},
"error": {
"error": "Error",
"success": "Success",
"0001": "You're not allowed to do that.",
"1001": "A user with this username already exists.",
"1002": "A user with this email address already exists.",
"1004": "No username and password specified.",
"1005": "The user does not exist.",
"1006": "Could not get the user id.",
"1008": "No password reset token provided.",
"1009": "Invalid password reset token.",
"1010": "Invalid email confirm token.",
"1011": "Wrong username or password.",
"1012": "Email address of the user not confirmed.",
"1013": "New password is empty.",
"1014": "Old password is empty.",
"1015": "Totp is already enabled for this user.",
"1016": "Totp is not enabled for this user.",
"1017": "The totp passcode is invalid.",
"1018": "The user avatar type setting is invalid.",
"2001": "ID cannot be empty or 0.",
"2002": "Some of the request data was invalid.",
"3001": "The list does not exist.",
"3004": "You need to have read permissions on that list to perform that action.",
"3005": "The list title cannot be empty.",
"3006": "The list share does not exist.",
"3007": "A list with this identifier already exists.",
"3008": "The list is archived and can therefore only be accessed read only. This is also true for all tasks associated with this list.",
"4001": "The list task text cannot be empty.",
"4002": "The list task does not exist.",
"4003": "All bulk editing tasks must belong to the same list.",
"4004": "Need at least one task when bulk editing tasks.",
"4005": "You do not have the right to see the task.",
"4006": "You can't set a parent task as the task itself.",
"4007": "You can't create a task relation with an invalid kind of relation.",
"4008": "You can't create a task relation which already exists.",
"4009": "The task relation does not exist.",
"4010": "Cannot relate a task with itself.",
"4011": "The task attachment does not exist.",
"4012": "The task attachment is too large.",
"4013": "The task sort param is invalid.",
"4014": "The task sort order is invalid.",
"4015": "The task comment does not exist.",
"4016": "Invalid task field.",
"4017": "Invalid task filter comparator.",
"4018": "Invalid task filter concatinator.",
"4019": "Invalid task filter value.",
"5001": "The namespace does not exist.",
"5003": "You do not have access to the specified namespace.",
"5006": "The namespace name cannot be empty.",
"5009": "You need to have namespace read access to perform that action.",
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
"6001": "The team name cannot be emtpy.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or list.",
"6005": "The user is already a member of that team.",
"6006": "Cannot delete the last team member.",
"6007": "The team does not have access to the list to perform that action.",
"7002": "The user already has access to that list.",
"7003": "You do not have access to that list.",
"8001": "This label already exists on that task.",
"8002": "The label does not exist.",
"8003": "You do not have access to this label.",
"9001": "The right is invalid.",
"10001": "The bucket does not exist.",
"10002": "The bucket does not belong to that list.",
"10003": "You cannot remove the last bucket on a list.",
"10004": "You cannot add the task to this bucket as it already exceeded the limit of tasks it can hold.",
"10005": "There can be only one done bucket per list.",
"11001": "The saved filter does not exist.",
"11002": "Saved filters are not available for link shares.",
"12001": "The subscription entity type is invalid.",
"12002": "You are already subscribed to the entity itself or a parent entity.",
"13001": "This link share requires a password for authentication, but none was provided.",
"13002": "The provided link share password was invalid."
},
"about": {
"title": "About",
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}

View File

@ -234,7 +234,7 @@
"list": {
"title": "Danh sách",
"add": "Thêm",
"addPlaceholder": "Thêm một công việc mới…",
"addPlaceholder": "Thêm việc cần làm…",
"empty": "Danh sách này đang trống trơn.",
"newTaskCta": "Thêm một công việc mới.",
"editTask": "Chỉnh sửa Công việc"
@ -449,7 +449,9 @@
"saved": "Đã lưu!",
"default": "Mặc định",
"close": "Đóng",
"download": "Tải về"
"download": "Tải về",
"showMenu": "Show the menu",
"hideMenu": "Hide the menu"
},
"input": {
"resetColor": "Đặt lại màu",
@ -459,7 +461,7 @@
"nextMonday": "Thứ Hai tới",
"thisWeekend": "Cuối tuần này",
"laterThisWeek": "Cuối tuần này",
"nextWeek": "Tuần kế tiếp",
"nextWeek": "Tuần ti",
"chooseDate": "Chọn một ngày"
},
"editor": {
@ -509,8 +511,8 @@
"from": "Công việc từ",
"until": "cho đến",
"today": "Hôm nay",
"nextWeek": "Tuần kế tiếp",
"nextMonth": "Tháng kế tiếp",
"nextWeek": "Tuần ti",
"nextMonth": "Tháng ti",
"noTasks": "Hôm nay thảnh thơi — Hãy tận hưởng ngày tuyệt vời!"
},
"detail": {
@ -792,7 +794,7 @@
"quickActions": {
"commands": "Các lệnh",
"placeholder": "Gõ một lệnh hoặc tìm kiếm…",
"hint": "Bạn có thể dùng # để chỉ tìm kiếm công việc, * để chỉ tìm kiếm danh sách và @ để chỉ tìm kiếm Team.",
"hint": "You can use # to only search for tasks, * to only search for lists and @ to only search for teams.",
"tasks": "Tác vụ",
"lists": "Danh sách",
"teams": "Team",

View File

@ -223,13 +223,12 @@ export default {
const labelAddsToWaitFor = parsedLabels.map(async labelTitle => {
let label = validateLabel(labels, labelTitle)
if (typeof label !== 'undefined') {
return label
if (typeof label === 'undefined') {
// label not found, create it
const labelModel = new LabelModel({title: labelTitle})
label = await dispatch('labels/createLabel', labelModel, {root: true})
}
// label not found, create it
const labelModel = new LabelModel({title: labelTitle})
await dispatch('labels/createLabel', labelModel, {root: true})
return addLabelToTask(task, label)
})

View File

@ -7,5 +7,4 @@
@import "form";
@import "link-share";
@import "loading";
@import "navigation";
@import "notification";

View File

@ -1,92 +0,0 @@
// FIXME: create <MenuButton> component
.menu-hide-button,
.menu-show-button {
display: none;
z-index: 31;
font-weight: bold;
font-size: 2rem;
color: $grey-400;
line-height: 1;
transition: all $transition;
&:hover,
&:focus {
height: 1rem;
color: $grey-600;
}
}
.menu-show-button {
height: .75rem;
width: 2rem;
@media screen and (max-width: $tablet) {
display: block;
margin-left: $hamburger-menu-icon-spacing;
}
// menu line icon and animationanimation // START
&::before,
&::after {
display: block;
content: '';
border-top: 3px solid $grey-400;
border-radius: $radius;
transition: all $transition;
}
&::before {
margin-bottom: .5rem;
}
&::after {
margin-top: .5rem;
}
&:hover,
&:focus {
&::before {
margin-bottom: .75rem;
}
&::after {
margin-top: .75rem;
}
}
// menu line animation // END
}
.menu-hide-button {
position: fixed;
@media screen and (max-width: $tablet) {
display: block;
top: $hamburger-menu-icon-spacing;
right: $hamburger-menu-icon-spacing;
}
&:hover,
&:focus {
color: $text;
}
}
.navbar-brand .menu-show-button {
display: block;
}
@media screen and (max-width: $tablet) {
.navbar.is-dark .navbar-brand > .navbar-item {
margin: 0 auto;
}
}
.menu-bottom-link {
width: 100%;
color: $grey-300;
text-align: center;
display: block;
margin: 1rem 0;
font-size: .8rem;
}

View File

@ -5,14 +5,6 @@
.notifications {
left: 0.5rem !important;
bottom: 1rem !important;
.notification-wrapper .notification {
border-radius: 0;
border-top-width: 0;
border-right-width: 0;
border-bottom-width: 0;
border-left-width: 0.4rem;
}
}
.message .message-body {

View File

@ -33,15 +33,6 @@ h6 {
font-weight: 400 !important;
}
.logo {
padding-left: 2rem !important;
img {
max-height: 3rem !important;
margin-right: 1rem;
}
}
// FIXME: create <ProgressBar> component. used in
// - attachments.vue
// - kanban-card.vue

1
src/types/vite-svg-loader.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference types="vite-svg-loader" />

View File

@ -5,30 +5,29 @@
variant="hint-modal"
>
<card
class="has-background-white has-no-shadow"
:title="$t('about.title')"
:has-close="true"
close-icon="times"
@close="$router.back()"
:padding="false"
>
<div class="p-4">
<p>
{{ $t('about.frontendVersion', {version: this.frontendVersion}) }}
</p>
<p>
{{ $t('about.apiVersion', {version: this.apiVersion}) }}
</p>
</div>
<footer class="modal-card-foot is-flex is-justify-content-flex-end">
<x-button
type="secondary"
@click.prevent.stop="$router.back()"
>
{{ $t('misc.close') }}
</x-button>
</footer>
</card>
class="has-no-shadow"
:title="$t('about.title')"
:has-close="true"
@close="$router.back()"
:padding="false"
>
<div class="p-4">
<p>
{{ $t('about.frontendVersion', {version: this.frontendVersion}) }}
</p>
<p>
{{ $t('about.apiVersion', {version: this.apiVersion}) }}
</p>
</div>
<footer class="modal-card-foot is-flex is-justify-content-flex-end">
<x-button
type="secondary"
@click.prevent.stop="$router.back()"
>
{{ $t('misc.close') }}
</x-button>
</footer>
</card>
</modal>
</template>

View File

@ -51,7 +51,7 @@
/>
</div>
</div>
<ShowTasks :show-all="true" v-if="hasLists" :key="showTasksKey"/>
<ShowTasks class="mt-4" :show-all="true" v-if="hasLists" :key="showTasksKey"/>
</div>
</template>

View File

@ -3,7 +3,7 @@
@close="$router.back()"
variant="hint-modal"
>
<card class="has-background-white has-no-shadow" :title="$t('filters.create.title')">
<card class="has-no-shadow" :title="$t('filters.create.title')">
<p>
{{ $t('filters.create.description') }}
</p>

View File

@ -116,13 +116,14 @@
</template>
</draggable>
</div>
<card
<edit-task
v-if="isTaskEdit"
class="taskedit mt-0" :title="$t('list.list.editTask')" :has-close="true"
class="taskedit mt-0"
:title="$t('list.list.editTask')"
@close="() => isTaskEdit = false"
:shadow="false">
<edit-task :task="taskEditTask"/>
</card>
:shadow="false"
:task="taskEditTask"
/>
</div>
<Pagination
@ -344,6 +345,7 @@ export default {
width: 33%;
margin-right: 1rem;
margin-left: .5rem;
min-height: calc(100% - 1rem);
@media screen and (max-width: $tablet) {
width: 100%;

View File

@ -41,7 +41,7 @@
<div class="progress-dots">
<span v-for="i in progressDotsCount" :key="i" />
</div>
<img alt="Vikunja" :src="logoUrl" />
<Logo alt="Vikunja" />
</div>
<p>{{ $t('migrate.inProgress') }}</p>
</div>
@ -70,14 +70,17 @@
<script>
import AbstractMigrationService from '@/services/migrator/abstractMigration'
import AbstractMigrationFileService from '@/services/migrator/abstractMigrationFile'
import {MIGRATORS} from './migrators'
import Logo from '@/assets/logo.svg?component'
import logoUrl from '@/assets/logo.svg'
import {MIGRATORS} from './migrators'
const PROGRESS_DOTS_COUNT = 8
export default {
name: 'MigrateService',
components: { Logo },
data() {
return {
progressDotsCount: PROGRESS_DOTS_COUNT,
@ -87,7 +90,6 @@ export default {
message: '',
migratorAuthCode: '',
migrationService: null,
logoUrl,
}
},

View File

@ -1,8 +1,8 @@
import wunderlistIcon from './icons/wunderlist.jpg'
import todoistIcon from './icons/todoist.svg'
import trelloIcon from './icons/trello.svg'
import microsoftTodoIcon from './icons/microsoft-todo.svg'
import vikunjaFileIcon from './icons/vikunja-file.png'
import todoistIcon from './icons/todoist.svg?url'
import trelloIcon from './icons/trello.svg?url'
import microsoftTodoIcon from './icons/microsoft-todo.svg?url'
import vikunjaFileIcon from './icons/vikunja-file.png?url'
export interface Migrator {
id: string

View File

@ -38,7 +38,7 @@
</div>
<template v-if="!loading && (!tasks || tasks.length === 0) && showNothingToDo">
<h3 class="nothing">{{ $t('task.show.noTasks') }}</h3>
<img alt="" :src="llamaCoolUrl" />
<LlamaCool class="llama-cool" />
</template>
<div :class="{ 'is-loading': loading}" class="spinner"></div>
@ -64,7 +64,7 @@ import 'flatpickr/dist/flatpickr.css'
import Fancycheckbox from '../../components/input/fancycheckbox'
import {LOADING, LOADING_MODULE} from '../../store/mutation-types'
import llamaCoolUrl from '@/assets/llama-cool.svg'
import LlamaCool from '@/assets/llama-cool.svg?component'
export default {
name: 'ShowTasks',
@ -72,6 +72,7 @@ export default {
Fancycheckbox,
SingleTaskInList,
flatPickr,
LlamaCool,
},
data() {
return {
@ -83,7 +84,6 @@ export default {
cEndDate: null,
showNothingToDo: false,
llamaCoolUrl,
}
},
props: {
@ -256,28 +256,22 @@ export default {
</script>
<style lang="scss" scoped>
.show-tasks {
h3 {
text-align: left;
h3 {
text-align: left;
&.nothing {
text-align: center;
margin-top: 3rem;
}
:deep(.input) {
width: 190px;
vertical-align: middle;
margin: .5rem 0;
}
&.nothing {
text-align: center;
margin-top: 3rem;
}
img {
margin-top: 2rem;
}
.user img {
margin: 0;
:deep(.input) {
width: 190px;
vertical-align: middle;
margin: .5rem 0;
}
}
.llama-cool {
margin-top: 2rem;
}
</style>

View File

@ -4,6 +4,7 @@ import legacyFn from '@vitejs/plugin-legacy'
const {VitePWA} = require('vite-plugin-pwa')
const path = require('path')
const {visualizer} = require('rollup-plugin-visualizer')
import svgLoader from 'vite-svg-loader'
const pathSrc = path.resolve(__dirname, './src')
@ -42,6 +43,11 @@ export default defineConfig({
},
}),
legacy,
svgLoader({
// Since the svgs are already manually optimized via https://jakearchibald.github.io/svgomg/
// we don't need to optimize them again.
svgo: false,
}),
VitePWA({
srcDir: 'src',
filename: 'sw.js',

7320
yarn.lock

File diff suppressed because it is too large Load Diff