New elements and updates

This commit is contained in:
René Preuß
2023-02-20 18:42:21 +01:00
parent 40d02e52ec
commit d9041f471e
11 changed files with 334 additions and 14 deletions

View File

@@ -4,6 +4,10 @@
:class="computedClass" :class="computedClass"
@click="click" @click="click"
> >
<i
v-if="icon"
:class="['fal mr-1', icon]"
/>
<slot v-if="!loading" /> <slot v-if="!loading" />
<template v-else> <template v-else>
<i class="fas fa-spinner fa-spin" /> <i class="fas fa-spinner fa-spin" />
@@ -16,6 +20,10 @@ export default {
name: "BitinflowButton", name: "BitinflowButton",
props: { props: {
icon: {
type: String,
default: null
},
size: { size: {
type: String, type: String,
default: 'md' default: 'md'
@@ -59,9 +67,11 @@ export default {
.disabled { .disabled {
@apply opacity-50 cursor-not-allowed; @apply opacity-50 cursor-not-allowed;
} }
.loading { .loading {
@apply opacity-50 cursor-not-allowed; @apply opacity-50 cursor-not-allowed;
} }
.button-text-sm { .button-text-sm {
@apply text-sm; @apply text-sm;
} }
@@ -97,6 +107,7 @@ export default {
.primary-solid { .primary-solid {
@apply bg-primary-500 hover:bg-primary-600 dark:bg-primary-500 dark:hover:bg-primary-400 text-white; @apply bg-primary-500 hover:bg-primary-600 dark:bg-primary-500 dark:hover:bg-primary-400 text-white;
} }
.primary-outline { .primary-outline {
@apply border-primary-500 hover:bg-primary-500 dark:hover:bg-primary-500 dark:border-primary-500 dark:hover:border-primary-500 text-primary-500 hover:text-white; @apply border-primary-500 hover:bg-primary-500 dark:hover:bg-primary-500 dark:border-primary-500 dark:hover:border-primary-500 text-primary-500 hover:text-white;
} }
@@ -104,6 +115,7 @@ export default {
.danger-solid { .danger-solid {
@apply bg-rose-500 hover:bg-rose-600 dark:bg-rose-500 dark:hover:bg-rose-400 text-white; @apply bg-rose-500 hover:bg-rose-600 dark:bg-rose-500 dark:hover:bg-rose-400 text-white;
} }
.danger-outline { .danger-outline {
@apply border-rose-500 hover:bg-rose-500 dark:hover:bg-rose-500 dark:border-rose-500 dark:hover:border-rose-500 text-rose-500 hover:text-white; @apply border-rose-500 hover:bg-rose-500 dark:hover:bg-rose-500 dark:border-rose-500 dark:hover:border-rose-500 text-rose-500 hover:text-white;
} }
@@ -111,6 +123,7 @@ export default {
.warning-solid { .warning-solid {
@apply bg-amber-500 hover:bg-amber-600 dark:bg-amber-500 dark:hover:bg-amber-400 text-white; @apply bg-amber-500 hover:bg-amber-600 dark:bg-amber-500 dark:hover:bg-amber-400 text-white;
} }
.warning-outline { .warning-outline {
@apply border-amber-500 hover:bg-amber-500 dark:hover:bg-amber-500 dark:border-amber-500 dark:hover:border-amber-500 text-amber-500 hover:text-white; @apply border-amber-500 hover:bg-amber-500 dark:hover:bg-amber-500 dark:border-amber-500 dark:hover:border-amber-500 text-amber-500 hover:text-white;
} }
@@ -118,6 +131,7 @@ export default {
.base-solid { .base-solid {
@apply bg-white hover:bg-zinc-100 dark:bg-base-700 dark:hover:bg-base-600 text-black dark:text-white; @apply bg-white hover:bg-zinc-100 dark:bg-base-700 dark:hover:bg-base-600 text-black dark:text-white;
} }
.base-outline { .base-outline {
@apply border-zinc-100 hover:bg-zinc-100 dark:hover:bg-base-700 dark:border-base-600 dark:hover:border-base-600 text-black dark:text-white; @apply border-zinc-100 hover:bg-zinc-100 dark:hover:bg-base-700 dark:border-base-600 dark:hover:border-base-600 text-black dark:text-white;
} }
@@ -125,6 +139,7 @@ export default {
.light-solid { .light-solid {
@apply bg-zinc-200 hover:bg-zinc-300 dark:bg-base-600 dark:hover:bg-base-500 text-black dark:text-white; @apply bg-zinc-200 hover:bg-zinc-300 dark:bg-base-600 dark:hover:bg-base-500 text-black dark:text-white;
} }
.light-outline { .light-outline {
@apply border-zinc-200 hover:bg-zinc-200 hover:border-zinc-200 dark:hover:bg-base-500 dark:border-base-500 dark:hover:border-base-500 text-black dark:text-white; @apply border-zinc-200 hover:bg-zinc-200 hover:border-zinc-200 dark:hover:bg-base-500 dark:border-base-500 dark:hover:border-base-500 text-black dark:text-white;
} }

View File

@@ -1,7 +1,8 @@
<template> <template>
<nuxt-link <nuxt-link
class="hover:bg-primary-500 rounded-lg text-center text-xs py-4 flex flex-col space-y-2" class="hover:bg-primary-500 rounded-lg text-center text-xs py-4 flex flex-col space-y-2"
href="#" :class="calculateClasses"
:to="to"
> >
<i :class="['fal text-xl', icon]" /> <i :class="['fal text-xl', icon]" />
<span> <span>
@@ -17,7 +18,29 @@ export default {
icon: { icon: {
type: String, type: String,
default: 'fa-arrow-up-right-from-square' default: 'fa-arrow-up-right-from-square'
},
to: {
type: String,
default: '/'
}
},
computed: {
calculateClasses: function () {
return {
'router-link-active': this.$route.path.includes(this.to) && this.to !== '/',
}
} }
} }
} }
</script> </script>
<style scoped>
.router-link-active {
@apply bg-primary-500 dark:bg-primary-500;
}
/*
.router-link-active:hover {
@apply bg-primary-600 dark:bg-primary-400;
}
*/
</style>

View File

@@ -96,19 +96,19 @@
<div class="flex-auto flex flex-col overflow-y-auto py-6 space-y-6"> <div class="flex-auto flex flex-col overflow-y-auto py-6 space-y-6">
<!-- nav --> <!-- nav -->
<nav class="primary flex flex-grow flex-col space-y-4 px-6"> <nav class="primary flex flex-grow flex-col space-y-4 px-6">
<slot name="top" /> <slot name="top"/>
</nav> </nav>
<nav class="flex flex-initial flex-col space-y-4 px-6"> <nav class="flex flex-initial flex-col space-y-4 px-6">
<slot name="bottom" /> <slot name="bottom"/>
</nav> </nav>
</div> </div>
<div class="flex-none" /> <div class="flex-none"/>
</nav> </nav>
<!-- Content --> <!-- Content -->
<main class="flex flex-1"> <main class="flex flex-1">
<slot /> <slot/>
</main> </main>
</div> </div>
</div> </div>
@@ -139,6 +139,12 @@ export default {
], ],
}; };
}, },
mounted() {
// restore dark mode from local storage
if (localStorage.getItem('darkMode') === 'true') {
document.body.classList.add('dark');
}
},
methods: { methods: {
toggleMenu() { toggleMenu() {
this.$refs.overlay.classList.toggle('hidden'); this.$refs.overlay.classList.toggle('hidden');
@@ -166,7 +172,8 @@ export default {
}, 500); }, 500);
}); });
} }
document.body.classList.toggle('dark') const result = document.body.classList.toggle('dark')
localStorage.setItem('darkMode', result ? 'true' : 'false');
} }
}, },
}; };

