add: (wip) new filtering layout
DropDown component, ToggleButton component,
This commit is contained in:
parent
38cd37cf74
commit
3fd26b4e66
11 changed files with 203 additions and 42 deletions
2
app/assets/icons/sort_asc.svg
Normal file
2
app/assets/icons/sort_asc.svg
Normal file
|
@ -0,0 +1,2 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="m6.29 14.29l-.29.3V7a1 1 0 0 0-2 0v7.59l-.29-.3a1 1 0 0 0-1.42 1.42l2 2a1 1 0 0 0 .33.21a.94.94 0 0 0 .76 0a1 1 0 0 0 .33-.21l2-2a1 1 0 0 0-1.42-1.42M11 8h10a1 1 0 0 0 0-2H11a1 1 1 0 0 0 2m10 3H11a1 1 0 0 0 0 2h10a1 1 0 0 0 0-2m0 5H11a1 1 0 0 0 0 2h10a1 1 0 0 0 0-2"/></svg>
|
After Width: | Height: | Size: 391 B |
2
app/assets/icons/sort_desc.svg
Normal file
2
app/assets/icons/sort_desc.svg
Normal file
|
@ -0,0 +1,2 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="m6.29 14.29l-.29.3V7a1 1 0 0 0-2 0v7.59l-.29-.3a1 1 0 0 0-1.42 1.42l2 2a1 1 0 0 0 .33.21a.94.94 0 0 0 .76 0a1 1 0 0 0 .33-.21l2-2a1 1 0 0 0-1.42-1.42M11 8h10a1 1 0 0 0 0-2H11a1 1 1 0 0 0 2m10 3H11a1 1 0 0 0 0 2h10a1 1 0 0 0 0-2m0 5H11a1 1 0 0 0 0 2h10a1 1 0 0 0 0-2"/></svg>
|
After Width: | Height: | Size: 391 B |
64
app/assets/styles/form/dropdown.css
Normal file
64
app/assets/styles/form/dropdown.css
Normal file
|
@ -0,0 +1,64 @@
|
|||
.DropDown {
|
||||
--border-color: var(--color-light);
|
||||
--label-color: var(--color-darkest);
|
||||
--background-color: var(--color-lightest);
|
||||
--arrow-color: var(--color-main-dark);
|
||||
|
||||
position: relative;
|
||||
|
||||
&.active {
|
||||
--background-color: var(--color-main-dark);
|
||||
--label-color: var(--color-lightest);
|
||||
--arrow-color: var(--color-lightest);
|
||||
--border-color: var(--color-main-dark);
|
||||
|
||||
& ul {
|
||||
scale: 1 1;
|
||||
}
|
||||
}
|
||||
|
||||
& button {
|
||||
all: unset;
|
||||
cursor: pointer;
|
||||
color: var(--label-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-default);
|
||||
background: var(--background-color);
|
||||
padding: .5rem 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: .5rem;
|
||||
transition: var(--transition-default);
|
||||
width: 70px;
|
||||
|
||||
& .icon {
|
||||
color: var(--arrow-color);
|
||||
}
|
||||
}
|
||||
|
||||
& ul {
|
||||
position: absolute;
|
||||
list-style: none;
|
||||
transform-origin: top;
|
||||
scale: 1 0;
|
||||
transition: var(--transition-default);
|
||||
color: var(--color-darkest);
|
||||
border: 1px solid var(--color-main-dark);
|
||||
border-radius: var(--radius-default);
|
||||
background: var(--color-lightest);
|
||||
box-shadow: var(--box-shadow-z2);
|
||||
width: 100%;
|
||||
z-index: 2000;
|
||||
top: 0;
|
||||
|
||||
& li {
|
||||
padding: .5rem 1rem;
|
||||
|
||||
&.selected {
|
||||
background: var(--color-main-dark);
|
||||
color: var(--color-lightest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
14
app/assets/styles/form/togglebutton.css
Normal file
14
app/assets/styles/form/togglebutton.css
Normal file
|
@ -0,0 +1,14 @@
|
|||
.ToggleButton {
|
||||
all: unset;
|
||||
color: var(--color-lightest);
|
||||
background: var(--color-main-dark);
|
||||
padding: .5rem .8rem;
|
||||
border-radius: var(--radius-default);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
& .icon {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
|
@ -16,24 +16,9 @@
|
|||
.filter-bar {
|
||||
background: var(--color-lightest);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
justify-content: flex-end;
|
||||
gap: 1rem;
|
||||
padding: var(--padding-default);
|
||||
|
||||
& > button {
|
||||
all: unset;
|
||||
cursor: pointer;
|
||||
color: var(--color-main-darkest);
|
||||
font-weight: bolder;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
|
||||
&.active {
|
||||
color: var(--color-main-darkest);
|
||||
}
|
||||
|
||||
&:not(.active) {
|
||||
opacity: .5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
position: relative;
|
||||
width: 100%;
|
||||
color: var(--color-darkest);
|
||||
border-bottom: 1px solid var(--color-light);
|
||||
border-bottom: 1px dashed var(--color-light);
|
||||
|
||||
.bottom {
|
||||
position: absolute;
|
||||
|
|
45
app/components/Pp/Form/DropDown.vue
Normal file
45
app/components/Pp/Form/DropDown.vue
Normal file
|
@ -0,0 +1,45 @@
|
|||
<template>
|
||||
<div
|
||||
class="DropDown"
|
||||
:class="{ active }"
|
||||
ref="dropdown"
|
||||
>
|
||||
<button @click="active = !active">
|
||||
<span>{{ current.label }}</span>
|
||||
<Icon class="icon" name="uil:angle-down" mode="svg" />
|
||||
</button>
|
||||
<ul>
|
||||
<li
|
||||
v-for="element in elements"
|
||||
@click="click(element)"
|
||||
:class="{ selected : element.value === current.value }"
|
||||
>
|
||||
{{ element.label }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { DropDownElement } from '../../../../shared/DropDown'
|
||||
|
||||
type Props = {
|
||||
elements : DropDownElement[]
|
||||
current : DropDownElement
|
||||
}
|
||||
|
||||
const { elements = [] } = defineProps<Props>()
|
||||
const emit = defineEmits(['click'])
|
||||
|
||||
const active = ref(false)
|
||||
const dropdown = useTemplateRef<HTMLDivElement>('dropdown')
|
||||
|
||||
const click = (element : DropDownElement) => {
|
||||
emit('click', element)
|
||||
active.value = false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
onClickOutside(dropdown, () => active.value = false)
|
||||
})
|
||||
</script>
|
21
app/components/Pp/Form/ToggleButton.vue
Normal file
21
app/components/Pp/Form/ToggleButton.vue
Normal file
|
@ -0,0 +1,21 @@
|
|||
<template>
|
||||
<button class="ToggleButton" @click="click">
|
||||
<Icon class="icon" :name="icons[current]!" mode="svg" />
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
type Props = {
|
||||
icons : string[]
|
||||
current: number
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
const emit = defineEmits(['click'])
|
||||
|
||||
const click = () => emit('click')
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -17,9 +17,16 @@
|
|||
<h1>Mit ProPapier Preise vergleichen und sparen</h1>
|
||||
</div>
|
||||
<aside class="filter-bar">
|
||||
<button v-for="(button, index) in filterButtons" @click="() => sort(index)" :class="{ 'active': button.active }">
|
||||
{{ button.label }}
|
||||
</button>
|
||||
<PpFormDropDown
|
||||
:elements="sortElements"
|
||||
:current="currentSortElement!"
|
||||
@click="setSortElement"
|
||||
/>
|
||||
<PpFormToggleButton
|
||||
:icons="['uil:sort-amount-up', 'uil:sort-amount-down']"
|
||||
:current="currentSortDirection"
|
||||
@click="countSortDirection"
|
||||
/>
|
||||
</aside>
|
||||
<div class="flex-col" role="list" v-if="cards.length">
|
||||
<PpPriceCard
|
||||
|
@ -52,15 +59,37 @@
|
|||
import type { Card } from '../../shared/Card'
|
||||
import type { Button } from '../../shared/ButtonGroup'
|
||||
import { PpPriceCardDialog, PpDeleteDialog, PpPriceCard } from '#components'
|
||||
import type { DropDownElement } from '../../shared/DropDown'
|
||||
|
||||
const cards = useLocalStorage<Card[]>('cards', [])
|
||||
const currentSort = useLocalStorage<number>('sort', 0)
|
||||
const currentSortDirection = useLocalStorage<number>('sortDirection', 0)
|
||||
const currentCard = ref<Card>()
|
||||
const currentCardIndex = ref<number>(-1)
|
||||
const modal = useTemplateRef<typeof PpPriceCardDialog>('modal')
|
||||
const deleteModal = useTemplateRef<typeof PpDeleteDialog>('deleteModal')
|
||||
const priceCards = useTemplateRef<(typeof PpPriceCard)[]>('priceCard')
|
||||
|
||||
const sortElements : DropDownElement[] = [
|
||||
{
|
||||
label: 'Rollen',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: 'Blatt',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: 'Lagen',
|
||||
value: 2,
|
||||
}
|
||||
]
|
||||
const currentSortElement = ref<DropDownElement>(sortElements[0]!)
|
||||
|
||||
const setSortElement = (element : DropDownElement) => {
|
||||
sort(element.value as number)
|
||||
}
|
||||
|
||||
const createCard = (uuid : string) : Card => ({
|
||||
uuid,
|
||||
name: '',
|
||||
|
@ -70,7 +99,6 @@ const createCard = (uuid : string) : Card => ({
|
|||
layers: '',
|
||||
})
|
||||
|
||||
|
||||
const addCard = (card : Card) => {
|
||||
cards.value.unshift({ ...card })
|
||||
sort()
|
||||
|
@ -111,37 +139,23 @@ const openDeleteModal = () => {
|
|||
deleteModal.value?.$el.showModal()
|
||||
}
|
||||
|
||||
const filterButtons = ref<Button[]>([
|
||||
{
|
||||
label: 'Rollen',
|
||||
icon: 'uil:toilet-paper',
|
||||
active: currentSort.value === 0,
|
||||
},
|
||||
{
|
||||
label: 'Blatt',
|
||||
icon: 'uil:file-landscape',
|
||||
active: currentSort.value === 1,
|
||||
},
|
||||
{
|
||||
label: 'Lagen',
|
||||
icon: 'uil:layer-group',
|
||||
active: currentSort.value === 2,
|
||||
},
|
||||
])
|
||||
|
||||
const sortBy = (key : 'ppr' | 'pps' | 'ppl') => {
|
||||
cards.value.sort((a, b) => {
|
||||
const aCard = priceCards.value?.find(card => card.uuid === a.uuid) || null
|
||||
const bCard = priceCards.value?.find(card => card.uuid === b.uuid) || null
|
||||
if (!aCard || !bCard) return 0
|
||||
|
||||
if (currentSortDirection.value === 0) {
|
||||
return bCard[key] - aCard[key]
|
||||
}
|
||||
|
||||
return aCard[key] - bCard[key]
|
||||
})
|
||||
}
|
||||
|
||||
const sort = async (index : number = currentSort.value) => {
|
||||
currentSort.value = index
|
||||
filterButtons.value.forEach(button => { button.active = false })
|
||||
filterButtons.value[index]!.active = true
|
||||
currentSortElement.value = sortElements[index]!
|
||||
|
||||
await nextTick()
|
||||
|
||||
|
@ -151,4 +165,12 @@ const sort = async (index : number = currentSort.value) => {
|
|||
case 2: return sortBy('ppl')
|
||||
}
|
||||
}
|
||||
|
||||
const countSortDirection = () => {
|
||||
let newSortDirection = currentSortDirection.value + 1
|
||||
if (newSortDirection > 1) newSortDirection = 0
|
||||
|
||||
currentSortDirection.value = newSortDirection
|
||||
sort()
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -54,6 +54,8 @@ export default defineNuxtConfig({
|
|||
'./app/assets/styles/priceCard.css',
|
||||
'./app/assets/styles/form/textfield.css',
|
||||
'./app/assets/styles/form/search.css',
|
||||
'./app/assets/styles/form/dropdown.css',
|
||||
'./app/assets/styles/form/togglebutton.css',
|
||||
'./app/assets/styles/toolbar.css',
|
||||
'./app/assets/styles/page.css',
|
||||
'./app/assets/styles/dialog.css',
|
||||
|
|
4
shared/DropDown.ts
Normal file
4
shared/DropDown.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export type DropDownElement = {
|
||||
label: string
|
||||
value: string | number
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue