Gisle Aune
4 years ago
5 changed files with 180 additions and 185 deletions
-
2svelte-ui/public/global.css
-
93svelte-ui/src/components/GroupEntry.svelte
-
22svelte-ui/src/components/LinkHook.svelte
-
120svelte-ui/src/components/ParentEntry.svelte
-
128svelte-ui/src/components/ProjectEntry.svelte
@ -1,96 +1,35 @@ |
|||
<script lang="ts"> |
|||
import { onMount } from "svelte"; |
|||
import type { IconName } from "../external/icons"; |
|||
import type { GroupResult } from "../models/group"; |
|||
import type { ModalData } from "../stores/modal"; |
|||
import Icon from "./Icon.svelte"; |
|||
import ItemEntry from "./ItemEntry.svelte"; |
|||
import Option from "./Option.svelte"; |
|||
import OptionRow from "./OptionRow.svelte"; |
|||
import ParentEntry from "./ParentEntry.svelte"; |
|||
|
|||
export let group: GroupResult = null; |
|||
export let showAllOptions: boolean = false; |
|||
|
|||
let iconName: IconName = "question"; |
|||
let mdItemAdd: ModalData; |
|||
let mdGroupEdit: ModalData; |
|||
let mdGroupDelete: ModalData; |
|||
let linkHook: HTMLElement; |
|||
|
|||
onMount(() => { |
|||
if (window.location.hash === "#" + group.id) { |
|||
window.scrollTo({top: linkHook.getBoundingClientRect().top}); |
|||
} |
|||
}); |
|||
|
|||
$: iconName = group.icon as IconName; |
|||
$: mdItemAdd = {name:"item.add", group}; |
|||
$: mdGroupEdit = {name:"group.edit", group}; |
|||
$: mdGroupDelete = {name:"group.delete", group}; |
|||
</script> |
|||
|
|||
<div class="group"> |
|||
<div class="link-hook" id={group.id} bind:this={linkHook}></div> |
|||
<div class="icon"><Icon block name={iconName} /></div> |
|||
<div class="body"> |
|||
<div class="header"> |
|||
<div class="name">{group.name}</div> |
|||
</div> |
|||
{#if showAllOptions} |
|||
<div class="description"> |
|||
<p>{group.description}</p> |
|||
</div> |
|||
<OptionRow> |
|||
<Option open={mdItemAdd}>Add Item</Option> |
|||
<Option open={mdGroupEdit}>Edit</Option> |
|||
<Option open={mdGroupDelete}>Delete</Option> |
|||
</OptionRow> |
|||
{/if} |
|||
<div class="list" class:full={showAllOptions}> |
|||
{#each group.items as item (item.id)} |
|||
<ItemEntry item={item} group={group} /> |
|||
{/each} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<style> |
|||
div.link-hook { |
|||
position: relative; |
|||
top: -2em; |
|||
} |
|||
|
|||
div.group { |
|||
display: flex; |
|||
flex-direction: row; |
|||
padding-bottom: 1em; |
|||
} |
|||
div.icon { |
|||
font-size: 2em; |
|||
padding: 0 0.5ch; |
|||
width: 2ch; |
|||
padding-top: 0.125em; |
|||
color: #333; |
|||
} |
|||
div.body { |
|||
display: flex; |
|||
flex-direction: column; |
|||
width: 100%; |
|||
} |
|||
div.header { |
|||
display: flex; |
|||
flex-direction: row; |
|||
} |
|||
|
|||
div.name { |
|||
font-size: 1em; |
|||
font-weight: 100; |
|||
margin: auto 0; |
|||
vertical-align: middle; |
|||
} |
|||
|
|||
div.description > p { |
|||
padding: 0; |
|||
margin: 0.25em 0; |
|||
} |
|||
</style> |
|||
<ParentEntry |
|||
full={showAllOptions} |
|||
entry={group} |
|||
> |
|||
{#if showAllOptions} |
|||
<OptionRow> |
|||
<Option open={mdItemAdd}>Add Item</Option> |
|||
<Option open={mdGroupEdit}>Edit</Option> |
|||
<Option open={mdGroupDelete}>Delete</Option> |
|||
</OptionRow> |
|||
{#each group.items as item (item.id)} |
|||
<ItemEntry item={item} group={group} /> |
|||
{/each} |
|||
{/if} |
|||
</ParentEntry> |
@ -0,0 +1,22 @@ |
|||
<script lang="ts"> |
|||
import { onMount } from "svelte"; |
|||
|
|||
export let id = ""; |
|||
|
|||
let linkHook: HTMLElement; |
|||
|
|||
onMount(() => { |
|||
if (window.location.hash === "#" + id) { |
|||
window.scrollTo({top: linkHook.getBoundingClientRect().top}); |
|||
} |
|||
}); |
|||
</script> |
|||
|
|||
<div class="link-hook" id={id} bind:this={linkHook}></div> |
|||
|
|||
<style> |
|||
div.link-hook { |
|||
position: relative; |
|||
top: -2em; |
|||
} |
|||
</style> |
@ -0,0 +1,120 @@ |
|||
<script lang="ts"> |
|||
import type { IconName } from "../external/icons"; |
|||
import DaysLeft from "./DaysLeft.svelte"; |
|||
import Icon from "./Icon.svelte"; |
|||
import LinkHook from "./LinkHook.svelte"; |
|||
import Progress from "./Progress.svelte"; |
|||
|
|||
interface EntryIconHolder { |
|||
icon: IconName |
|||
} |
|||
|
|||
interface EntryCommon { |
|||
id: string |
|||
name: string |
|||
description: string |
|||
icon?: IconName |
|||
startTime?: string |
|||
endTime?: string |
|||
createdTime?: string |
|||
group?: EntryIconHolder |
|||
project?: EntryIconHolder |
|||
} |
|||
|
|||
export let entry: EntryCommon; |
|||
export let full = false; |
|||
export let headerLink = ""; |
|||
|
|||
export let progressAmount: number = null; |
|||
export let progressTarget: number = null; |
|||
|
|||
let iconName: IconName; |
|||
|
|||
$: { |
|||
if (entry.project != null) { |
|||
iconName = entry.project.icon; |
|||
} else if (entry.group != null) { |
|||
iconName = entry.group.icon; |
|||
} else { |
|||
iconName = entry.icon || "question"; |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<div class="parent-entry" class:full={full}> |
|||
<LinkHook id={entry.id} /> |
|||
<div class="icon"><Icon block name={iconName} /></div> |
|||
<div class="body"> |
|||
<div class="header"> |
|||
<div class="name"> |
|||
{#if headerLink} |
|||
<a href={headerLink}>{entry.name}</a> |
|||
{:else} |
|||
{entry.name} |
|||
{/if} |
|||
</div> |
|||
{#if entry.endTime != null} |
|||
<div class="days-left"> |
|||
<DaysLeft startTime={entry.startTime || entry.createdTime} endTime={entry.endTime} /> |
|||
</div> |
|||
{/if} |
|||
</div> |
|||
{#if (progressAmount != null)} |
|||
<Progress thin green count={progressAmount} target={progressTarget} /> |
|||
{/if} |
|||
{#if (full)} |
|||
<div class="description"> |
|||
<p>{entry.description}</p> |
|||
</div> |
|||
{/if} |
|||
<slot></slot> |
|||
</div> |
|||
</div> |
|||
|
|||
<style> |
|||
div.parent-entry { |
|||
display: flex; |
|||
flex-direction: row; |
|||
padding-bottom: 0.5em; |
|||
} |
|||
div.parent-entry.full { |
|||
padding-bottom: 1em; |
|||
} |
|||
div.icon { |
|||
font-size: 2em; |
|||
padding: 0 0.5ch; |
|||
width: 2ch; |
|||
padding-top: 0.125em; |
|||
color: #333; |
|||
} |
|||
div.body { |
|||
display: flex; |
|||
flex-direction: column; |
|||
width: 100%; |
|||
} |
|||
div.header { |
|||
display: flex; |
|||
flex-direction: row; |
|||
} |
|||
|
|||
div.name { |
|||
font-size: 1em; |
|||
margin: auto 0; |
|||
vertical-align: middle; |
|||
font-weight: 100; |
|||
} |
|||
div.days-left { |
|||
margin-left: auto; |
|||
margin-right: 0.25ch; |
|||
} |
|||
|
|||
a { |
|||
color: inherit; |
|||
text-decoration-color: #777; |
|||
} |
|||
|
|||
div.description > p { |
|||
padding: 0; |
|||
margin: 0.25em 0; |
|||
} |
|||
</style> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue