add project progress indicator and sort front page projects by deadline.
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -11,6 +11,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let target = 1;
|
export let target = 1;
|
||||||
export let count = 0;
|
export let count = 0;
|
||||||
|
export let green = false;
|
||||||
|
export let thin = false;
|
||||||
|
|
||||||
let offClass = COLORS[0];
|
let offClass = COLORS[0];
|
||||||
let onClass = COLORS[1];
|
let onClass = COLORS[1];
|
||||||
@@ -19,7 +21,7 @@
|
|||||||
|
|
||||||
$: {
|
$: {
|
||||||
let level = Math.floor(count / target);
|
let level = Math.floor(count / target);
|
||||||
if (level >= COLORS.length - 1) {
|
if (level >= COLORS.length - 1 || (level > 1 && green)) {
|
||||||
offs = 0;
|
offs = 0;
|
||||||
ons = target;
|
ons = target;
|
||||||
offClass = "gold";
|
offClass = "gold";
|
||||||
@@ -34,10 +36,15 @@
|
|||||||
offClass = COLORS[level];
|
offClass = COLORS[level];
|
||||||
onClass = COLORS[level + 1];
|
onClass = COLORS[level + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (green) {
|
||||||
|
onClass = "green"
|
||||||
|
offClass = "none"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="bar">
|
<div class="bar" class:thin>
|
||||||
{#each {length: ons} as _}
|
{#each {length: ons} as _}
|
||||||
<div class={"on " + onClass}></div>
|
<div class={"on " + onClass}></div>
|
||||||
{/each}
|
{/each}
|
||||||
@@ -61,7 +68,7 @@
|
|||||||
flex-basis: 0;
|
flex-basis: 0;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border: 0.1px solid #000;
|
border: 1px solid #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.none { background-color: #555555; }
|
div.none { background-color: #555555; }
|
||||||
@@ -69,6 +76,7 @@
|
|||||||
div.silver { background-color: #d8dce4; }
|
div.silver { background-color: #d8dce4; }
|
||||||
div.gold { background-color: #ffd966; }
|
div.gold { background-color: #ffd966; }
|
||||||
div.diamond { background-color: #84f5ff; }
|
div.diamond { background-color: #84f5ff; }
|
||||||
|
div.green { background-color: #78ff78; }
|
||||||
|
|
||||||
div.on {
|
div.on {
|
||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
@@ -77,4 +85,8 @@
|
|||||||
div.off {
|
div.off {
|
||||||
opacity: 0.33;
|
opacity: 0.33;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.bar.thin {
|
||||||
|
height: 0.25em;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -1,31 +1,32 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { IconName } from "../external/icons";
|
|
||||||
import TaskAddForm from "../forms/TaskAddForm.svelte";
|
|
||||||
import type { ProjectResult } from "../models/project";
|
import type { ProjectResult } from "../models/project";
|
||||||
import type { ModalData } from "../stores/modal";
|
import type { ModalData } from "../stores/modal";
|
||||||
import DaysLeft from "./DaysLeft.svelte";
|
import DaysLeft from "./DaysLeft.svelte";
|
||||||
import Icon from "./Icon.svelte";
|
import Icon from "./Icon.svelte";
|
||||||
import Option from "./Option.svelte";
|
import Option from "./Option.svelte";
|
||||||
import OptionRow from "./OptionRow.svelte";
|
import OptionRow from "./OptionRow.svelte";
|
||||||
|
import Progress from "./Progress.svelte";
|
||||||
import TaskEntry from "./TaskEntry.svelte";
|
import TaskEntry from "./TaskEntry.svelte";
|
||||||
|
|
||||||
export let project: ProjectResult = null;
|
export let project: ProjectResult = null;
|
||||||
export let showAllOptions: boolean = false;
|
export let showAllOptions: boolean = false;
|
||||||
export let hideInactive: boolean = false;
|
export let hideInactive: boolean = false;
|
||||||
|
|
||||||
let iconName: IconName = "question";
|
|
||||||
let mdAddTask: ModalData;
|
let mdAddTask: ModalData;
|
||||||
let mdProjectEdit: ModalData;
|
let mdProjectEdit: ModalData;
|
||||||
let mdProjectDelete: ModalData;
|
let mdProjectDelete: ModalData;
|
||||||
|
let progressAmount: number;
|
||||||
|
let progressTarget: number;
|
||||||
|
|
||||||
$: iconName = project.icon as IconName;
|
|
||||||
$: mdAddTask = {name:"task.add", project};
|
$: mdAddTask = {name:"task.add", project};
|
||||||
$: mdProjectEdit = {name:"project.edit", project};
|
$: mdProjectEdit = {name:"project.edit", project};
|
||||||
$: mdProjectDelete = {name:"project.delete", project};
|
$: mdProjectDelete = {name:"project.delete", project};
|
||||||
|
$: progressAmount = project.tasks.map(t => Math.min(t.completedAmount, t.itemAmount) * t.item.groupWeight).reduce((n,m) => n+m, 0);
|
||||||
|
$: progressTarget = Math.max(project.tasks.map(t => t.itemAmount * t.item.groupWeight).reduce((n,m) => n+m, 0), 1);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="project">
|
<div class="project">
|
||||||
<div class="icon" class:inactive={!project.active}><Icon block name={iconName} /></div>
|
<div class="icon" class:inactive={!project.active}><Icon block name={project.icon} /></div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="name">{project.name}</div>
|
<div class="name">{project.name}</div>
|
||||||
@@ -35,6 +36,7 @@ import TaskAddForm from "../forms/TaskAddForm.svelte";
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
<Progress thin green count={progressAmount} target={progressTarget} />
|
||||||
{#if showAllOptions}
|
{#if showAllOptions}
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<p>{project.description}</p>
|
<p>{project.description}</p>
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
export let task: TaskResult = null;
|
export let task: TaskResult = null;
|
||||||
export let showAllOptions: boolean = false;
|
export let showAllOptions: boolean = false;
|
||||||
|
|
||||||
let itomIconName: IconName = "question";
|
|
||||||
let showLogs = false;
|
let showLogs = false;
|
||||||
let mdLogAdd: ModalData;
|
let mdLogAdd: ModalData;
|
||||||
let mdTaskEdit: ModalData;
|
let mdTaskEdit: ModalData;
|
||||||
@@ -21,7 +20,6 @@
|
|||||||
showLogs = !showLogs;
|
showLogs = !showLogs;
|
||||||
}
|
}
|
||||||
|
|
||||||
$: itomIconName = task.item.icon as IconName;
|
|
||||||
$: mdLogAdd = {name: "log.add", task};
|
$: mdLogAdd = {name: "log.add", task};
|
||||||
$: mdTaskEdit = {name: "task.edit", task};
|
$: mdTaskEdit = {name: "task.edit", task};
|
||||||
$: mdTaskDelete = {name: "task.delete", task};
|
$: mdTaskDelete = {name: "task.delete", task};
|
||||||
@@ -53,7 +51,7 @@
|
|||||||
<p>{task.description}</p>
|
<p>{task.description}</p>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="item-icon">
|
<div class="item-icon">
|
||||||
<Icon name={itomIconName} />
|
<Icon name={task.item.icon} />
|
||||||
</div>
|
</div>
|
||||||
<div class="item-name">{task.item.name} ({task.item.groupWeight})</div>
|
<div class="item-name">{task.item.name} ({task.item.groupWeight})</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,10 +4,11 @@
|
|||||||
import ProjectEntry from "../components/ProjectEntry.svelte";
|
import ProjectEntry from "../components/ProjectEntry.svelte";
|
||||||
import type { ProjectResult } from "../models/project";
|
import type { ProjectResult } from "../models/project";
|
||||||
import { fpGoalStore } from "../stores/goal";
|
import { fpGoalStore } from "../stores/goal";
|
||||||
import { fpProjectStore } from "../stores/project";
|
import projectStore, { fpProjectStore } from "../stores/project";
|
||||||
import { fpTaskStore } from "../stores/tasks";
|
import taskStore, { fpTaskStore } from "../stores/tasks";
|
||||||
|
|
||||||
let fakeProject: ProjectResult
|
let fakeProject: ProjectResult
|
||||||
|
let sortedProjects: ProjectResult[]
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if ($fpGoalStore.stale && !$fpGoalStore.loading) {
|
if ($fpGoalStore.stale && !$fpGoalStore.loading) {
|
||||||
@@ -44,12 +45,22 @@
|
|||||||
description: "",
|
description: "",
|
||||||
icon: "list",
|
icon: "list",
|
||||||
name: "Individual Tasks",
|
name: "Individual Tasks",
|
||||||
tasks: $fpTaskStore.tasks.filter(t => $fpProjectStore.projects.find(p => p.id === t.id) == null),
|
tasks: $fpTaskStore.tasks.filter(t => $fpProjectStore.projects.find(p => p.id === t.id) == null)
|
||||||
|
.sort((a,b) => Date.parse(a.endTime) - Date.parse(b.endTime)),
|
||||||
endTime: null,
|
endTime: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fakeProject.tasks.length > 0) {
|
||||||
|
fakeProject.endTime = fakeProject.tasks[0].endTime;
|
||||||
|
}
|
||||||
|
|
||||||
console.log(fakeProject, $fpTaskStore);
|
console.log(fakeProject, $fpTaskStore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: {
|
||||||
|
const projects = fakeProject.tasks.length > 0 ? [...$fpProjectStore.projects, fakeProject] : [...$fpProjectStore.projects];
|
||||||
|
sortedProjects = projects.sort((a,b) => Date.parse(a.endTime) - Date.parse(b.endTime));
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="page">
|
<div class="page">
|
||||||
@@ -68,12 +79,9 @@
|
|||||||
{#if !$fpProjectStore.loading || $fpProjectStore.projects.length > 0}
|
{#if !$fpProjectStore.loading || $fpProjectStore.projects.length > 0}
|
||||||
<h1>Upcoming Deadlines</h1>
|
<h1>Upcoming Deadlines</h1>
|
||||||
{/if}
|
{/if}
|
||||||
{#each $fpProjectStore.projects as project (project.id)}
|
{#each sortedProjects as project (project.id)}
|
||||||
<ProjectEntry hideInactive project={project} />
|
<ProjectEntry hideInactive project={project} />
|
||||||
{/each}
|
{/each}
|
||||||
{#if fakeProject.tasks.length > 0}
|
|
||||||
<ProjectEntry project={fakeProject} />
|
|
||||||
{/if}
|
|
||||||
{#if fakeProject.tasks.length === 0 && !$fpProjectStore.loading && $fpProjectStore.projects.length === 0}
|
{#if fakeProject.tasks.length === 0 && !$fpProjectStore.loading && $fpProjectStore.projects.length === 0}
|
||||||
<EmptyList icon="check" text="All good!" />
|
<EmptyList icon="check" text="All good!" />
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
Reference in New Issue
Block a user