diff options
| author | ivarlovlie <git@ivarlovlie.no> | 2022-10-11 06:57:36 +0200 |
|---|---|---|
| committer | ivarlovlie <git@ivarlovlie.no> | 2022-10-11 06:57:36 +0200 |
| commit | 4e8f0c96904f9915c6bc6e50f12e5094f924759c (patch) | |
| tree | edbfb45a80878636fa04afe516e892ed4aefd594 /code/app/src/routes/(main) | |
| parent | afbe98090a90ae7770c3a319b8a30c1d23cfbbc3 (diff) | |
| download | greatoffice-4e8f0c96904f9915c6bc6e50f12e5094f924759c.tar.xz greatoffice-4e8f0c96904f9915c6bc6e50f12e5094f924759c.zip | |
feat: !WIP projects table
- Sorting
- Filtering
- Project status badge
Diffstat (limited to 'code/app/src/routes/(main)')
| -rw-r--r-- | code/app/src/routes/(main)/(app)/projects/+page.svelte | 75 | ||||
| -rw-r--r-- | code/app/src/routes/(main)/(app)/projects/[id]/+page.svelte | 5 |
2 files changed, 67 insertions, 13 deletions
diff --git a/code/app/src/routes/(main)/(app)/projects/+page.svelte b/code/app/src/routes/(main)/(app)/projects/+page.svelte index ad273ab..ceb08b4 100644 --- a/code/app/src/routes/(main)/(app)/projects/+page.svelte +++ b/code/app/src/routes/(main)/(app)/projects/+page.svelte @@ -1,13 +1,16 @@ <script lang="ts"> - import { Button } from "$lib/components"; + import { Button, ProjectStatusBadge, Input } from "$lib/components"; import type { Project } from "$lib/models/projects/Project"; import { onMount } from "svelte"; import { faker } from "@faker-js/faker"; import { Temporal } from "temporal-polyfill"; import { createTable, Subscribe, Render } from "svelte-headless-table"; + import { addSortBy, addTableFilter } from "svelte-headless-table/plugins"; import { ProjectStatus } from "$lib/models/projects/ProjectStatus"; import { writable, type Writable } from "svelte/store"; + import { ChevronDownIcon, ChevronUpIcon, ChevronUpDownIcon, MagnifyingGlassIcon, FunnelIcon } from "$lib/components/icons"; import LL from "$lib/i18n/i18n-svelte"; + import { goto } from "$app/navigation"; let projects: Writable<Array<Project>> = writable([]); @@ -28,37 +31,75 @@ projects.set(tempProjects); }); - const table = createTable(projects); + function goto_project(name: string) { + const projectId = $projects.find((p) => p.name === name).id; + goto("/projects/" + projectId); + } + + const table = createTable(projects, { + sort: addSortBy(), + filter: addTableFilter(), + }); + const columns = table.createColumns([ table.column({ header: $LL.name(), accessor: "name" }), table.column({ header: "Status", accessor: "status" }), table.column({ header: "Start", accessor: "start" }), - table.column({ header: "Description", accessor: "description" }), + table.column({ header: "Description", accessor: "description", plugins: { sort: { disable: true } } }), ]); - const { headerRows, rows, tableAttrs, tableBodyAttrs } = table.createViewModel(columns); + const { headerRows, rows, tableAttrs, tableBodyAttrs, pluginStates } = table.createViewModel(columns); + const { filterValue } = pluginStates.filter; </script> -<div class="px-4 sm:px-6 lg:px-8"> +<div class="py-2 px-5"> <div class="sm:flex sm:items-center"> <div class="sm:flex-auto"> <h1 class="text-xl font-semibold text-gray-900">Projects</h1> <p class="mt-2 text-sm text-gray-700">A list of all the projects in your organsation.</p> </div> - <div class="mt-4 sm:mt-0 sm:ml-16 sm:flex-none"> + <div class="mt-4 sm:mt-0 sm:ml-16 inline-flex gap-1 sm:flex-none"> + <Input icon={MagnifyingGlassIcon} placeholder="Search" bind:value={$filterValue} /> <Button text="Create project" /> </div> </div> - <div class="-mx-4 mt-8 overflow-hidden sm:-mx-6 md:mx-0 MuonW PowerTable"> + <div class="-mx-2 mt-6 rounded-md shadow overflow-auto max-h-[80vh] sm:-mx-6 md:mx-0"> <table {...$tableAttrs} class="min-w-full divide-y divide-gray-300"> <thead class="bg-gray-50"> {#each $headerRows as headerRow (headerRow.id)} <Subscribe rowAttrs={headerRow.attrs()} let:rowAttrs> - <tr {...rowAttrs}> + <tr {...rowAttrs} class="shadow-sm"> {#each headerRow.cells as cell (cell.id)} - <Subscribe attrs={cell.attrs()} let:attrs> - <th {...attrs} class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6"> - <Render of={cell.render()} /> + <Subscribe attrs={cell.attrs()} let:attrs props={cell.props()} let:props> + <th + {...attrs} + scope="col" + class="sticky top-0 bg-gray-50 bg-opacity-100 whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-gray-900" + > + <div class="group inline-flex"> + <Render of={cell.render()} /> + <span + on:click={props.sort.toggle} + class="{props.sort.disabled + ? 'bg-gray-200 text-gray-900 group-hover:bg-gray-300' + : 'invisible text-gray-400 group-hover:visible group-focus:visible'} + {props.sort.disabled ? '' : 'cursor-pointer'} + ml-2 flex-none rounded" + > + {#if props.sort.order === "asc"} + <ChevronUpIcon /> + {:else if props.sort.order === "desc"} + <ChevronDownIcon /> + {:else if !props.sort.disabled} + <ChevronUpDownIcon /> + {/if} + </span> + {#if cell.id === "status"} + <span class="invisible text-gray-400 cursor-pointer group-hover:visible group-focus:visible ml-2 flex-none rounded"> + <FunnelIcon /> + </span> + {/if} + </div> </th> </Subscribe> {/each} @@ -73,8 +114,16 @@ {#each row.cells as cell (cell.id)} {@const materialisedCell = cell.render()} <Subscribe attrs={cell.attrs()} let:attrs> - <td class="w-full max-w-0 py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:w-auto sm:max-w-none sm:pl-6" {...attrs}> - <Render of={materialisedCell} /> + <td {...attrs} class="whitespace-nowrap px-2 py-2 text-sm"> + {#if cell.id === "name"} + <span class="link" title="Open project" on:click={() => goto_project(materialisedCell.toString())}> + <Render of={materialisedCell} /> + </span> + {:else if cell.id === "status"} + <ProjectStatusBadge status={materialisedCell.toString()} /> + {:else} + <Render of={materialisedCell} /> + {/if} </td> </Subscribe> {/each} diff --git a/code/app/src/routes/(main)/(app)/projects/[id]/+page.svelte b/code/app/src/routes/(main)/(app)/projects/[id]/+page.svelte new file mode 100644 index 0000000..ca474e2 --- /dev/null +++ b/code/app/src/routes/(main)/(app)/projects/[id]/+page.svelte @@ -0,0 +1,5 @@ +<script lang="ts"> + import { page } from "$app/stores"; +</script> + +<h1>{$page.params.id}</h1> |
