feature(3331): made board, overview, stack and search result cards width behave more dynamic
Signed-off-by: Luutzen Dijkstra <luutzen.dijkstra@gmail.com>
This commit is contained in:
committed by
Luka Trovic
parent
6ace1867e1
commit
3115363c28
@@ -276,18 +276,15 @@ export default {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: calc(100vh - 50px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.board {
|
||||
padding-left: $board-spacing;
|
||||
position: relative;
|
||||
max-height: calc(100% - var(--default-clickable-area));
|
||||
overflow: hidden;
|
||||
overflow-x: auto;
|
||||
overflow: auto;
|
||||
flex-grow: 1;
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -297,11 +294,14 @@ export default {
|
||||
.smooth-dnd-container.horizontal {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
height: 100%;
|
||||
gap: $board-gap;
|
||||
padding: 0 $board-gap;
|
||||
|
||||
&:deep(.stack-draggable-wrapper.smooth-dnd-draggable-wrapper) {
|
||||
display: flex;
|
||||
height: auto;
|
||||
flex: 0 1 $card-max-width;
|
||||
min-width: $card-min-width;
|
||||
|
||||
.stack {
|
||||
display: flex;
|
||||
@@ -309,16 +309,10 @@ export default {
|
||||
position: relative;
|
||||
|
||||
.smooth-dnd-container.vertical {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// Margin left instead of padidng to avoid jumps on dropping a card
|
||||
margin-left: $stack-spacing;
|
||||
padding-right: $stack-spacing;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-top: 15px;
|
||||
margin-top: -10px;
|
||||
gap: $stack-gap;
|
||||
padding: 5px 0 $stack-gap;
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
|
||||
@@ -365,34 +365,32 @@ export default {
|
||||
@import './../../css/variables';
|
||||
|
||||
.stack {
|
||||
width: $stack-width + $stack-spacing * 3;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.stack__header {
|
||||
display: flex;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
height: var(--default-clickable-area);
|
||||
z-index: 100;
|
||||
padding-left: $card-spacing;
|
||||
padding-right: $card-spacing;
|
||||
margin: 6px;
|
||||
margin-top: 0;
|
||||
cursor: grab;
|
||||
background-color: var(--color-main-background);
|
||||
|
||||
// Smooth fade out of the cards at the top
|
||||
&:before {
|
||||
content: ' ';
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: calc(100% - 16px);
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
top: 30px;
|
||||
left: 0px;
|
||||
z-index: 99;
|
||||
transition: top var(--animation-slow);
|
||||
|
||||
background-image: linear-gradient(180deg, var(--color-main-background) 3px, rgba(255, 255, 255, 0) 100%);
|
||||
|
||||
body.theme--dark & {
|
||||
background-image: linear-gradient(180deg, var(--color-main-background) 3px, rgba(0, 0, 0, 0) 100%);
|
||||
}
|
||||
@@ -404,8 +402,10 @@ export default {
|
||||
}
|
||||
|
||||
h3, form {
|
||||
flex-grow: 1;
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: inherit;
|
||||
margin: 0;
|
||||
|
||||
@@ -418,9 +418,8 @@ export default {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: calc($stack-width - 60px);
|
||||
border-radius: 3px;
|
||||
padding: 4px 4px;
|
||||
padding: $card-padding;
|
||||
font-size: var(--default-font-size);
|
||||
|
||||
&:focus-visible {
|
||||
@@ -430,7 +429,6 @@ export default {
|
||||
}
|
||||
|
||||
form {
|
||||
margin: -4px;
|
||||
input {
|
||||
font-weight: bold;
|
||||
padding: 0 6px;
|
||||
@@ -459,8 +457,6 @@ export default {
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
margin-left: $stack-spacing;
|
||||
margin-right: $stack-spacing;
|
||||
width: 100%;
|
||||
border: 2px solid var(--color-border-maxcontrast);
|
||||
border-radius: var(--border-radius-large);
|
||||
@@ -481,7 +477,6 @@ export default {
|
||||
input {
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +101,8 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './../../css/variables';
|
||||
|
||||
.badges {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
@@ -111,6 +113,7 @@ export default {
|
||||
.icon-badge {
|
||||
color: var(--color-text-maxcontrast);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 2px;
|
||||
|
||||
span,
|
||||
@@ -125,6 +128,7 @@ export default {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: 3px;
|
||||
height: var(--default-clickable-area);
|
||||
}
|
||||
|
||||
.badges .icon.due {
|
||||
|
||||
@@ -77,9 +77,7 @@ export default {
|
||||
.card-cover {
|
||||
height: 90px;
|
||||
display: flex;
|
||||
margin-top: -4px;
|
||||
margin-left: -4px;
|
||||
margin-right: -4px;
|
||||
margin: $card-image-margin $card-image-margin 0;
|
||||
|
||||
.image-wrapper {
|
||||
flex: 1;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<template>
|
||||
<AttachmentDragAndDrop v-if="card" :card-id="card.id" class="drop-upload--card">
|
||||
<div :ref="`card${card.id}`"
|
||||
:class="{'compact': compactMode, 'current-card': currentCard, 'has-labels': card.labels && card.labels.length > 0, 'card__editable': canEdit, 'card__archived': card.archived, 'card__highlight': highlight}"
|
||||
:class="{'compact': compactMode, 'current-card': currentCard, 'no-labels': !hasLabels, 'card__editable': canEdit, 'card__archived': card.archived, 'card__highlight': highlight}"
|
||||
tag="div"
|
||||
:tabindex="0"
|
||||
class="card"
|
||||
@@ -331,12 +331,12 @@ export default {
|
||||
border-radius: var(--border-radius-large);
|
||||
font-size: 100%;
|
||||
background-color: var(--color-main-background);
|
||||
margin-bottom: $card-spacing;
|
||||
padding: var(--default-grid-baseline) $card-padding;
|
||||
padding: $card-padding;
|
||||
border: 2px solid var(--color-border-dark);
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $card-gap;
|
||||
|
||||
&:deep(*) {
|
||||
cursor: pointer;
|
||||
@@ -359,12 +359,10 @@ export default {
|
||||
h4 {
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: var(--default-grid-baseline);
|
||||
flex-grow: 1;
|
||||
font-size: 100%;
|
||||
overflow: hidden;
|
||||
word-wrap: break-word;
|
||||
padding-left: 4px;
|
||||
align-self: center;
|
||||
|
||||
:deep(a) {
|
||||
@@ -374,9 +372,6 @@ export default {
|
||||
&.editable {
|
||||
span {
|
||||
cursor: text;
|
||||
padding-right: 8px;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
|
||||
&:focus, &:focus-visible {
|
||||
outline: none;
|
||||
@@ -385,6 +380,7 @@ export default {
|
||||
|
||||
&:focus-within {
|
||||
outline: 2px solid var(--color-border-dark);
|
||||
outline-offset: 4px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
@@ -427,8 +423,6 @@ export default {
|
||||
.card-labels {
|
||||
display: flex;
|
||||
align-items: end;
|
||||
padding-left: var(--default-grid-baseline);
|
||||
padding-top: var(--default-grid-baseline);
|
||||
|
||||
.labels {
|
||||
flex-wrap: wrap;
|
||||
@@ -444,7 +438,7 @@ export default {
|
||||
|
||||
.card-related {
|
||||
display: flex;
|
||||
padding: 12px;
|
||||
padding: 4px;
|
||||
padding-bottom: 0px;
|
||||
color: var(--color-text-maxcontrast);
|
||||
|
||||
@@ -469,8 +463,8 @@ export default {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
}
|
||||
&.has-labels {
|
||||
padding-bottom: $card-padding;
|
||||
&.no-labels {
|
||||
padding-bottom: var(--default-grid-baseline);
|
||||
}
|
||||
.labels {
|
||||
height: 6px;
|
||||
|
||||
@@ -14,45 +14,18 @@
|
||||
</div>
|
||||
|
||||
<div v-else-if="isValidFilter" class="overview">
|
||||
<div class="dashboard-column">
|
||||
<h3>{{ t('deck', 'Overdue') }}</h3>
|
||||
<div v-for="card in sortCards('overdue')" :key="card.id">
|
||||
<CardItem :id="card.id" />
|
||||
<div v-for="columnProps in columnPropsList" class="dashboard-column" :key="columnProps.title">
|
||||
<div class="dashboard-column__header">
|
||||
<h3 class="dashboard-column__header-title">{{ t('deck', columnProps.title) }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-column">
|
||||
<h3>{{ t('deck', 'Today') }}</h3>
|
||||
<div v-for="card in sortCards('today')" :key="card.id">
|
||||
<CardItem :id="card.id" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-column">
|
||||
<h3>{{ t('deck', 'Tomorrow') }}</h3>
|
||||
<div v-for="card in sortCards('tomorrow')" :key="card.id">
|
||||
<CardItem :id="card.id" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-column">
|
||||
<h3>{{ t('deck', 'Next 7 days') }}</h3>
|
||||
<div v-for="card in sortCards('nextSevenDays')" :key="card.id">
|
||||
<CardItem :id="card.id" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-column">
|
||||
<h3>{{ t('deck', 'Later') }}</h3>
|
||||
<div v-for="card in sortCards('later')" :key="card.id">
|
||||
<CardItem :id="card.id" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-column">
|
||||
<h3>{{ t('deck', 'No due') }}</h3>
|
||||
<div v-for="card in assignedCardsDashboard.nodue" :key="card.id">
|
||||
<CardItem :id="card.id" />
|
||||
<div class="dashboard-column__list">
|
||||
<template v-if="columnProps.sort === false">
|
||||
<CardItem :id="card.id" v-for="card in filterCards(columnProps.filter)" :key="card.id" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<CardItem :id="card.id" v-for="card in sortCards(filterCards(columnProps.filter))"
|
||||
:key="card.id" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -73,6 +46,34 @@ const SUPPORTED_FILTERS = [
|
||||
FILTER_UPCOMING,
|
||||
]
|
||||
|
||||
const COLUMN_PROPS_LIST = [
|
||||
{
|
||||
title: 'Overdue',
|
||||
filter: 'overdue',
|
||||
},
|
||||
{
|
||||
title: 'Today',
|
||||
filter: 'today',
|
||||
},
|
||||
{
|
||||
title: 'Tomorrow',
|
||||
filter: 'tomorrow',
|
||||
},
|
||||
{
|
||||
title: 'Next 7 days',
|
||||
filter: 'nextSevenDays',
|
||||
},
|
||||
{
|
||||
title: 'Later',
|
||||
filter: 'later',
|
||||
},
|
||||
{
|
||||
title: 'No due',
|
||||
filter: 'nodue',
|
||||
sort: false,
|
||||
},
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'Overview',
|
||||
components: {
|
||||
@@ -89,6 +90,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
columnPropsList: COLUMN_PROPS_LIST,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -125,16 +127,16 @@ export default {
|
||||
}
|
||||
this.loading = false
|
||||
},
|
||||
sortCards(when) {
|
||||
const cards = this.assignedCardsDashboard[when]
|
||||
|
||||
filterCards(when) {
|
||||
return this.assignedCardsDashboard[when];
|
||||
},
|
||||
sortCards(cards) {
|
||||
if (!cards) {
|
||||
return null
|
||||
} else {
|
||||
return cards.toSorted((current, next) => {
|
||||
const currentDueDate = new Date(current.duedate)
|
||||
const nextDueDate = new Date(next.duedate)
|
||||
|
||||
return currentDueDate - nextDueDate
|
||||
})
|
||||
}
|
||||
@@ -151,38 +153,71 @@ export default {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: calc(100vh - 50px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.overview {
|
||||
position: relative;
|
||||
height: calc(100% - var(--default-clickable-area));
|
||||
overflow-x: scroll;
|
||||
overflow: auto;
|
||||
flex-grow: 1;
|
||||
scrollbar-gutter: stable;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
padding-left: $board-spacing;
|
||||
padding-right: $board-spacing;
|
||||
gap: $board-gap;
|
||||
padding: 0 $board-gap;
|
||||
|
||||
.dashboard-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: $stack-width;
|
||||
width: $stack-width;
|
||||
margin-left: $stack-spacing;
|
||||
margin-right: $stack-spacing;
|
||||
flex: 0 1 $card-max-width;
|
||||
min-width: $card-min-width;
|
||||
|
||||
h3 {
|
||||
font-size: var(--default-font-size);
|
||||
margin: -6px;
|
||||
margin-bottom: 12px;
|
||||
padding: 6px 13px;
|
||||
.dashboard-column__header {
|
||||
display: flex;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
height: var(--default-clickable-area);
|
||||
z-index: 100;
|
||||
margin-top: 0;
|
||||
background-color: var(--color-main-background);
|
||||
border: 1px solid var(--color-main-background);
|
||||
|
||||
// Smooth fade out of the cards at the top
|
||||
&:before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
top: 30px;
|
||||
left: 0px;
|
||||
z-index: 99;
|
||||
transition: top var(--animation-slow);
|
||||
background-image: linear-gradient(180deg, var(--color-main-background) 3px, rgba(255, 255, 255, 0) 100%);
|
||||
|
||||
body.theme--dark & {
|
||||
background-image: linear-gradient(180deg, var(--color-main-background) 3px, rgba(0, 0, 0, 0) 100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-column__header-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: var(--default-clickable-area);
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding: 4px;
|
||||
font-size: var(--default-font-size);
|
||||
}
|
||||
|
||||
.dashboard-column__list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $stack-gap;
|
||||
padding: 5px 0 $stack-gap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,20 +4,21 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div v-if="searchQuery!==''" class="global-search">
|
||||
<h2>
|
||||
<NcRichText :text="t('deck', 'Search for {searchQuery} in all boards')" :arguments="queryStringArgs" />
|
||||
<div v-if="loading" class="icon-loading-small" />
|
||||
</h2>
|
||||
<NcActions>
|
||||
<NcActionButton icon="icon-close" @click="$store.commit('setSearchQuery', '')" />
|
||||
</NcActions>
|
||||
<section v-if="searchQuery!==''" class="global-search">
|
||||
<header class="search-header">
|
||||
<h2>
|
||||
<NcRichText
|
||||
:text="t('deck', 'Search for {searchQuery} in all boards')"
|
||||
:arguments="queryStringArgs" />
|
||||
<span v-if="loading" class="icon-loading-small" />
|
||||
</h2>
|
||||
<NcActions>
|
||||
<NcActionButton icon="icon-close" @click="$store.commit('setSearchQuery', '')" />
|
||||
</NcActions>
|
||||
</header>
|
||||
<div class="search-wrapper">
|
||||
<div v-if="loading || filteredResults.length > 0" class="search-results">
|
||||
<CardItem v-for="card in filteredResults"
|
||||
:id="card.id"
|
||||
:key="card.id"
|
||||
:standalone="true" />
|
||||
<template v-if="loading || filteredResults.length > 0">
|
||||
<CardItem v-for="card in filteredResults" :id="card.id" :key="card.id" :standalone="true" />
|
||||
<Placeholder v-if="loading" />
|
||||
<InfiniteLoading :identifier="searchQuery" @infinite="infiniteHandler">
|
||||
<div slot="spinner" />
|
||||
@@ -26,12 +27,12 @@
|
||||
{{ t('deck', 'No results found') }}
|
||||
</div>
|
||||
</InfiniteLoading>
|
||||
</div>
|
||||
<div v-else>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p>{{ t('deck', 'No results found') }}</p>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -159,7 +160,7 @@ export default {
|
||||
|
||||
.global-search {
|
||||
width: 100%;
|
||||
padding: $board-spacing + $stack-spacing;
|
||||
padding: $board-gap;
|
||||
padding-bottom: 0;
|
||||
overflow: hidden;
|
||||
min-height: 35vh;
|
||||
@@ -169,17 +170,24 @@ export default {
|
||||
border-top: 1px solid var(--color-border);
|
||||
z-index: 1010;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.action-item.icon-close {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
.search-wrapper {
|
||||
overflow: scroll;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
|
||||
.search-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
padding: var(--default-grid-baseline) var(--default-grid-baseline) $board-gap;
|
||||
}
|
||||
|
||||
h2 > div {
|
||||
@@ -189,23 +197,25 @@ export default {
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
h2:deep(span) {
|
||||
background-color: var(--color-background-dark);
|
||||
padding: 3px;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.search-results {
|
||||
.search-wrapper {
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: $stack-gap;
|
||||
|
||||
& > div {
|
||||
& > .drop-upload--card {
|
||||
flex-grow: 0;
|
||||
flex: 0 1 $card-max-width;
|
||||
min-width: $card-min-width;
|
||||
}
|
||||
}
|
||||
&:deep(.card) {
|
||||
width: $stack-width;
|
||||
margin-right: $stack-spacing;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -62,14 +62,13 @@ export default {
|
||||
$clickable-area: var(--default-clickable-area);
|
||||
|
||||
.card--placeholder {
|
||||
width: $stack-width;
|
||||
margin-right: $stack-spacing;
|
||||
min-width: $card-min-width;
|
||||
max-width: $card-min-width;
|
||||
padding: $card-padding;
|
||||
transition: box-shadow 0.1s ease-in-out;
|
||||
box-shadow: 0 0 2px 0 var(--color-box-shadow);
|
||||
border-radius: var(--border-radius-large);
|
||||
font-size: 100%;
|
||||
margin-bottom: $card-spacing;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
$card-spacing: 8px;
|
||||
$card-padding: 4px;
|
||||
$stack-spacing: 12px;
|
||||
$stack-width: 280px;
|
||||
$board-spacing: 16px;
|
||||
$card-min-width: 216px;
|
||||
$card-max-width: 300px;
|
||||
$card-padding: calc(var(--default-grid-baseline) * 2) calc(var(--default-grid-baseline) * 2) var(--default-grid-baseline);
|
||||
$card-gap: calc(var(--default-grid-baseline) * 3);
|
||||
$card-image-margin: calc(var(--default-grid-baseline) * -1);
|
||||
$stack-gap: calc(var(--default-grid-baseline) * 3);
|
||||
$board-gap: calc(var(--default-grid-baseline) * 4);
|
||||
|
||||
Reference in New Issue
Block a user