View File

@@ -0,0 +1,15 @@
<template>
<div class="flex-1">
<slot />
</div>
</template>
<script>
export default {
name: "BitinflowFlex1"
}
</script>
<style scoped>
</style>

View File

@@ -1,12 +1,12 @@
<template> <template>
<div class="flex-auto"> <div class="flex-auto">
<slot/> <slot />
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: "BitinflowFlex" name: "BitinflowFlexAuto"
} }
</script> </script>

View File

@@ -1,9 +1,9 @@
<template> <template>
<bitinflow-button <bitinflow-button
class="flex items-center gap-2 w-full" class="flex items-center gap-2 w-full"
icon="fa-plus"
@click="$emit('click')" @click="$emit('click')"
> >
<i :class="['fal', icon]" />
<slot /> <slot />
</bitinflow-button> </bitinflow-button>
</template> </template>

View File

@@ -1,6 +1,7 @@
<template> <template>
<bitinflow-button-link <bitinflow-button-link
class="flex items-center gap-2" class="flex items-center gap-2"
:class="calculateClasses"
:to="to" :to="to"
> >
<i :class="['fal', icon]" /> <i :class="['fal', icon]" />
@@ -23,6 +24,25 @@ export default {
type: String, type: String,
required: true required: true
} }
},
computed: {
calculateClasses: function () {
return {
'router-link-active': this.$route.path.includes(this.to),
}
}
} }
} }
</script> </script>
<style scoped>
.router-link-active, .router-link-exact-active {
@apply bg-primary-500 dark:bg-primary-500;
}
/*
.router-link-active:hover, .router-link-exact-active:hover {
@apply bg-primary-600 dark:bg-primary-400;
}
*/
</style>

