This commit is contained in:
@@ -51,7 +51,7 @@ func (r *taskRepository) List(ctx context.Context, filter models.TaskFilter) ([]
|
|||||||
}
|
}
|
||||||
|
|
||||||
sq = sq.InnerJoin("project AS p ON task.project_id = p.project_id")
|
sq = sq.InnerJoin("project AS p ON task.project_id = p.project_id")
|
||||||
sq = sq.OrderBy("created_time")
|
sq = sq.OrderBy("active DESC", "created_time")
|
||||||
|
|
||||||
query, args, err := sq.ToSql()
|
query, args, err := sq.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
import LogsPage from "./pages/LogsPage.svelte";
|
import LogsPage from "./pages/LogsPage.svelte";
|
||||||
import GroupPage from "./pages/GroupPage.svelte";
|
import GroupPage from "./pages/GroupPage.svelte";
|
||||||
import GoalPage from "./pages/GoalPage.svelte";
|
import GoalPage from "./pages/GoalPage.svelte";
|
||||||
|
import QlPage from "./pages/QLPage.svelte";
|
||||||
|
|
||||||
import GroupForm from "./forms/GroupForm.svelte";
|
import GroupForm from "./forms/GroupForm.svelte";
|
||||||
import GoalForm from "./forms/GoalForm.svelte";
|
import GoalForm from "./forms/GoalForm.svelte";
|
||||||
@@ -36,6 +37,7 @@
|
|||||||
<Route path="/" component={FrontPage} />
|
<Route path="/" component={FrontPage} />
|
||||||
<Route path="/goals/" component={GoalPage} />
|
<Route path="/goals/" component={GoalPage} />
|
||||||
<Route path="/projects/" component={ProjectPage} />
|
<Route path="/projects/" component={ProjectPage} />
|
||||||
|
<Route path="/questlog/" component={QlPage} />
|
||||||
<Route path="/logs/" component={LogsPage} />
|
<Route path="/logs/" component={LogsPage} />
|
||||||
<Route path="/items/" component={GroupPage} />
|
<Route path="/items/" component={GroupPage} />
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { link } from "svelte-routing";
|
import { link } from "svelte-routing";
|
||||||
|
import selectionStore from "../stores/selection";
|
||||||
|
|
||||||
export let location: string = window.location.pathname.split("?")[0];
|
export let location: string = window.location.pathname.split("?")[0];
|
||||||
|
|
||||||
@@ -9,19 +10,23 @@
|
|||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: console.log($selectionStore);
|
||||||
|
|
||||||
$: selected = {
|
$: selected = {
|
||||||
home: location == "/",
|
home: $selectionStore.path === "/",
|
||||||
goals: location.startsWith("/goals"),
|
goals: $selectionStore.path.startsWith("/goals"),
|
||||||
projects: location.startsWith("/projects"),
|
questlog: $selectionStore.path.startsWith("/questlog"),
|
||||||
items: location.startsWith("/items"),
|
projects: $selectionStore.path.startsWith("/projects"),
|
||||||
logs: location.startsWith("/logs"),
|
items: $selectionStore.path.startsWith("/items"),
|
||||||
|
logs: $selectionStore.path.startsWith("/logs"),
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
<a on:click={updateLocation} class:selected={selected.home} use:link href="/">Stufflog</a>
|
<a on:click={updateLocation} class:selected={selected.home} use:link href="/">Stufflog</a>
|
||||||
<a on:click={updateLocation} class:selected={selected.goals} use:link href="/goals">Goals</a>
|
<a on:click={updateLocation} class:selected={selected.goals} use:link href="/goals">Goals</a>
|
||||||
<a on:click={updateLocation} class:selected={selected.projects} use:link href="/projects">Projects</a>
|
<a class="desktop" on:click={updateLocation} class:selected={selected.questlog} use:link href="/questlog">Projects</a>
|
||||||
|
<a class="mobile" on:click={updateLocation} class:selected={selected.projects} use:link href="/projects">Projects</a>
|
||||||
<a on:click={updateLocation} class:selected={selected.items} use:link href="/items">Items</a>
|
<a on:click={updateLocation} class:selected={selected.items} use:link href="/items">Items</a>
|
||||||
<a on:click={updateLocation} class:selected={selected.logs} use:link href="/logs">Logs</a>
|
<a on:click={updateLocation} class:selected={selected.logs} use:link href="/logs">Logs</a>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -41,4 +46,17 @@
|
|||||||
a.selected {
|
a.selected {
|
||||||
color: #AAA;
|
color: #AAA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.mobile {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
a.mobile {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
a.desktop {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { IconName } from "../external/icons";
|
import type { IconName } from "../external/icons";
|
||||||
|
import type { TaskResult } from "../models/task";
|
||||||
import DaysLeft from "./DaysLeft.svelte";
|
import DaysLeft from "./DaysLeft.svelte";
|
||||||
import Icon from "./Icon.svelte";
|
import Icon from "./Icon.svelte";
|
||||||
import LinkHook from "./LinkHook.svelte";
|
import LinkHook from "./LinkHook.svelte";
|
||||||
import Markdown from "./Markdown.svelte";
|
import Markdown from "./Markdown.svelte";
|
||||||
import Progress from "./Progress.svelte";
|
import ProjectProgress from "./ProjectProgress.svelte";
|
||||||
|
|
||||||
interface EntryIconHolder {
|
interface EntryIconHolder {
|
||||||
icon: IconName
|
icon: IconName
|
||||||
@@ -20,14 +21,15 @@
|
|||||||
createdTime?: string
|
createdTime?: string
|
||||||
group?: EntryIconHolder
|
group?: EntryIconHolder
|
||||||
project?: EntryIconHolder
|
project?: EntryIconHolder
|
||||||
|
tasks?: TaskResult[]
|
||||||
|
active?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export let entry: EntryCommon;
|
export let entry: EntryCommon;
|
||||||
export let full = false;
|
export let full = false;
|
||||||
export let headerLink = "";
|
export let headerLink = "";
|
||||||
|
export let hideProgress: boolean = false;
|
||||||
export let progressAmount: number = null;
|
export let hideIcon: boolean = false;
|
||||||
export let progressTarget: number = null;
|
|
||||||
|
|
||||||
let iconName: IconName;
|
let iconName: IconName;
|
||||||
|
|
||||||
@@ -44,7 +46,11 @@
|
|||||||
|
|
||||||
<div class="parent-entry" class:full={full}>
|
<div class="parent-entry" class:full={full}>
|
||||||
<LinkHook id={entry.id} />
|
<LinkHook id={entry.id} />
|
||||||
<div class="icon"><Icon block name={iconName} /></div>
|
{#if !hideIcon}
|
||||||
|
<div class="icon" class:completed={entry.active === false}>
|
||||||
|
<Icon block name={iconName} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="name">
|
<div class="name">
|
||||||
@@ -60,8 +66,8 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if (progressAmount != null)}
|
{#if (!hideProgress && entry.tasks != null)}
|
||||||
<Progress thin green count={progressAmount} target={progressTarget} />
|
<ProjectProgress project={entry} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if (full)}
|
{#if (full)}
|
||||||
<Markdown source={entry.description} />
|
<Markdown source={entry.description} />
|
||||||
@@ -86,6 +92,9 @@
|
|||||||
padding-top: 0.125em;
|
padding-top: 0.125em;
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
div.icon.completed {
|
||||||
|
color: #484;
|
||||||
|
}
|
||||||
div.body {
|
div.body {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { ProjectResult } from "../models/project";
|
import type { ProjectResult } from "../models/project";
|
||||||
|
import type { TaskResult } from "../models/task";
|
||||||
import type { ModalData } from "../stores/modal";
|
import type { ModalData } from "../stores/modal";
|
||||||
|
import projectStore from "../stores/project";
|
||||||
|
import taskStore from "../stores/tasks";
|
||||||
import Option from "./Option.svelte";
|
import Option from "./Option.svelte";
|
||||||
import OptionRow from "./OptionRow.svelte";
|
import OptionRow from "./OptionRow.svelte";
|
||||||
import ParentEntry from "./ParentEntry.svelte";
|
import ParentEntry from "./ParentEntry.svelte";
|
||||||
@@ -9,30 +12,25 @@
|
|||||||
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;
|
||||||
|
export let hideProgress: boolean = false;
|
||||||
export let linkProject: boolean = false;
|
export let linkProject: boolean = false;
|
||||||
|
export let hideIcon: boolean = false;
|
||||||
|
|
||||||
let mdAddTask: ModalData;
|
let mdAddTask: ModalData;
|
||||||
let mdProjectEdit: ModalData;
|
let mdProjectEdit: ModalData;
|
||||||
let mdProjectDelete: ModalData;
|
let mdProjectDelete: ModalData;
|
||||||
let progressAmount: number;
|
|
||||||
let progressTarget: number;
|
|
||||||
|
|
||||||
$: 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 => t.active
|
|
||||||
? Math.min(t.completedAmount, t.itemAmount) * t.item.groupWeight
|
|
||||||
: 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>
|
||||||
|
|
||||||
<ParentEntry
|
<ParentEntry
|
||||||
full={showAllOptions}
|
full={showAllOptions}
|
||||||
entry={project}
|
entry={project}
|
||||||
headerLink={linkProject ? "/projects#"+project.id : ""}
|
headerLink={linkProject ? "/projects#"+project.id : ""}
|
||||||
progressAmount={progressAmount}
|
hideProgress={hideProgress}
|
||||||
progressTarget={progressTarget}
|
hideIcon={hideIcon}
|
||||||
>
|
>
|
||||||
{#if showAllOptions}
|
{#if showAllOptions}
|
||||||
<OptionRow>
|
<OptionRow>
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { TaskResult } from "../models/task";
|
||||||
|
import Progress from "./Progress.svelte";
|
||||||
|
|
||||||
|
interface ProjectLike {
|
||||||
|
tasks?: TaskResult[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export let project: ProjectLike;
|
||||||
|
|
||||||
|
let progressAmount: number;
|
||||||
|
let progressTarget: number;
|
||||||
|
|
||||||
|
$: progressAmount = (project.tasks||[]).map(t => t.active
|
||||||
|
? Math.min(t.completedAmount, t.itemAmount) * t.item.groupWeight
|
||||||
|
: 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>
|
||||||
|
|
||||||
|
<Progress thin green count={progressAmount} target={progressTarget} />
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { ProjectResult } from "../models/project";
|
||||||
|
import QlListItem from "./QLListItem.svelte";
|
||||||
|
|
||||||
|
export let projects: ProjectResult[];
|
||||||
|
export let label: string = "";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if projects.length > 0}
|
||||||
|
<div class="ql-list">
|
||||||
|
<h2>{label}</h2>
|
||||||
|
{#each projects as project (project.id)}
|
||||||
|
<QlListItem project={project} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div.ql-list {
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-weight: 100;
|
||||||
|
margin: 0;
|
||||||
|
padding-bottom: 0.125em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { ProjectResult } from "../models/project";
|
||||||
|
import selectionStore from "../stores/selection";
|
||||||
|
import Icon from "./Icon.svelte";
|
||||||
|
import ProjectProgress from "./ProjectProgress.svelte";
|
||||||
|
|
||||||
|
export let project: ProjectResult;
|
||||||
|
|
||||||
|
let selected: boolean;
|
||||||
|
let completed: boolean;
|
||||||
|
|
||||||
|
function handleClick() {
|
||||||
|
window.location.hash = "#" + project.id;
|
||||||
|
selectionStore.change("hash", project.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$: selected = $selectionStore.hash === project.id;
|
||||||
|
$: completed = !project.active;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="ql-list-item" on:click={handleClick} class:selected>
|
||||||
|
<div class="icon" class:completed>
|
||||||
|
<Icon block name={project.icon} />
|
||||||
|
</div>
|
||||||
|
<div class="header">
|
||||||
|
<div class="name">{project.name}</div>
|
||||||
|
<ProjectProgress project={project} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div.ql-list-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
|
||||||
|
color: #777;
|
||||||
|
padding: 0.2em;
|
||||||
|
padding-bottom: 0.05em;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
div.ql-list-item:hover {
|
||||||
|
color: #ccc;
|
||||||
|
background-color: #191919;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.ql-list-item.selected {
|
||||||
|
background-color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.icon {
|
||||||
|
color: #444;
|
||||||
|
|
||||||
|
padding: 0.3em 0.5ch;
|
||||||
|
padding-right: 1ch;
|
||||||
|
}
|
||||||
|
div.ql-list-item.selected div.icon {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
div.icon.completed {
|
||||||
|
color: #484;
|
||||||
|
}
|
||||||
|
div.ql-list-item.selected div.icon.completed {
|
||||||
|
color: #78ff78;
|
||||||
|
}
|
||||||
|
div.ql-list-item:hover div.icon {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.header {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding-right: 0.5ch;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { ProjectResult } from "../models/project";
|
||||||
|
import selectionStore from "../stores/selection";
|
||||||
|
import ProjectEntry from "./ProjectEntry.svelte";
|
||||||
|
import QlList from "./QLList.svelte";
|
||||||
|
|
||||||
|
export let projects: ProjectResult[];
|
||||||
|
|
||||||
|
let expiringProjects: ProjectResult[];
|
||||||
|
let activeProjects: ProjectResult[];
|
||||||
|
let completedProjects: ProjectResult[];
|
||||||
|
let project: ProjectResult = null;
|
||||||
|
|
||||||
|
$: project = $selectionStore.hash.startsWith("P") ? projects.find(p => p.id === $selectionStore.hash) : null;
|
||||||
|
$: expiringProjects = projects.filter(p => p.active && p.endTime).sort((a,b) => Date.parse(a.endTime) - Date.parse(b.endTime));
|
||||||
|
$: activeProjects = projects.filter(p => p.active && !p.endTime).sort((a,b) => a.name.localeCompare(b.name));
|
||||||
|
$: completedProjects = projects.filter(p => !p.active).sort((a,b) => a.name.localeCompare(b.name));
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if (project === null && projects.length > 0) {
|
||||||
|
project = expiringProjects[0] || activeProjects[0] || completedProjects[0] || null;
|
||||||
|
if (project !== null) {
|
||||||
|
selectionStore.change("hash", project.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="quest-log">
|
||||||
|
<div class="list">
|
||||||
|
<QlList label="Deadlines" projects={expiringProjects} />
|
||||||
|
<QlList label="Acitve" projects={activeProjects} />
|
||||||
|
<QlList label="Completed" projects={completedProjects} />
|
||||||
|
</div>
|
||||||
|
<div class="body">
|
||||||
|
{#if project != null}
|
||||||
|
<ProjectEntry hideIcon project={project} showAllOptions />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div.quest-log {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.list {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 32ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body {
|
||||||
|
flex-grow: 1;
|
||||||
|
margin: 1em 1ch;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
import selectionStore from "../stores/selection";
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
selectionStore.refresh();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -2,10 +2,11 @@
|
|||||||
import EmptyList from "../components/EmptyList.svelte";
|
import EmptyList from "../components/EmptyList.svelte";
|
||||||
import GoalEntry from "../components/GoalEntry.svelte";
|
import GoalEntry from "../components/GoalEntry.svelte";
|
||||||
import ProjectEntry from "../components/ProjectEntry.svelte";
|
import ProjectEntry from "../components/ProjectEntry.svelte";
|
||||||
|
import RefreshSelection from "../components/RefreshSelection.svelte";
|
||||||
import type { ProjectResult } from "../models/project";
|
import type { ProjectResult } from "../models/project";
|
||||||
import { fpGoalStore } from "../stores/goal";
|
import { fpGoalStore } from "../stores/goal";
|
||||||
import projectStore, { fpProjectStore } from "../stores/project";
|
import { fpProjectStore } from "../stores/project";
|
||||||
import taskStore, { fpTaskStore } from "../stores/tasks";
|
import { fpTaskStore } from "../stores/tasks";
|
||||||
|
|
||||||
let fakeProject: ProjectResult
|
let fakeProject: ProjectResult
|
||||||
let sortedProjects: ProjectResult[]
|
let sortedProjects: ProjectResult[]
|
||||||
@@ -85,6 +86,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<RefreshSelection />
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
div.page {
|
div.page {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import GoalEntry from "../components/GoalEntry.svelte";
|
import GoalEntry from "../components/GoalEntry.svelte";
|
||||||
import type { ModalData } from "../stores/modal";
|
import type { ModalData } from "../stores/modal";
|
||||||
import goalStore from "../stores/goal";
|
import goalStore from "../stores/goal";
|
||||||
|
import RefreshSelection from "../components/RefreshSelection.svelte";
|
||||||
|
|
||||||
const mdGoalAdd: ModalData = {name: "goal.add"};
|
const mdGoalAdd: ModalData = {name: "goal.add"};
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@
|
|||||||
{/each}
|
{/each}
|
||||||
<Boi open={mdGoalAdd}>Add Goal</Boi>
|
<Boi open={mdGoalAdd}>Add Goal</Boi>
|
||||||
</div>
|
</div>
|
||||||
|
<RefreshSelection />
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
div.page {
|
div.page {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
import GroupEntry from "../components/GroupEntry.svelte";
|
import GroupEntry from "../components/GroupEntry.svelte";
|
||||||
import type { ModalData } from "../stores/modal";
|
import type { ModalData } from "../stores/modal";
|
||||||
import groupStore from "../stores/group";
|
import groupStore from "../stores/group";
|
||||||
import TableOfContent from "../components/TableOfContent.svelte";
|
import TableOfContent from "../components/TableOfContent.svelte";
|
||||||
|
import RefreshSelection from "../components/RefreshSelection.svelte";
|
||||||
|
|
||||||
const mdGroupAdd: ModalData = {name: "group.add"};
|
const mdGroupAdd: ModalData = {name: "group.add"};
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ import TableOfContent from "../components/TableOfContent.svelte";
|
|||||||
{/each}
|
{/each}
|
||||||
<Boi open={mdGroupAdd}>Add Group</Boi>
|
<Boi open={mdGroupAdd}>Add Group</Boi>
|
||||||
</div>
|
</div>
|
||||||
|
<RefreshSelection />
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
div.page {
|
div.page {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
import { formatDate, formatTime, formatWeekdayDate } from "../utils/time";
|
import { formatDate, formatTime, formatWeekdayDate } from "../utils/time";
|
||||||
import Boi from "../components/Boi.svelte";
|
import Boi from "../components/Boi.svelte";
|
||||||
import EmptyList from "../components/EmptyList.svelte";
|
import EmptyList from "../components/EmptyList.svelte";
|
||||||
|
import RefreshSelection from "../components/RefreshSelection.svelte";
|
||||||
|
|
||||||
let groupedLogs: {day: number, text: string, logs: LogResult[]}[] = [];
|
let groupedLogs: {day: number, text: string, logs: LogResult[]}[] = [];
|
||||||
let minTime = $logStore.filter.minTime || new Date(Date.now() - (86400000*30));
|
let minTime = $logStore.filter.minTime || new Date(Date.now() - (86400000*30));
|
||||||
@@ -95,6 +96,7 @@
|
|||||||
<Boi disabled>Loading...</Boi>
|
<Boi disabled>Loading...</Boi>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
<RefreshSelection />
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
div.page {
|
div.page {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import Boi from "../components/Boi.svelte";
|
import Boi from "../components/Boi.svelte";
|
||||||
import Checkbox from "../components/Checkbox.svelte";
|
import Checkbox from "../components/Checkbox.svelte";
|
||||||
import ProjectEntry from "../components/ProjectEntry.svelte";
|
import ProjectEntry from "../components/ProjectEntry.svelte";
|
||||||
|
import RefreshSelection from "../components/RefreshSelection.svelte";
|
||||||
import TableOfContent from "../components/TableOfContent.svelte";
|
import TableOfContent from "../components/TableOfContent.svelte";
|
||||||
import type { ModalData } from "../stores/modal";
|
import type { ModalData } from "../stores/modal";
|
||||||
import projectStore from "../stores/project";
|
import projectStore from "../stores/project";
|
||||||
@@ -37,6 +38,7 @@
|
|||||||
{/each}
|
{/each}
|
||||||
<Boi open={mdProjectAdd}>Add Project</Boi>
|
<Boi open={mdProjectAdd}>Add Project</Boi>
|
||||||
</div>
|
</div>
|
||||||
|
<RefreshSelection />
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
div.page {
|
div.page {
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Boi from "../components/Boi.svelte";
|
||||||
|
import QuestLog from "../components/QuestLog.svelte";
|
||||||
|
import RefreshSelection from "../components/RefreshSelection.svelte";
|
||||||
|
import type { ModalData } from "../stores/modal";
|
||||||
|
import projectStore from "../stores/project";
|
||||||
|
|
||||||
|
const mdProjectAdd: ModalData = {name: "project.add"};
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if (($projectStore.stale || $projectStore.filter.active != null) && !$projectStore.loading) {
|
||||||
|
projectStore.load({});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="page">
|
||||||
|
<QuestLog projects={$projectStore.projects} />
|
||||||
|
<Boi open={mdProjectAdd}>Add Project</Boi>
|
||||||
|
</div>
|
||||||
|
<RefreshSelection />
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div.page {
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
width: 1600px;
|
||||||
|
margin-top: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
|
interface SelectionData {
|
||||||
|
path: string,
|
||||||
|
hash: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSelectionStore() {
|
||||||
|
const {update, set, subscribe} = writable<SelectionData>({
|
||||||
|
path: window.location.pathname,
|
||||||
|
hash: window.location.hash.slice(1),
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
set({
|
||||||
|
path: window.location.pathname,
|
||||||
|
hash: window.location.hash.slice(1),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
change(key: keyof(SelectionData), value: string) {
|
||||||
|
update(d => ({...d, [key]: value}));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectionStore = createSelectionStore();
|
||||||
|
|
||||||
|
export default selectionStore;
|
||||||
Reference in New Issue
Block a user