Group button
This commit is contained in:
parent
e8ec7919d9
commit
5bc43aaba2
|
@ -5,6 +5,7 @@
|
||||||
<link rel="icon" href="/img/favicon.png" />
|
<link rel="icon" href="/img/favicon.png" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link rel="stylesheet" type="text/css" href="/css/global.css" />
|
<link rel="stylesheet" type="text/css" href="/css/global.css" />
|
||||||
|
<title>Focus.</title>
|
||||||
%sveltekit.head%
|
%sveltekit.head%
|
||||||
</head>
|
</head>
|
||||||
<body data-sveltekit-preload-data="hover">
|
<body data-sveltekit-preload-data="hover">
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
<script lang="ts">
|
||||||
|
export let isOpen = false;
|
||||||
|
export let choices: { id: number; value: string }[] = [];
|
||||||
|
export let onChoice = (id: number) => {};
|
||||||
|
export let currentChoice: number = -1;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if isOpen}
|
||||||
|
<div class="menu">
|
||||||
|
{#each choices as choice}
|
||||||
|
<div
|
||||||
|
class="menu-item"
|
||||||
|
on:click={() => onChoice(choice.id)}
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
on:keypress={(e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
onChoice(choice.id);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>{choice.value}</span>
|
||||||
|
{#if currentChoice === choice.id}
|
||||||
|
<span class="mark"> ✓ </span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.menu {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: #222;
|
||||||
|
border: 1px solid #666;
|
||||||
|
padding: 10px 0;
|
||||||
|
|
||||||
|
.menu-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 5px 20px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mark {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,10 +1,13 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { get } from 'svelte/store';
|
import { get } from 'svelte/store';
|
||||||
import type { Project, TagValue } from '../../stores/interfaces';
|
import type { Project, TagValue, View } from '../../stores/interfaces';
|
||||||
import { cards } from '../../stores/smallStore';
|
import { cards, currentView } from '../../stores/smallStore';
|
||||||
import projectTags from '../../stores/projectTags';
|
import projectTags from '../../stores/projectTags';
|
||||||
|
import GroupMenu from './groupMenu.svelte';
|
||||||
|
|
||||||
export let project: Project;
|
export let project: Project;
|
||||||
|
export let currentTagId: number;
|
||||||
|
let groupMenuOpen = false;
|
||||||
|
|
||||||
function getEmptyTags(): TagValue[] {
|
function getEmptyTags(): TagValue[] {
|
||||||
const tags: TagValue[] = [];
|
const tags: TagValue[] = [];
|
||||||
|
@ -18,16 +21,41 @@
|
||||||
}
|
}
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function setGroup(id: number): Promise<boolean> {
|
||||||
|
if ($currentView == null) return false;
|
||||||
|
|
||||||
|
return await currentView.update({
|
||||||
|
...$currentView,
|
||||||
|
primary_tag_id: id
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
<h2>{project.title}</h2>
|
<h2>{project.title}</h2>
|
||||||
<nav>
|
<nav>
|
||||||
<span>Group</span>
|
<div>
|
||||||
<span>Sub-group</span>
|
<button
|
||||||
<span>Filter</span>
|
on:click={() => (groupMenuOpen = !groupMenuOpen)}
|
||||||
<span>Sort</span>
|
class:defined={$currentView?.primary_tag_id}>Group</button
|
||||||
<button on:click={async () => cards.add(project.id, getEmptyTags())}>New</button>
|
>
|
||||||
|
<GroupMenu
|
||||||
|
isOpen={groupMenuOpen}
|
||||||
|
choices={Object.values($projectTags).map((tag) => ({ id: tag.id, value: tag.title }))}
|
||||||
|
onChoice={async (id) => {
|
||||||
|
if (!(await setGroup(id))) return;
|
||||||
|
groupMenuOpen = false;
|
||||||
|
}}
|
||||||
|
currentChoice={currentTagId}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class:disabled={true}>Sub-group</button>
|
||||||
|
</div>
|
||||||
|
<button>Filter</button>
|
||||||
|
<button>Sort</button>
|
||||||
|
<button id="newButton" on:click={async () => cards.add(project.id, getEmptyTags())}>New</button>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
@ -45,32 +73,34 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
* {
|
display: flex;
|
||||||
cursor: pointer;
|
flex-direction: row;
|
||||||
}
|
align-items: center;
|
||||||
|
|
||||||
span {
|
|
||||||
margin-right: 10px;
|
|
||||||
color: #aaa;
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-radius: 7px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
// background-color: #fff2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
button {
|
||||||
background: #324067;
|
cursor: pointer;
|
||||||
color: inherit;
|
color: #aaa;
|
||||||
|
padding: 5px 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
border-radius: 7px;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 10px;
|
background-color: transparent;
|
||||||
padding: 10px 20px;
|
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
|
|
||||||
&:hover {
|
&.defined {
|
||||||
// background-color: #3a4a77;
|
color: #6481cc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
color: #555;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#newButton {
|
||||||
|
background: #324067;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 10px 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -25,8 +25,8 @@
|
||||||
|
|
||||||
{#if project}
|
{#if project}
|
||||||
<section>
|
<section>
|
||||||
<Header {project} />
|
|
||||||
{#if view && $projectTags[view.primary_tag_id] && $cards}
|
{#if view && $projectTags[view.primary_tag_id] && $cards}
|
||||||
|
<Header {project} currentTagId={view.primary_tag_id} />
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
{#each $projectTags[view.primary_tag_id].options as option}
|
{#each $projectTags[view.primary_tag_id].options as option}
|
||||||
<Column
|
<Column
|
||||||
|
|
|
@ -2,8 +2,29 @@ import { writable } from 'svelte/store';
|
||||||
import { parseCards, type Card, type View, type TagValue } from './interfaces';
|
import { parseCards, type Card, type View, type TagValue } from './interfaces';
|
||||||
import { deleteCardApi, newCardApi } from '../api/cards';
|
import { deleteCardApi, newCardApi } from '../api/cards';
|
||||||
import { getProjectCardsAPI } from '../api/projects';
|
import { getProjectCardsAPI } from '../api/projects';
|
||||||
|
import api, { processError } from '../utils/api';
|
||||||
|
import status from '../utils/status';
|
||||||
|
|
||||||
export const currentView = writable(null as View | null);
|
export const currentView = (() => {
|
||||||
|
const { subscribe, set, update } = writable(null as View | null);
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
set,
|
||||||
|
update: async (view: View): Promise<boolean> => {
|
||||||
|
const response = await api.put(`/v1/views/${view.id}`, view);
|
||||||
|
|
||||||
|
if (response.status !== status.NoContent) {
|
||||||
|
processError(response, 'Failed to update view');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
set(view);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
export const currentModalCard = writable(-1);
|
export const currentModalCard = writable(-1);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue