Delete todo app, add blog website
This commit is contained in:
@@ -7,6 +7,41 @@ description: "This is a test article."
|
|||||||
|
|
||||||
This is a test article.
|
This is a test article.
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum a tempor
|
||||||
|
dolor. Nullam mattis sapien vel finibus dignissim. Etiam et diam ultrices,
|
||||||
|
aliquam enim nec, commodo sem. Cras ut faucibus risus. Suspendisse vel faucibus
|
||||||
|
ipsum. Duis vel orci nec arcu porttitor fermentum eu quis est. Phasellus elit
|
||||||
|
odio, elementum ac placerat at, feugiat sit amet sapien.
|
||||||
|
|
||||||
|
Vestibulum dapibus pharetra metus. Integer volutpat lacus nec enim euismod, id
|
||||||
|
dignissim felis rhoncus. Cras commodo tempus turpis, eu vehicula mi lacinia
|
||||||
|
eget. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per
|
||||||
|
inceptos himenaeos. Integer rhoncus dolor ut dolor gravida vestibulum. Ut
|
||||||
|
dignissim orci a ornare ullamcorper. Nam facilisis mauris sit amet nunc
|
||||||
|
fermentum pretium. Nullam in nisi at risus luctus viverra. Mauris non congue
|
||||||
|
dolor, vel finibus lectus. Nam quis leo pretium, sodales augue et, dictum sem.
|
||||||
|
|
||||||
|
Curabitur velit ante, imperdiet in eros eu, iaculis gravida risus. Nullam ut
|
||||||
|
feugiat eros, viverra vehicula sem. Aliquam finibus mi magna, eu fringilla
|
||||||
|
tellus ullamcorper vel. Fusce eget auctor mi. Mauris venenatis pellentesque
|
||||||
|
arcu. Nam ac diam sem. Nulla suscipit sed risus non vehicula. Cras molestie
|
||||||
|
lectus et tincidunt tempor. Ut tempus lorem id augue semper convallis. Aliquam
|
||||||
|
vel dui quis dolor cursus faucibus eget a mi. Curabitur tempus justo diam, a
|
||||||
|
facilisis ligula tincidunt viverra. Donec sodales quis dolor at dignissim.
|
||||||
|
Nullam placerat vitae urna quis bibendum.
|
||||||
|
|
||||||
|
Integer a magna a velit bibendum mollis. Donec lobortis molestie diam at rutrum.
|
||||||
|
Nunc viverra gravida metus at facilisis. Nulla sit amet erat sodales, commodo
|
||||||
|
elit sed, ultrices magna. Aliquam vel purus fringilla, gravida enim quis,
|
||||||
|
aliquam augue. Duis interdum et erat nec feugiat. Praesent vitae lacinia leo,
|
||||||
|
non suscipit purus.
|
||||||
|
|
||||||
|
Aenean massa magna, imperdiet id ex quis, mollis auctor lectus. Cras velit
|
||||||
|
nulla, volutpat eu neque id, semper venenatis urna. Integer in blandit ex, non
|
||||||
|
scelerisque nisi. Ut sagittis tincidunt enim at volutpat. Sed hendrerit metus ac
|
||||||
|
interdum laoreet. In rutrum turpis in nulla vulputate suscipit. Nunc dictum nisl
|
||||||
|
id magna laoreet dapibus.
|
||||||
|
|
||||||
## Component Rendering
|
## Component Rendering
|
||||||
|
|
||||||
::ExampleComponent
|
::ExampleComponent
|
||||||
@@ -36,9 +71,9 @@ protected static $router;
|
|||||||
$path = parse_url($_SERVER['REQUEST_URI'])['path'];
|
$path = parse_url($_SERVER['REQUEST_URI'])['path'];
|
||||||
```
|
```
|
||||||
|
|
||||||
Inline `hightlight`.
|
Inline `hightlight` looks like so.
|
||||||
|
|
||||||
`const code: string = 'highlighted code inline'`{lang="ts"}
|
Inline highlight with language `const code: string = 'highlighted code inline'`{lang="ts"} like this.
|
||||||
|
|
||||||
- An
|
- An
|
||||||
- Unordered
|
- Unordered
|
||||||
|
|||||||
+19
-11
@@ -1,4 +1,6 @@
|
|||||||
import Aura from "@primevue/themes/aura";
|
import Icons from "unplugin-icons/vite"
|
||||||
|
import IconsResolver from "unplugin-icons/resolver"
|
||||||
|
import ViteComponents from "unplugin-vue-components/vite"
|
||||||
|
|
||||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
@@ -17,7 +19,7 @@ export default defineNuxtConfig({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
css: [
|
css: [
|
||||||
"primeicons/primeicons.css",
|
"bootstrap/dist/css/bootstrap.min.css",
|
||||||
"~/assets/css/style.css"
|
"~/assets/css/style.css"
|
||||||
],
|
],
|
||||||
devtools: { enabled: true },
|
devtools: { enabled: true },
|
||||||
@@ -25,11 +27,12 @@ export default defineNuxtConfig({
|
|||||||
public: "../public"
|
public: "../public"
|
||||||
},
|
},
|
||||||
modules: [
|
modules: [
|
||||||
|
"@bootstrap-vue-next/nuxt",
|
||||||
"@nuxt/content",
|
"@nuxt/content",
|
||||||
"@nuxt/eslint",
|
"@nuxt/eslint",
|
||||||
"@pinia/nuxt",
|
"@pinia/nuxt",
|
||||||
"@primevue/nuxt-module",
|
|
||||||
"pinia-plugin-persistedstate/nuxt",
|
"pinia-plugin-persistedstate/nuxt",
|
||||||
|
"unplugin-icons/nuxt"
|
||||||
],
|
],
|
||||||
pinia: {
|
pinia: {
|
||||||
storesDirs: ["src/stores/**"] // also auto-import nested directories
|
storesDirs: ["src/stores/**"] // also auto-import nested directories
|
||||||
@@ -42,13 +45,18 @@ export default defineNuxtConfig({
|
|||||||
secure: process.env.NODE_ENV !== "development" // only send over HTTPS
|
secure: process.env.NODE_ENV !== "development" // only send over HTTPS
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
primevue: {
|
|
||||||
options: {
|
|
||||||
theme: {
|
|
||||||
preset: Aura
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
srcDir: "src/",
|
srcDir: "src/",
|
||||||
ssr: false
|
ssr: false,
|
||||||
|
vite: {
|
||||||
|
plugins: [
|
||||||
|
ViteComponents({
|
||||||
|
resolvers: [IconsResolver()],
|
||||||
|
dts: true
|
||||||
|
}),
|
||||||
|
Icons({
|
||||||
|
compiler: "vue3",
|
||||||
|
autoInstall: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Generated
+822
-309
File diff suppressed because it is too large
Load Diff
+10
-7
@@ -11,25 +11,28 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@pinia/nuxt": "^0.10.1",
|
"@pinia/nuxt": "^0.10.1",
|
||||||
"@primevue/forms": "^4.2.3",
|
|
||||||
"@primevue/themes": "^4.2.3",
|
|
||||||
"nuxt": "^3.14.1592",
|
|
||||||
"pinia-plugin-persistedstate": "^4.1.3",
|
"pinia-plugin-persistedstate": "^4.1.3",
|
||||||
"primeicons": "^7.0.0",
|
|
||||||
"primevue": "^4.2.3",
|
|
||||||
"uuid": "^11.0.3",
|
"uuid": "^11.0.3",
|
||||||
"vue": "latest",
|
"vue": "latest",
|
||||||
"vue-router": "latest",
|
"vue-router": "latest",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@bootstrap-vue-next/nuxt": "^0.28.3",
|
||||||
|
"@iconify-json/bi": "^1.2.2",
|
||||||
|
"@iconify-json/fa": "^1.2.1",
|
||||||
"@nuxt/content": "^3.4.0",
|
"@nuxt/content": "^3.4.0",
|
||||||
"@nuxt/eslint": "^1.2.0",
|
"@nuxt/eslint": "^1.2.0",
|
||||||
"@primevue/nuxt-module": "^4.2.3",
|
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest",
|
||||||
|
"@vue/compiler-sfc": "^3.5.13",
|
||||||
"@vue/language-server": "^2.1.10",
|
"@vue/language-server": "^2.1.10",
|
||||||
"@vue/typescript-plugin": "^2.1.10",
|
"@vue/typescript-plugin": "^2.1.10",
|
||||||
"typescript": "^5.7.2"
|
"bootstrap": "^5.3.3",
|
||||||
|
"bootstrap-vue-next": "^0.28.3",
|
||||||
|
"nuxt": "^3.14.1592",
|
||||||
|
"typescript": "^5.7.2",
|
||||||
|
"unplugin-icons": "^22.1.0",
|
||||||
|
"unplugin-vue-components": "^28.4.1"
|
||||||
},
|
},
|
||||||
"trustedDependencies": [
|
"trustedDependencies": [
|
||||||
"@parcel/watcher"
|
"@parcel/watcher"
|
||||||
|
|||||||
@@ -1,7 +1,42 @@
|
|||||||
/*----------------------------------------*/
|
/*----------------------------------------*/
|
||||||
/* General */
|
/* General */
|
||||||
|
|
||||||
body {
|
html {
|
||||||
font-family: "Segoe UI", "DejaVu Sans", sans-serif;
|
font-family: "Segoe UI", "DejaVu Sans", sans-serif;
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
box-shadow: 0 .25rem .5rem rgba(0,0,0,.28) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main content */
|
||||||
|
/*----------------------------------------*/
|
||||||
|
|
||||||
|
.container {
|
||||||
|
margin: 56px auto 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
position: relative;
|
||||||
|
min-height: calc(100vh - 104px - .5rem);
|
||||||
|
padding: 20px 20px 50px 20px;
|
||||||
|
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #818080 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
/*----------------------------------------*/
|
||||||
|
|
||||||
|
footer {
|
||||||
|
text-align: center;
|
||||||
|
color: #909090;
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+28
@@ -0,0 +1,28 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
// Generated by unplugin-vue-components
|
||||||
|
// Read more: https://github.com/vuejs/core/pull/3399
|
||||||
|
// biome-ignore lint: disable
|
||||||
|
export {}
|
||||||
|
|
||||||
|
/* prettier-ignore */
|
||||||
|
declare module 'vue' {
|
||||||
|
export interface GlobalComponents {
|
||||||
|
IBi0Circle: typeof import('~icons/bi/0-circle')['default']
|
||||||
|
IBiActivity: typeof import('~icons/bi/activity')['default']
|
||||||
|
IFaAngellist: typeof import('~icons/fa/angellist')['default']
|
||||||
|
IFaCheck: typeof import('~icons/fa/check')['default']
|
||||||
|
IFaClone: typeof import('~icons/fa/clone')['default']
|
||||||
|
IFaCoffee: typeof import('~icons/fa/coffee')['default']
|
||||||
|
IFaCope: typeof import('~icons/fa/cope')['default']
|
||||||
|
IFaCopy: typeof import('~icons/fa/copy')['default']
|
||||||
|
IFaGithub: typeof import('~icons/fa/github')['default']
|
||||||
|
IFaGitlab: typeof import('~icons/fa/gitlab')['default']
|
||||||
|
IFaHome: typeof import('~icons/fa/home')['default']
|
||||||
|
IFaLink: typeof import('~icons/fa/link')['default']
|
||||||
|
IFaLinkedinSquare: typeof import('~icons/fa/linkedin-square')['default']
|
||||||
|
IMdiAccountBox: typeof import('~icons/mdi/account-box')['default']
|
||||||
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h2 v-if="$slots.namedslot">
|
<strong v-if="$slots.namedslot">
|
||||||
<slot name="namedslot" mdc-unwrap="p" />
|
<slot name="namedslot" mdc-unwrap="p" />
|
||||||
</h2>
|
</strong>
|
||||||
<h2 v-else>Broken Slot</h2>
|
<h2 v-else>Broken Slot</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
<slot mdc-unwrap="p" />
|
<slot mdc-unwrap="p" />
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps({
|
defineProps({
|
||||||
namedslot: String,
|
namedslot: String,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,2 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<footer class="row mb-2">
|
||||||
|
<div class="col-12">
|
||||||
|
© {{ year }} Rick van Vonderen
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const year = new Date().getFullYear();
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -1,61 +1,30 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="card">
|
<BNavbar v-b-color-mode="'dark'" toggleable="lg" variant="dark" fixed="top">
|
||||||
<Menubar :model="items">
|
<BNavbarBrand to="/">
|
||||||
<template #item="{ item, props, hasSubmenu }">
|
<IFaHome /> Home
|
||||||
<router-link v-if="item.route" v-slot="{ href, navigate }" :to="item.route" custom>
|
</BNavbarBrand>
|
||||||
<a v-ripple :href="href" v-bind="props.action" @click="navigate">
|
<BNavbarToggle target="nav-collapse" />
|
||||||
<span :class="item.icon" />
|
<BCollapse id="nav-collapse" is-nav>
|
||||||
<span>{{ item.label }}</span>
|
<!-- Left aligned nav items -->
|
||||||
</a>
|
<BNavbarNav>
|
||||||
</router-link>
|
<BNavItem to="/articles">Articles</BNavItem>
|
||||||
<a v-else v-ripple :href="item.url" :target="item.target" v-bind="props.action">
|
<BNavItem to="/todos">Todos</BNavItem>
|
||||||
<span :class="item.icon" />
|
</BNavbarNav>
|
||||||
<span>{{ item.label }}</span>
|
<!-- Right aligned nav items -->
|
||||||
<span v-if="hasSubmenu" class="pi pi-fw pi-angle-down" />
|
<BNavbarNav class="ms-auto mb-2 mb-lg-0">
|
||||||
</a>
|
<BNavItem href="https://git.riyyi.com/riyyi" target="_blank">
|
||||||
</template>
|
<IFaCoffee /> Gitea
|
||||||
</Menubar>
|
</BNavItem>
|
||||||
</div>
|
<BNavItem href="https://github.com/riyyi" target="_blank">
|
||||||
|
<IFaGithub /> Github
|
||||||
|
</BNavItem>
|
||||||
|
<BNavItem href="https://gitlab.com/riyyi" target="_blank">
|
||||||
|
<IFaGitlab /> Gitlab
|
||||||
|
</BNavItem>
|
||||||
|
<BNavItem href="https://linkedin.com/in/rickvanvonderen" target="_blank">Linked
|
||||||
|
<IFaLinkedinSquare />
|
||||||
|
</BNavItem>
|
||||||
|
</BNavbarNav>
|
||||||
|
</BCollapse>
|
||||||
|
</BNavbar>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref } from "vue";
|
|
||||||
import { useRouter } from "vue-router";
|
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
const currentDate = new Date().toLocaleString("nl-NL");
|
|
||||||
|
|
||||||
const items = ref([
|
|
||||||
{
|
|
||||||
label: "Home",
|
|
||||||
icon: "pi pi-home",
|
|
||||||
route: "/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Todos",
|
|
||||||
icon: "pi pi-check",
|
|
||||||
command: () => {
|
|
||||||
router.push("/todos");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Articles",
|
|
||||||
icon: "pi pi-link",
|
|
||||||
route: "/articles"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Service",
|
|
||||||
icon: "pi pi-link",
|
|
||||||
route: "#"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Contact",
|
|
||||||
icon: "pi pi-link",
|
|
||||||
route: "#"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Date: " + currentDate,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
</script>
|
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
<template>
|
|
||||||
adasda
|
|
||||||
<Column field="title">
|
|
||||||
<template #header>
|
|
||||||
<span @click="toggleSorting('title')" class="p-datatable-column-title">Title
|
|
||||||
<span :class="['pi', sorting.title === 'asc' ? 'pi-arrow-circle-down' : 'pi-arrow-circle-up']"></span>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</Column>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
const sorting = defineModel<Record<string, string>>({ required: true });
|
|
||||||
|
|
||||||
function toggleSorting(key: string) {
|
|
||||||
sorting.value[key] = sorting.value[key] === 'asc' ? 'desc' : 'asc';
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<template>
|
|
||||||
<Form v-slot="$form" ref="formRef" :initialValues :resolver @submit="onFormSubmit"
|
|
||||||
class="flex flex-col gap-4 w-full sm:w-56">
|
|
||||||
<!-- {{ $form }} -->
|
|
||||||
<div class="flex flex-col gap-1">
|
|
||||||
<InputText @input="initial = false;" v-model="formData.title" name="title" type="text" placeholder="Title"
|
|
||||||
autocomplete="off" fluid />
|
|
||||||
<Message v-if="$form.title?.invalid" severity="error" size="small" variant="simple">
|
|
||||||
{{ $form.title.error?.message }}
|
|
||||||
</Message>
|
|
||||||
</div>
|
|
||||||
<Button :disabled="initial || !$form.valid" class="fr" type="submit" severity="secondary" label="Submit" />
|
|
||||||
</Form>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { useTodoStore } from "@/stores/todoStore";
|
|
||||||
import { todoSchema } from "@/schemas/todo";
|
|
||||||
import { zodResolver } from '@primevue/forms/resolvers/zod';
|
|
||||||
import { v4 as uuidv4 } from "uuid";
|
|
||||||
|
|
||||||
import { type FormSubmitEvent } from "@primevue/forms/form";
|
|
||||||
|
|
||||||
const store = useTodoStore();
|
|
||||||
const toast = useToast();
|
|
||||||
const resolver = zodResolver(todoSchema);
|
|
||||||
|
|
||||||
const initial = ref(true); // makes submit button disabled
|
|
||||||
const initialValues = ref({
|
|
||||||
title: ""
|
|
||||||
});
|
|
||||||
const formRef = ref<HTMLElement | null>(null);
|
|
||||||
const formData = ref({ ...initialValues.value }); // copy data from initialValues
|
|
||||||
|
|
||||||
async function onFormSubmit(e: FormSubmitEvent) {
|
|
||||||
if (e.valid) {
|
|
||||||
toast.add({ severity: "success", summary: "Todo added", life: 3000 });
|
|
||||||
|
|
||||||
store.todos.push({
|
|
||||||
id: uuidv4(),
|
|
||||||
title: e.values?.title || e.states?.title.value
|
|
||||||
});
|
|
||||||
|
|
||||||
// Reset the form
|
|
||||||
initial.value = true;
|
|
||||||
formData.value = { ...initialValues.value }; // copy data from initialValues
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
toast.add({ severity: "error", summary: "Invalid request", life: 3000 });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.fr {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="card">
|
|
||||||
<ConfirmDialog></ConfirmDialog>
|
|
||||||
<DataTable :value="computedTodos" :lazy="true" tableStyle="min-width: 50rem" removableSort
|
|
||||||
:sortMode="'multiple'" v-model:multiSortMeta="multiSortMeta">
|
|
||||||
<Column field="number" header="#" />
|
|
||||||
<Column field="id" header="ID" sortable />
|
|
||||||
<Column field="title" header="Title" sortable />
|
|
||||||
<Column header="Modifier">
|
|
||||||
<template #body="slotProps">
|
|
||||||
<a @click="removeTodo(slotProps.data.id)" v-tooltip.top="'Delete'" class="pointer">
|
|
||||||
<span class="pi pi-trash" style="color: var(--p-red-600);"></span>
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
</Column>
|
|
||||||
</DataTable>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { useConfirm } from "primevue/useconfirm";
|
|
||||||
import { useToast } from "primevue/usetoast";
|
|
||||||
import { useTodoStore } from "@/stores/todoStore";
|
|
||||||
|
|
||||||
import type { DataTableSortMeta } from "primevue/datatable";
|
|
||||||
import type { Todo } from "@/schemas/todo";
|
|
||||||
|
|
||||||
const confirm = useConfirm();
|
|
||||||
const store = useTodoStore();
|
|
||||||
const toast = useToast();
|
|
||||||
|
|
||||||
// Reactive bindings for sorting
|
|
||||||
const multiSortMeta = ref<DataTableSortMeta[]>([]);
|
|
||||||
|
|
||||||
function sortTodos(): Todo[] {
|
|
||||||
let todos: Todo[] = JSON.parse(JSON.stringify(store.todos)); // deep copy
|
|
||||||
|
|
||||||
// Loop in reverse order to apply the sorting correctly
|
|
||||||
for (let i = multiSortMeta.value.length - 1; i >= 0; i--) {
|
|
||||||
|
|
||||||
const sort: DataTableSortMeta = multiSortMeta.value[i];
|
|
||||||
const value = (item: Todo): string => {
|
|
||||||
if (typeof sort.field === "string") {
|
|
||||||
return item[sort.field as keyof Todo] || "";
|
|
||||||
}
|
|
||||||
else if (typeof sort.field === "function") {
|
|
||||||
return sort.field(item) || "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
};
|
|
||||||
|
|
||||||
todos.sort((a, b) => sort.order! * value(a).localeCompare(value(b)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return todos;
|
|
||||||
}
|
|
||||||
|
|
||||||
const computedTodos = computed(() => {
|
|
||||||
return sortTodos().map((todo, index) => ({
|
|
||||||
number: index + 1,
|
|
||||||
...todo
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
const removeTodo = (id: String) => {
|
|
||||||
confirm.require({
|
|
||||||
message: "Do you want to delete this todo?",
|
|
||||||
header: "Confirmation",
|
|
||||||
icon: "pi pi-info-circle",
|
|
||||||
rejectLabel: "Cancel",
|
|
||||||
rejectProps: {
|
|
||||||
label: "Cancel",
|
|
||||||
severity: "secondary",
|
|
||||||
outlined: true
|
|
||||||
},
|
|
||||||
acceptProps: {
|
|
||||||
label: "Delete",
|
|
||||||
severity: "danger"
|
|
||||||
},
|
|
||||||
accept: () => {
|
|
||||||
toast.add({ severity: "info", summary: "Confirmed", detail: "Todo deleted", life: 3000 });
|
|
||||||
store.todos = store.todos.filter(todo => todo.id !== id);
|
|
||||||
},
|
|
||||||
reject: () => {}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.pointer {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,5 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<SharedHeader />
|
<SharedHeader />
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="content shadow p-4 mb-4">
|
||||||
<slot />
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<SharedFooter />
|
<SharedFooter />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -12,6 +12,41 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Target element in child components with :deep */
|
||||||
|
|
||||||
|
/* Select any <a> inside a <h> */
|
||||||
|
:deep(:is(h1, h2, h3, h4, h5, h6) > a) {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select <pre class="shiki"> */
|
||||||
|
:deep(pre.shiki) {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: #f6f8fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select <code> and <code class="shiki"> */
|
||||||
|
:deep(code:not(pre code)) {
|
||||||
|
padding: .2em .4em;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 85%;
|
||||||
|
white-space: break-spaces;
|
||||||
|
background-color: #818b981f;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select <code> */
|
||||||
|
:deep(code:not(.shiki):not(pre code)) {
|
||||||
|
/* reset font to black */
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const { params } = useRoute();
|
const { params } = useRoute();
|
||||||
|
|
||||||
|
|||||||
+183
-16
@@ -1,18 +1,185 @@
|
|||||||
<template>
|
<template>
|
||||||
<TodoBrowse />
|
<ExampleComponent>
|
||||||
<br>
|
<template v-slot:namedslot>
|
||||||
<TodoAdd />
|
<h1>named slot</h1>
|
||||||
<br>
|
</template>
|
||||||
<Button @click="showToast()" type="button">Toast</Button>
|
default slot goes here
|
||||||
|
</ExampleComponent>
|
||||||
|
|
||||||
|
<ExampleComponent>
|
||||||
|
<template #namedslot>
|
||||||
|
<h1>named slot</h1>
|
||||||
|
</template>
|
||||||
|
default slot goes here
|
||||||
|
</ExampleComponent>
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris eget
|
||||||
|
nibh eget mi interdum porta eu at eros. Integer nec magna ligula.
|
||||||
|
Nulla turpis turpis, vulputate in gravida ac, euismod ullamcorper
|
||||||
|
mi. Pellentesque ornare leo lorem, eu mollis nisi congue feugiat.
|
||||||
|
Vestibulum eget interdum sem, ut eleifend quam. Sed cursus consequat
|
||||||
|
ex, quis sodales nunc gravida faucibus. Fusce et velit sed turpis
|
||||||
|
accumsan interdum sed ut enim. Suspendisse vehicula mi ac tellus
|
||||||
|
fermentum feugiat. Nullam volutpat tempor nunc, ac tincidunt nisi.
|
||||||
|
Sed varius est a nisi lobortis, vel gravida dui efficitur. Vivamus
|
||||||
|
in ipsum quis mi bibendum venenatis ac sed erat. Pellentesque id
|
||||||
|
ligula sapien. Vivamus elit mauris, volutpat eu venenatis ac,
|
||||||
|
condimentum et velit. Morbi ullamcorper tellus non magna faucibus,
|
||||||
|
et molestie erat euismod.
|
||||||
|
|
||||||
|
Ut posuere libero sed finibus bibendum. Integer non est eu sapien
|
||||||
|
gravida fringilla. Aliquam lobortis, ipsum in volutpat ullamcorper,
|
||||||
|
nunc augue consequat risus, id ultrices diam erat eu enim. Cras at
|
||||||
|
nibh turpis. Donec facilisis massa ante, et volutpat ante faucibus
|
||||||
|
nec. Nullam at dictum erat, eu iaculis nibh. Integer ac velit eget
|
||||||
|
dolor consequat tristique. Praesent interdum nisi eget libero
|
||||||
|
euismod congue ac vitae mi. Aliquam in ex quam. Sed id nisi in diam
|
||||||
|
lacinia dignissim a dapibus magna. Vivamus vestibulum suscipit
|
||||||
|
sapien. Aenean luctus orci at hendrerit rhoncus. Nam nec ligula nec
|
||||||
|
justo pellentesque finibus vitae id elit.
|
||||||
|
|
||||||
|
Cras posuere neque at pharetra lacinia. Etiam id suscipit dolor,
|
||||||
|
quis ullamcorper diam. Donec semper feugiat risus, sit amet maximus
|
||||||
|
risus lacinia in. Aenean auctor iaculis dui, et commodo ex
|
||||||
|
consectetur ac. Morbi elementum, est eget condimentum placerat,
|
||||||
|
sapien felis molestie neque, cursus tempus purus lectus at eros. Nam
|
||||||
|
in lorem eu magna elementum viverra ut nec lorem. Fusce auctor arcu
|
||||||
|
sodales nibh iaculis ultrices. Nunc mi elit, pulvinar ut quam eu,
|
||||||
|
iaculis gravida mauris. Sed ultrices, orci vitae pretium
|
||||||
|
condimentum, felis dolor auctor velit, vel viverra nulla lacus vel
|
||||||
|
lectus. Cras eros turpis, dignissim sit amet rutrum gravida,
|
||||||
|
placerat non nulla.
|
||||||
|
|
||||||
|
Curabitur at sodales lectus, vulputate accumsan tortor. Duis in
|
||||||
|
efficitur ex. Mauris imperdiet nibh urna, eu elementum erat
|
||||||
|
elementum a. Curabitur id magna ac risus euismod aliquet. Nullam
|
||||||
|
hendrerit gravida nisl, ac sodales nibh tempor mattis. Orci varius
|
||||||
|
natoque penatibus et magnis dis parturient montes, nascetur
|
||||||
|
ridiculus mus. Aenean viverra semper sapien. Nulla finibus nec metus
|
||||||
|
id molestie. Proin scelerisque venenatis enim, et maximus velit
|
||||||
|
imperdiet vel. Vestibulum sit amet nisi vel justo pharetra efficitur
|
||||||
|
sit amet ac elit. Donec feugiat id ante sit amet fermentum.
|
||||||
|
Pellentesque rhoncus ultricies erat, sit amet ultrices magna
|
||||||
|
condimentum ut. Donec vulputate efficitur augue a placerat.
|
||||||
|
|
||||||
|
Integer pulvinar erat ut ipsum ultrices, in posuere urna rhoncus.
|
||||||
|
Sed vestibulum nisl a magna volutpat, quis sodales leo vehicula.
|
||||||
|
Morbi tincidunt urna sed nisl feugiat, vel commodo nulla tincidunt.
|
||||||
|
Cras gravida massa et rutrum imperdiet. Proin eget iaculis urna. In
|
||||||
|
hac habitasse platea dictumst. Nullam consectetur ante sit amet
|
||||||
|
tortor ornare porttitor. Duis quis eros lorem. Morbi pulvinar
|
||||||
|
elementum purus, eget eleifend felis eleifend luctus. Sed iaculis
|
||||||
|
feugiat ligula, a hendrerit dui aliquet at. Aliquam erat volutpat.
|
||||||
|
Suspendisse id volutpat nisl, id iaculis ex. Morbi vehicula tellus a
|
||||||
|
arcu efficitur, et vehicula lectus vestibulum. Praesent sed
|
||||||
|
imperdiet dolor.
|
||||||
|
|
||||||
|
Nunc condimentum odio nec placerat auctor. Nam posuere condimentum
|
||||||
|
velit quis porttitor. Phasellus vitae enim et ex sodales lobortis
|
||||||
|
vel quis sapien. Maecenas at venenatis ante, sit amet elementum
|
||||||
|
risus. In lorem magna, fringilla fermentum diam sit amet, imperdiet
|
||||||
|
sollicitudin dui. Quisque eros magna, auctor ac hendrerit venenatis,
|
||||||
|
porta a lacus. Donec neque ligula, euismod nec mauris et, varius
|
||||||
|
commodo dolor. Etiam pharetra libero massa, eu congue metus
|
||||||
|
venenatis et. Nullam eu efficitur ligula. Suspendisse at scelerisque
|
||||||
|
libero, nec consequat nisl. In dignissim finibus nisl, volutpat
|
||||||
|
efficitur tellus scelerisque vitae. Phasellus quam mauris, bibendum
|
||||||
|
ac pretium nec, venenatis eget ipsum.
|
||||||
|
|
||||||
|
Fusce eu risus porttitor eros venenatis ornare vel nec dui. Integer
|
||||||
|
feugiat non diam a molestie. Donec convallis turpis at orci
|
||||||
|
lobortis, id bibendum turpis posuere. Aenean quis lacus elementum,
|
||||||
|
condimentum elit ut, eleifend tortor. Ut dapibus ut nibh nec
|
||||||
|
pharetra. Suspendisse quis pulvinar tortor, in congue sapien. In hac
|
||||||
|
habitasse platea dictumst. Pellentesque tincidunt blandit tellus, in
|
||||||
|
mattis nulla luctus sit amet. Aliquam erat volutpat. Nunc elit
|
||||||
|
tortor, sagittis ut porta eleifend, congue quis orci. Nam a turpis
|
||||||
|
eu nulla sagittis ullamcorper eu vitae lectus. Vestibulum bibendum
|
||||||
|
vel mi vel gravida.
|
||||||
|
|
||||||
|
Curabitur non maximus tortor. Aliquam ac est et enim vestibulum
|
||||||
|
cursus ut et magna. Class aptent taciti sociosqu ad litora torquent
|
||||||
|
per conubia nostra, per inceptos himenaeos. Sed nec nulla non ex
|
||||||
|
fringilla fringilla. Praesent accumsan eros tellus, ac venenatis
|
||||||
|
eros maximus in. Etiam ipsum felis, congue ut risus in, feugiat
|
||||||
|
ornare ante. Aliquam sed fringilla lectus. Aenean semper, odio vel
|
||||||
|
ultricies laoreet, est erat faucibus mi, sit amet tincidunt nunc dui
|
||||||
|
sit amet arcu. Proin feugiat augue diam, sed rutrum dui congue ac.
|
||||||
|
Nullam laoreet neque nunc, sed volutpat justo maximus ac. Sed eu
|
||||||
|
turpis aliquam, laoreet orci vitae, dictum ipsum. Quisque at
|
||||||
|
placerat orci. Suspendisse vulputate, erat eget pretium placerat,
|
||||||
|
metus magna consectetur metus, id rutrum neque est sed turpis. Nulla
|
||||||
|
pretium et lacus vel cursus.
|
||||||
|
|
||||||
|
Maecenas quis libero mollis, commodo mi id, placerat nisl. Sed a
|
||||||
|
neque vel dui faucibus semper. Duis ullamcorper, libero at porta
|
||||||
|
convallis, lectus odio malesuada nunc, a tempus turpis ipsum at ex.
|
||||||
|
Nullam enim leo, hendrerit a quam vel, finibus auctor dui. Mauris
|
||||||
|
quis sem in nulla ornare pharetra vitae ut augue. Vivamus quis
|
||||||
|
tincidunt tortor, at imperdiet augue. Mauris augue augue, varius
|
||||||
|
vitae sapien et, efficitur rhoncus mi. Orci varius natoque penatibus
|
||||||
|
et magnis dis parturient montes, nascetur ridiculus mus. Cras ac
|
||||||
|
enim at est molestie elementum.
|
||||||
|
|
||||||
|
Duis viverra quam ut nibh sodales accumsan. In hac habitasse platea
|
||||||
|
dictumst. Sed a eros id elit malesuada ultrices. Quisque et diam
|
||||||
|
justo. Pellentesque eu placerat ante, sit amet sagittis sapien. Nam
|
||||||
|
sed sollicitudin urna. Proin non libero ut metus eleifend tempus.
|
||||||
|
Sed in augue ligula. Suspendisse potenti. In eu fermentum augue.
|
||||||
|
Aliquam sem ex, congue a condimentum ac, maximus a est. Integer in
|
||||||
|
dui non lectus molestie auctor. Nullam mollis pellentesque semper.
|
||||||
|
Etiam id neque facilisis, tristique sem et, porttitor purus.
|
||||||
|
Praesent aliquam, nisi vel porttitor blandit, risus felis lobortis
|
||||||
|
arcu, eu porttitor orci enim nec tortor. Maecenas id ante eget nisl
|
||||||
|
pulvinar feugiat ac vel ante.
|
||||||
|
|
||||||
|
Nam porttitor eleifend nisl. Vivamus ac aliquam lacus. Suspendisse
|
||||||
|
facilisis arcu vel consectetur efficitur. Fusce sodales mollis
|
||||||
|
auctor. Aenean nec sem a elit lobortis maximus tincidunt ac lorem.
|
||||||
|
Proin dolor quam, volutpat id aliquet eu, faucibus ut urna. Quisque
|
||||||
|
orci eros, blandit ut consequat vitae, convallis egestas libero.
|
||||||
|
Nunc interdum elit id dui congue consequat. Maecenas volutpat odio
|
||||||
|
diam. In tincidunt efficitur ultrices. Orci varius natoque penatibus
|
||||||
|
et magnis dis parturient montes, nascetur ridiculus mus. Mauris eget
|
||||||
|
faucibus leo. Cras rhoncus accumsan ante nec tempor. Class aptent
|
||||||
|
taciti sociosqu ad litora torquent per conubia nostra, per inceptos
|
||||||
|
himenaeos.
|
||||||
|
|
||||||
|
Cras sit amet blandit mi. Cras ac mi pulvinar, aliquet ex quis,
|
||||||
|
mollis nisi. Duis a interdum libero. Vivamus sit amet felis in ante
|
||||||
|
cursus gravida eget quis lectus. Praesent vehicula tortor accumsan
|
||||||
|
lectus pellentesque, in facilisis nisi fermentum. Mauris faucibus
|
||||||
|
vulputate sapien non semper. Vestibulum tristique interdum dolor, id
|
||||||
|
accumsan dolor malesuada et. Donec a porta augue.
|
||||||
|
|
||||||
|
Nunc eu urna quis nulla consequat sagittis. Nullam eleifend
|
||||||
|
tincidunt sapien in mattis. Praesent faucibus nibh at tortor
|
||||||
|
malesuada, ut lobortis nisi pulvinar. Morbi congue ullamcorper
|
||||||
|
ipsum, nec accumsan est imperdiet eu. Aenean sit amet finibus erat,
|
||||||
|
quis porta felis. Sed sollicitudin erat nec consequat faucibus. Nam
|
||||||
|
eleifend rutrum orci at commodo. Quisque est mi, gravida ut ultrices
|
||||||
|
sit amet, hendrerit quis velit. Aenean dignissim consequat magna,
|
||||||
|
non ornare lectus facilisis eu.
|
||||||
|
|
||||||
|
Maecenas vel risus fringilla, fermentum lacus vel, laoreet leo. Sed
|
||||||
|
ultricies, odio id ullamcorper consectetur, elit massa maximus
|
||||||
|
ligula, vitae lacinia libero est sed justo. Integer eget lectus eu
|
||||||
|
augue iaculis egestas. Nullam feugiat nisl metus, quis mollis dolor
|
||||||
|
suscipit at. Nulla ac nulla ultricies, fermentum turpis sit amet,
|
||||||
|
aliquam augue. Nulla quis vulputate nisi. Morbi dolor lectus,
|
||||||
|
lacinia vitae leo id, fringilla porttitor sapien.
|
||||||
|
|
||||||
|
Donec vestibulum, est sit amet auctor vestibulum, eros orci iaculis
|
||||||
|
lacus, a efficitur lectus odio non mi. Nullam cursus purus vitae
|
||||||
|
ante cursus, sed pulvinar magna condimentum. Suspendisse dignissim
|
||||||
|
lorem non lacus cursus, quis lacinia eros semper. Integer aliquam
|
||||||
|
felis iaculis sollicitudin vestibulum. Pellentesque ornare mi quam,
|
||||||
|
ac pellentesque mi molestie vel. Mauris vel sapien ultricies mauris
|
||||||
|
hendrerit vestibulum in at ligula. Morbi id velit vitae libero
|
||||||
|
molestie elementum. Vivamus maximus orci vel ante sodales, ut
|
||||||
|
pharetra erat egestas. Vivamus lacinia congue purus, nec volutpat
|
||||||
|
felis pulvinar egestas. Nam blandit venenatis aliquam. Nullam a
|
||||||
|
lorem et est sollicitudin pretium sed eget ex. Vivamus a quam est.
|
||||||
|
Aliquam tristique volutpat magna, aliquet volutpat lorem fermentum
|
||||||
|
sagittis.
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { useToast } from "primevue/usetoast";
|
|
||||||
|
|
||||||
const toast = useToast();
|
|
||||||
|
|
||||||
async function showToast() {
|
|
||||||
toast.add({ severity: "success", summary: "This is a toast", detail: "Wow!", life: 3000 });
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|||||||
+5
-1
@@ -1,4 +1,8 @@
|
|||||||
{
|
{
|
||||||
// https://nuxt.com/docs/guide/concepts/typescript
|
// https://nuxt.com/docs/guide/concepts/typescript
|
||||||
"extends": "./.nuxt/tsconfig.json"
|
"extends": "./.nuxt/tsconfig.json",
|
||||||
|
"include": ["components.d.ts"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"types": ["unplugin-icons/types/vue"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user