add status icons, and tweak stuff.
This commit is contained in:
Generated
+11335
File diff suppressed because it is too large
Load Diff
@@ -11,12 +11,15 @@
|
|||||||
"lint": "eslint --ignore-path .gitignore ."
|
"lint": "eslint --ignore-path .gitignore ."
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^6.0.0",
|
||||||
"@sveltejs/adapter-auto": "next",
|
"@sveltejs/adapter-auto": "next",
|
||||||
"@sveltejs/kit": "next",
|
"@sveltejs/kit": "next",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.10.1",
|
"@typescript-eslint/eslint-plugin": "^5.10.1",
|
||||||
"@typescript-eslint/parser": "^5.10.1",
|
"@typescript-eslint/parser": "^5.10.1",
|
||||||
|
"@yarbsemaj/adapter-lambda": "^0.5.1",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-plugin-svelte3": "^3.2.1",
|
"eslint-plugin-svelte3": "^3.2.1",
|
||||||
|
"fa-svelte": "^3.1.0",
|
||||||
"node-sass": "^7.0.1",
|
"node-sass": "^7.0.1",
|
||||||
"sass": "^1.49.9",
|
"sass": "^1.49.9",
|
||||||
"svelte": "^3.44.0",
|
"svelte": "^3.44.0",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import type { StandaloneItem } from "$lib/models/item";
|
import type { StandaloneItem } from "$lib/models/item";
|
||||||
import Entry from "../layout/Entry.svelte";
|
import Entry from "../layout/Entry.svelte";
|
||||||
import EntryAmounts from "../layout/EntryAmounts.svelte";
|
import EntryAmounts from "../layout/EntryAmounts.svelte";
|
||||||
|
import EntryCompletionIcon from "../layout/EntryCompletionIcon.svelte";
|
||||||
import EntryDescription from "../layout/EntryDescription.svelte";
|
import EntryDescription from "../layout/EntryDescription.svelte";
|
||||||
import EntryName from "../layout/EntryName.svelte";
|
import EntryName from "../layout/EntryName.svelte";
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
|
|
||||||
<a href={link}>
|
<a href={link}>
|
||||||
<Entry>
|
<Entry>
|
||||||
|
<EntryCompletionIcon condition={!!item.acquireDate} />
|
||||||
<EntryName subtitle={subtitle}>{item.name}</EntryName>
|
<EntryName subtitle={subtitle}>{item.name}</EntryName>
|
||||||
{#if !compact}
|
{#if !compact}
|
||||||
<EntryDescription>{item.description}</EntryDescription>
|
<EntryDescription>{item.description}</EntryDescription>
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { StandaloneRequirement } from "$lib/models/project";
|
import type { StandaloneRequirement } from "$lib/models/project";
|
||||||
|
import Status from "$lib/models/status";
|
||||||
|
|
||||||
import Entry from "../layout/Entry.svelte";
|
import Entry from "../layout/Entry.svelte";
|
||||||
import EntryDescription from "../layout/EntryDescription.svelte";
|
import EntryDescription from "../layout/EntryDescription.svelte";
|
||||||
import EntryName from "../layout/EntryName.svelte";
|
import EntryName from "../layout/EntryName.svelte";
|
||||||
import EntryProgress from "../layout/EntryProgress.svelte";
|
import EntryProgress from "../layout/EntryProgress.svelte";
|
||||||
import EntryProgressRow from "../layout/EntryProgressRow.svelte";
|
import EntryProgressRow from "../layout/EntryProgressRow.svelte";
|
||||||
|
import EntryStatusIcon from "../layout/EntryStatusIcon.svelte";
|
||||||
|
|
||||||
export let requirement: StandaloneRequirement
|
export let requirement: StandaloneRequirement
|
||||||
export let compact: boolean = false;
|
export let compact: boolean = false;
|
||||||
@@ -14,6 +16,7 @@
|
|||||||
|
|
||||||
<a href="/{requirement.scope.id}/{requirement.project.id}?requirement={requirement.id}">
|
<a href="/{requirement.scope.id}/{requirement.project.id}?requirement={requirement.id}">
|
||||||
<Entry>
|
<Entry>
|
||||||
|
<EntryStatusIcon status={requirement.status} />
|
||||||
<EntryName subtitle={requirement.project.name}>{requirement.name}</EntryName>
|
<EntryName subtitle={requirement.project.name}>{requirement.name}</EntryName>
|
||||||
{#if !compact}
|
{#if !compact}
|
||||||
<EntryDescription>{requirement.description}</EntryDescription>
|
<EntryDescription>{requirement.description}</EntryDescription>
|
||||||
|
|||||||
@@ -75,7 +75,6 @@
|
|||||||
{#if sprint.kind === "item"}
|
{#if sprint.kind === "item"}
|
||||||
<EntryProgress
|
<EntryProgress
|
||||||
fullwidth green
|
fullwidth green
|
||||||
percentage={sprint.aggregateRequired == 0}
|
|
||||||
name="Items"
|
name="Items"
|
||||||
acquired={itemsAcquired}
|
acquired={itemsAcquired}
|
||||||
required={itemsRequired}
|
required={itemsRequired}
|
||||||
@@ -84,7 +83,6 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<EntryProgress
|
<EntryProgress
|
||||||
fullwidth
|
fullwidth
|
||||||
percentage={sprint.aggregateRequired == 0}
|
|
||||||
name="Total"
|
name="Total"
|
||||||
acquired={aggregate.acquired}
|
acquired={aggregate.acquired}
|
||||||
required={aggregate.required}
|
required={aggregate.required}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
margin: 0.5em 0;
|
margin: 0.5em 0;
|
||||||
padding: 0.25em 0.5ch;
|
padding: 0.25em 0.5ch;
|
||||||
transition: 250ms;
|
transition: 250ms;
|
||||||
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
div.entry:hover {
|
div.entry:hover {
|
||||||
background-color: #333;
|
background-color: #333;
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Icon, { DEFAULT_ICON } from "./Icon.svelte";
|
||||||
|
import type { IconName } from "./Icon.svelte";
|
||||||
|
|
||||||
|
export let name: IconName = DEFAULT_ICON;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="bgicon">
|
||||||
|
<Icon name={name} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div.bgicon {
|
||||||
|
position: relative;
|
||||||
|
top: 0.1em;
|
||||||
|
height: 0;
|
||||||
|
width: 2ch;
|
||||||
|
font-size: 3em;
|
||||||
|
margin-left: auto;
|
||||||
|
background: none;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
:global(.icon) {
|
||||||
|
opacity: 0.10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Status from "$lib/models/status";
|
||||||
|
|
||||||
|
import EntryBgIcon from "./EntryBgIcon.svelte";
|
||||||
|
import StatusColor from "./StatusColor.svelte";
|
||||||
|
|
||||||
|
export let condition: boolean;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if condition}
|
||||||
|
<StatusColor status={Status.Completed}>
|
||||||
|
<EntryBgIcon name="check" />
|
||||||
|
</StatusColor>
|
||||||
|
{/if}
|
||||||
@@ -26,26 +26,31 @@
|
|||||||
let segmented = false;
|
let segmented = false;
|
||||||
let boatClass = "gray";
|
let boatClass = "gray";
|
||||||
let boatDone = false;
|
let boatDone = false;
|
||||||
|
let ratio = 0;
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (required > 0) {
|
const acq = Math.floor(acquired);
|
||||||
let level = Math.floor(acquired / required);
|
const req = Math.floor(required);
|
||||||
|
|
||||||
|
ratio = acq / req;
|
||||||
|
|
||||||
|
if (req > 0) {
|
||||||
|
let level = Math.floor(acq / req);
|
||||||
if (level >= PROGRESS_COLORS.length - 1) {
|
if (level >= PROGRESS_COLORS.length - 1) {
|
||||||
offs = 0;
|
offs = 0;
|
||||||
ons = required;
|
ons = req;
|
||||||
offClass = "gold";
|
offClass = "gold";
|
||||||
onClass = "gold";
|
onClass = "gold";
|
||||||
} else {
|
} else {
|
||||||
ons = acquired - (level * required);
|
ons = acq - (level * req);
|
||||||
offs = required - ons;
|
offs = req - ons;
|
||||||
console.log(name, ons, offs);
|
|
||||||
offClass = PROGRESS_COLORS[level];
|
offClass = PROGRESS_COLORS[level];
|
||||||
onClass = PROGRESS_COLORS[level + 1];
|
onClass = PROGRESS_COLORS[level + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark it non-segmented if the required is too high. This prevents a clunky progress bar,
|
// Mark it non-segmented if the required is too high. This prevents a clunky progress bar,
|
||||||
// or a browser freeze if you set the required very high.
|
// or a browser freeze if you set the required very high.
|
||||||
segmented = !percentage && (required <= (fullwidth ? 60 : 15));
|
segmented = !percentage && (req <= (fullwidth ? 60 : 15));
|
||||||
} else {
|
} else {
|
||||||
offClass = "none";
|
offClass = "none";
|
||||||
segmented = true;
|
segmented = true;
|
||||||
@@ -57,8 +62,8 @@
|
|||||||
onClass = "green";
|
onClass = "green";
|
||||||
offClass = "none";
|
offClass = "none";
|
||||||
|
|
||||||
if (acquired >= required) {
|
if (acq >= req) {
|
||||||
ons = required;
|
ons = req;
|
||||||
offs = 0;
|
offs = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,7 +71,7 @@
|
|||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (boat != null && required > 0) {
|
if (boat != null && required > 0) {
|
||||||
const diff = (acquired / required) - boat;
|
const diff = ratio - boat;
|
||||||
if (diff < -0.05) {
|
if (diff < -0.05) {
|
||||||
boatClass = "red";
|
boatClass = "red";
|
||||||
} else if (diff > 0.05) {
|
} else if (diff > 0.05) {
|
||||||
@@ -75,7 +80,7 @@
|
|||||||
boatClass = "gray";
|
boatClass = "gray";
|
||||||
}
|
}
|
||||||
|
|
||||||
boatDone = acquired >= required;
|
boatDone = ratio >= 1.0;
|
||||||
} else {
|
} else {
|
||||||
boatClass = "gray";
|
boatClass = "gray";
|
||||||
boatDone = false;
|
boatDone = false;
|
||||||
@@ -91,7 +96,7 @@
|
|||||||
{#if percentage}
|
{#if percentage}
|
||||||
<span class="ackreq">({((acquired / required) * 100).toFixed(0)}%)</span>
|
<span class="ackreq">({((acquired / required) * 100).toFixed(0)}%)</span>
|
||||||
{:else}
|
{:else}
|
||||||
<span class="ackreq">({Math.round(acquired)} / {Math.round(required)})</span>
|
<span class="ackreq">({Math.floor(acquired)} / {Math.ceil(required)})</span>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -174,8 +179,8 @@
|
|||||||
flex-basis: 0;
|
flex-basis: 0;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin: 0 0.5px;
|
margin: 0 1px;
|
||||||
border: 0.25px solid #000;
|
border: 1px solid #000;
|
||||||
|
|
||||||
div.non-segmented {
|
div.non-segmented {
|
||||||
flex-grow: inherit;
|
flex-grow: inherit;
|
||||||
@@ -195,6 +200,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
span.ackreq {
|
span.ackreq {
|
||||||
opacity: 0.333;
|
color: #555;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type Status from "$lib/models/status";
|
||||||
|
import EntryBgIcon from "./EntryBgIcon.svelte";
|
||||||
|
import type { IconName } from "./Icon.svelte";
|
||||||
|
import StatusColor from "./StatusColor.svelte";
|
||||||
|
|
||||||
|
export let status: Status;
|
||||||
|
let icon: IconName
|
||||||
|
|
||||||
|
$: switch (status) {
|
||||||
|
case 0: icon = "hourglass"; break;
|
||||||
|
case 1: icon = "lightbulb"; break;
|
||||||
|
case 2: icon = "calendar"; break;
|
||||||
|
case 3: icon = "spinner"; break;
|
||||||
|
case 4: icon = "check"; break;
|
||||||
|
case 5: icon = "times"; break;
|
||||||
|
case 6: icon = "times"; break;
|
||||||
|
default: icon = "question";
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<StatusColor status={status}>
|
||||||
|
<EntryBgIcon name={icon} />
|
||||||
|
</StatusColor>
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Icon from "fa-svelte";
|
||||||
|
|
||||||
|
export let name: IconName = "question";
|
||||||
|
export let block: boolean = false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if block}
|
||||||
|
<div>
|
||||||
|
<Icon class="icon" icon={icons[name] || icons.question} />
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<Icon class="icon" icon={icons[name] || icons.question} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script lang="ts" context="module">
|
||||||
|
import { faQuestion } from "@fortawesome/free-solid-svg-icons/faQuestion";
|
||||||
|
import { faPlus } from "@fortawesome/free-solid-svg-icons/faPlus";
|
||||||
|
import { faPen } from "@fortawesome/free-solid-svg-icons/faPen";
|
||||||
|
import { faArchive } from "@fortawesome/free-solid-svg-icons/faArchive";
|
||||||
|
import { faCheck } from "@fortawesome/free-solid-svg-icons/faCheck";
|
||||||
|
import { faCog } from "@fortawesome/free-solid-svg-icons/faCog";
|
||||||
|
import { faLink } from "@fortawesome/free-solid-svg-icons/faLink";
|
||||||
|
import { faStar } from "@fortawesome/free-solid-svg-icons/faStar";
|
||||||
|
import { faTimes } from "@fortawesome/free-solid-svg-icons/faTimes";
|
||||||
|
import { faSpinner } from "@fortawesome/free-solid-svg-icons/faSpinner";
|
||||||
|
import { faHourglass } from "@fortawesome/free-solid-svg-icons/faHourglass";
|
||||||
|
import { faCalendar } from "@fortawesome/free-solid-svg-icons/faCalendar";
|
||||||
|
import { faExpand } from "@fortawesome/free-solid-svg-icons/faExpand";
|
||||||
|
import { faSearch } from "@fortawesome/free-solid-svg-icons/faSearch";
|
||||||
|
import { faClock } from "@fortawesome/free-solid-svg-icons/faClock";
|
||||||
|
import { faThumbtack } from "@fortawesome/free-solid-svg-icons/faThumbtack";
|
||||||
|
import { faHistory } from "@fortawesome/free-solid-svg-icons/faHistory";
|
||||||
|
import { faLightbulb } from "@fortawesome/free-solid-svg-icons/faLightbulb";
|
||||||
|
|
||||||
|
const icons = {
|
||||||
|
"clock": faClock,
|
||||||
|
"thumbtack": faThumbtack,
|
||||||
|
"history": faHistory,
|
||||||
|
"question": faQuestion,
|
||||||
|
"plus": faPlus,
|
||||||
|
"pen": faPen,
|
||||||
|
"archive": faArchive,
|
||||||
|
"check": faCheck,
|
||||||
|
"cog": faCog,
|
||||||
|
"link": faLink,
|
||||||
|
"star": faStar,
|
||||||
|
"times": faTimes,
|
||||||
|
"lightbulb": faLightbulb,
|
||||||
|
"spinner": faSpinner,
|
||||||
|
"hourglass": faHourglass,
|
||||||
|
"calendar": faCalendar,
|
||||||
|
"expand": faExpand,
|
||||||
|
"search": faSearch,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type IconName = keyof typeof icons;
|
||||||
|
|
||||||
|
export const iconNames = Object.keys(icons).sort() as IconName[];
|
||||||
|
export const DEFAULT_ICON: IconName = "question";
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type Status from "$lib/models/status";
|
||||||
|
|
||||||
|
export let status: Status;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span class="status-color status-{status}"><slot></slot></span>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
// Blocked = 0
|
||||||
|
span.status-color.status-0 {
|
||||||
|
color: #78c9ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Available = 1
|
||||||
|
span.status-color.status-1 {
|
||||||
|
color: #e7e55e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Background = 2
|
||||||
|
span.status-color.status-2 {
|
||||||
|
color: #e7a75e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Active = 3
|
||||||
|
span.status-color.status-3 {
|
||||||
|
color: #bdbdbd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Completed = 4
|
||||||
|
span.status-color.status-4 {
|
||||||
|
color: #78ff78;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed = 5
|
||||||
|
span.status-color.status-5 {
|
||||||
|
color: #852a24;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dropped = 6
|
||||||
|
span.status-color.status-6 {
|
||||||
|
color: #e75ed0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
enum Status {
|
enum Status {
|
||||||
Blocked = 0,
|
Blocked = 0,
|
||||||
Available = 1,
|
Available = 1,
|
||||||
Inactive = 2,
|
Background = 2,
|
||||||
Active = 3,
|
Active = 3,
|
||||||
Completed = 4,
|
Completed = 4,
|
||||||
Failed = 5,
|
Failed = 5,
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export const get: RequestHandler = async({}) => {
|
|||||||
name: "3D Maps: Proving the concept",
|
name: "3D Maps: Proving the concept",
|
||||||
status: Status.Active
|
status: Status.Active
|
||||||
},
|
},
|
||||||
status: Status.Active,
|
status: Status.Background,
|
||||||
stats: [
|
stats: [
|
||||||
{id: 1, name: "Asset", weight: 0.2, acquired: 8, required: 15},
|
{id: 1, name: "Asset", weight: 0.2, acquired: 8, required: 15},
|
||||||
{id: 2, name: "Complexity", weight: 1, acquired: 69, required: 30},
|
{id: 2, name: "Complexity", weight: 1, acquired: 69, required: 30},
|
||||||
@@ -106,7 +106,7 @@ export const get: RequestHandler = async({}) => {
|
|||||||
name: "Wenera's Job",
|
name: "Wenera's Job",
|
||||||
status: Status.Active
|
status: Status.Active
|
||||||
},
|
},
|
||||||
status: Status.Active,
|
status: Status.Available,
|
||||||
stats: [
|
stats: [
|
||||||
{id: 1, name: "Story", weight: 3, required: 5, acquired: 1},
|
{id: 1, name: "Story", weight: 3, required: 5, acquired: 1},
|
||||||
{id: 2, name: "Story Word", weight: 0.002, required: 4000, acquired: 759},
|
{id: 2, name: "Story Word", weight: 0.002, required: 4000, acquired: 759},
|
||||||
|
|||||||
Reference in New Issue
Block a user