View File

@@ -1,7 +1,7 @@
<!-- eslint-disable vue/require-explicit-emits --> <!-- eslint-disable vue/require-explicit-emits -->
<template> <template>
<nav <nav
class="w-64 bg-white text-black shadow dark:bg-base-700 dark:text-white dark:border-base-900 dark:border-l flex flex-col overflow-y-auto h-screen absolute sm:relative transform -translate-x-full sm:translate-x-0 pt-10 pb-4 px-4 space-y-2" class="w bg-white text-black shadow dark:bg-base-700 dark:text-white dark:border-base-900 dark:border-l flex flex-col overflow-y-auto h-screen absolute sm:relative transform -translate-x-full sm:translate-x-0 pt-10 pb-4 px-4 space-y-2"
> >
<span class="font-semibold px-4"> <span class="font-semibold px-4">
<slot name="title" /> <slot name="title" />
@@ -14,11 +14,23 @@
<div <div
v-for="i in 3" v-for="i in 3"
:key="i" :key="i"
class="bg-zinc-100 dark:bg-base-600 rounded-lg px-4 py-2" class="bg-zinc-100 dark:bg-base-600 rounded-lg px-4 py-2 h-10 animate-pulse"
> />
&nbsp;
</div>
</template> </template>
<div v-else-if="empty" class="bg-zinc-100 dark:bg-base-600 rounded-lg px-4 py-16 text-xl opacity-50 text-center">
<i class="fas fa-ghost mr-2 text-5xl opacity-70" />
<div>
No resources found
</div>
<div class="text-xs mt-2 opacity-70">
<template v-if="hasCreateListener">
Click on the <span class="font-bold"><i class="far fa-plus" /> Create Resource</span> button below to create your first resource.
</template>
<template v-else>
You don't have any resources yet.
</template>
</div>
</div>
</div> </div>
<div v-if="hasCreateListener"> <div v-if="hasCreateListener">
<bitinflow-second-level-button <bitinflow-second-level-button
@@ -51,6 +63,10 @@ export default {
loading: { loading: {
type: Boolean, type: Boolean,
default: false default: false
},
empty: {
type: Boolean,
default: false
} }
}, },

View File

@@ -0,0 +1,135 @@
<template>
<template v-if="loading">
<div
v-for="i in 3"
:key="i"
class="bg-white text-black dark:bg-base-700 rounded-lg h-16 animate-pulse"
/>
</template>
<div
v-else-if="items.length === 0"
class="bg-white dark:bg-base-700 rounded-lg px-4 py-16 text-xl text-center text-black dark:text-white"
>
<i class="fas fa-ghost mr-2 text-5xl opacity-70" />
<div>
No resources found
</div>
<div class="text-xs mt-2 opacity-70">
<template v-if="hasCreateListener">
Click on the
<span class="font-bold"><i class="far fa-plus" /> Create Resource</span>
button below to create your first resource.
</template>
<template v-else>
You don't have any resources yet.
</template>
</div>
<div v-if="hasCreateListener">
<bitinflow-button
color="light"
variant="outline"
class="mt-8"
size="sm"
icon="fa-plus"
@click="$emit('create')"
>
Create Resource
</bitinflow-button>
</div>
</div>
<div
v-else
class="text-black dark:text-white"
>
<div class="flex gap-4 py-2">
<div>
<bitinflow-table-checkbox
v-model="checkedAll"
@update:model-value="toggleAll"
/>
</div>
<div
class="flex-auto px-6"
:class="gridClass"
>
<template
v-for="key in keys"
:key="key"
>
<div class="opacity-80">{{ columns[key].label }}</div>
</template>
</div>
</div>
<div class="grid gap-4">
<bitinflow-table-row
v-for="item in items"
:key="item.id"
:grid-class="gridClass"
@click="click(item)"
>
<slot
name="row"
:item="item"
:keys="keys"
/>
</bitinflow-table-row>
</div>
</div>
</template>
<script>
import BitinflowTableRow from "../../../dist/runtime/components/BitinflowTableRow.vue";
import BitinflowTableCheckbox from "./BitinflowTableCheckbox.vue";
export default {
name: "BitinflowTable",
components: {BitinflowTableCheckbox, BitinflowTableRow},
props: {
columns: {
type: Array,
required: true
},
items: {
type: Array,
required: true
},
loading: {
type: Boolean,
default: false
}
},
data() {
return {
keys: Object.keys(this.columns),
checkedAll: false,
}
},
computed: {
gridClass() {
return `grid grid-cols-${this.keys.length} gap-4`;
},
hasCreateListener() {
return this.$attrs && this.$attrs.onCreate;
}
},
methods: {
title(value) {
// "humanized" by converting kebab-case, snake_case, and camelCase to individual words and capitalizes each word.
return value.replace(/([A-Z])/g, ' $1').replace(/[-_]/g, ' ').toLowerCase().replace(/(?:^|\s)\S/g, function(a) { return a.toUpperCase(); });
},
toggleAll(checked) {
console.log('toggleAll', checked)
},
click(item) {
this.$emit('click', item);
}
}
}
</script>

View File

@@ -0,0 +1,37 @@
<template>
<a
class="w-4 h-4 flex justify-center rounded p-2 text-black dark:text-white border-2 border-zinc-200 dark:border-base-600 dark:bg-base-700 dark:text-white"
href="#"
@click.prevent="toggle"
>
<i
v-if="modelValue"
class="fas fa-check text-xs text-primary-500 self-center"
/>
</a>
</template>
<script>
export default {
name: "BitinflowTableCheckbox",
props: {
modelValue: {
type: Boolean,
default: false
}
},
emits: ['update:modelValue'],
methods: {
toggle() {
this.$emit('update:modelValue', !this.modelValue);
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,52 @@
<template>
<div class="flex gap-4">
<div class="self-center">
<bitinflow-table-checkbox v-model="checked" />
</div>
<div class="flex-auto relative">
<a
class="after:absolute after:inset-0"
href="#"
@click.prevent="click"
/>
<div
class="bg-white border-2 text-black dark:bg-base-700 dark:text-white rounded shadow py-4 px-6"
:class="checked ? 'border-primary-500' : 'border-transparent'"
>
<div :class="gridClass" class="items-center">
<slot />
</div>
</div>
</div>
</div>
</template>
<script>
import BitinflowTableCheckbox from "./BitinflowTableCheckbox.vue";
export default {
name: "BitinflowTableRow",
components: {BitinflowTableCheckbox},
props: {
gridClass: {
type: String,
required: true
}
},
emits: ['click'],
data() {
return {
checked: false
}
},
methods: {
click() {
this.$emit('click');
}
}
}
</script>