Skip to content

Commit

Permalink
feat: create Promise List Component (#107)
Browse files Browse the repository at this point in the history
* feat: create PromiseList PromiseCard component and add to main page

* fix: add key for each block

* fix: fix error from key in each block

* style: add color for notStarted status in promise card

* fix: edit promise list component and card variables
  • Loading branch information
sealbb authored Sep 24, 2024
1 parent 69967e8 commit 9a51bb9
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 1 deletion.
112 changes: 112 additions & 0 deletions src/components/PromiseList/PromiseCard.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<script lang="ts">
import type { PromiseSummary } from '../../routes/promises/+page.server';
import { PromiseStatus } from '$models/promise';
import Quotes from 'carbon-icons-svelte/lib/Quotes.svelte';
export let promiseSummary: PromiseSummary;
const formatDate = (date: Date) =>
date.toLocaleDateString('th-TH', {
year: 'numeric',
month: 'short',
day: 'numeric'
});
const getStyles = (status: PromiseStatus) => {
switch (status) {
case PromiseStatus.inProgress:
return {
tag: 'bg-yellow-20 text-black',
footer: 'bg-yellow-10'
};
case PromiseStatus.fulfilled:
return {
tag: 'bg-green-50 text-white',
footer: 'bg-green-10'
};
case PromiseStatus.unhonored:
return {
tag: 'bg-magenta-50 text-white',
footer: 'bg-magenta-10'
};
default:
return {
tag: 'bg-gray-30 text-black',
footer: 'bg-gray-10'
};
}
};
</script>

<div class="flex w-full shrink-0 cursor-pointer flex-col">
<div class="h-1 {getStyles(promiseSummary.status).tag}"></div>

<div class="group bg-ui-background px-6 hover:bg-ui-03">
<div class="flex items-center gap-2 py-4">
<img
src={promiseSummary.party.logo}
alt=""
class="h-8 w-8 rounded-full border border-gray-30"
/>
<p class="body-01">พรรค{promiseSummary.party.name}</p>
</div>

<div class="flex flex-col gap-2">
<div class="flex gap-2">
<Quotes class="text-text-03" />
<div
class="w-full translate-y-[50%] border-t border-ui-03 duration-200 group-hover:border-ui-01"
></div>
</div>
<div class="flex h-[165px] items-center justify-center">
<p class="textCustom heading-compact-02 block h-full overflow-hidden">
{promiseSummary.statements}
</p>
</div>
<div class="flex flex-row-reverse gap-2">
<Quotes class="rotate-180 text-text-03" />
<div
class="w-full translate-y-[50%] border-t border-ui-03 duration-200 group-hover:border-ui-01"
></div>
</div>
</div>

<div class="flex flex-col gap-[5px] pb-4 pt-3">
{#each [{ label: 'คีย์เวิร์ด', items: promiseSummary.keywords }, { label: 'หมวด', items: promiseSummary.categories }] as { label, items } (label)}
<div class="flex flex-wrap gap-[2px]">
<p class="body-01 text-text-02">{label}</p>
{#each items as item, itemIndex (itemIndex)}
{#if item}
<button
class="label-01 rounded-full {label === 'คีย์เวิร์ด'
? 'bg-gray-10'
: 'border'} px-2">{item}</button
>
{/if}
{/each}
</div>
{/each}
</div>
</div>

<div class="{getStyles(promiseSummary.status).footer} grid grid-cols-2 gap-2 px-6 py-4">
<div class="flex flex-col gap-1">
<p class="heading-01">สถานะ</p>
<div class="{getStyles(promiseSummary.status).tag} label-01 w-fit rounded-full px-2 py-[3px]">
{promiseSummary.status}
</div>
</div>
<div class="flex flex-col gap-1">
<p class="heading-01">เคลื่อนไหวล่าสุด</p>
<div class="body-01">{formatDate(promiseSummary.latestProgressDate.date)}</div>
</div>
</div>
</div>

<style>
.textCustom {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 7;
line-height: 1.5;
}
</style>
72 changes: 72 additions & 0 deletions src/components/PromiseList/PromiseList.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<script lang="ts">
import type { PromiseSummary } from '../../routes/promises/+page.server';
import { Select, SelectItem } from 'carbon-components-svelte';
import PromiseCard from './PromiseCard.svelte';
import Grid from 'carbon-icons-svelte/lib/Grid.svelte';
import List from 'carbon-icons-svelte/lib/List.svelte';
export let summaries: PromiseSummary[];
// export let cappedAt: number | undefined;
type SortByOptions = 'วันที่เคลื่อนไหวล่าสุด' | 'ตัวอักษร' | 'สถานะ';
let sortBy: SortByOptions = 'วันที่เคลื่อนไหวล่าสุด';
function handleChange(e: Event) {
const target = e.target as HTMLSelectElement;
const value = target?.value as SortByOptions;
if (
Object.values<SortByOptions>(['วันที่เคลื่อนไหวล่าสุด', 'ตัวอักษร', 'สถานะ']).includes(value)
) {
sortBy = value;
}
}
$: sortedData = (() => {
const data = Array.from(summaries);
switch (sortBy) {
case 'วันที่เคลื่อนไหวล่าสุด':
return data.sort(
(a, b) => b.latestProgressDate.date.getTime() - a.latestProgressDate.date.getTime()
);
case 'ตัวอักษร':
return data.sort((a, b) => (a.statements[0] ?? '').localeCompare(b.statements[0] ?? ''));
case 'สถานะ':
return data.sort((a, b) => a.status.localeCompare(b.status));
default:
return data;
}
})();
</script>

<div class="">
<div class="flex flex-col justify-between gap-1 pb-4 pt-6 md:flex-row md:items-center">
<p class="fluid-heading-03 font-bold">ผลลัพธ์ {sortedData.length} คำสัญญา</p>
<div class="flex items-center gap-[15px]">
<div class="flex items-center gap-1">
<p class="body-compact-01 text-text-02">เรียงตาม</p>
<Select
class="w-[228px] md:w-[288px]"
hideLabel
labelText="Carbon theme"
on:change={handleChange}
>
<SelectItem value="วันที่เคลื่อนไหวล่าสุด" />
<SelectItem value="ตัวอักษร" />
<SelectItem value="สถานะ" />
</Select>
</div>
<div class="hidden items-center gap-2 md:flex">
{#each [{ icon: List, label: 'List' }, { icon: Grid, label: 'Grid' }] as { icon, label } (label)}
<button class="h-8 w-8 rounded-[2px] p-1 duration-200 hover:bg-[#CACACA]">
<svelte:component this={icon} class="h-6 w-6" />
</button>
{/each}
</div>
</div>
</div>
<div class="mx-auto grid w-fit gap-6 md:grid-cols-3">
{#each sortedData as promiseSummary, index (index)}
<PromiseCard {promiseSummary} />
{/each}
</div>
</div>
7 changes: 6 additions & 1 deletion src/routes/promises/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { fetchAssemblies, fetchParties, fetchPoliticians } from '$lib/datasheets
import { getAssemblyMembers } from '$lib/datasheets/assembly-member';
import type { Party } from '$models/party';
import type { Politician } from '$models/politician';
import { PromiseStatus, type Promise } from '$models/promise';
import { PromiseStatus, type Promise, type PromiseProgress } from '$models/promise';
import {
clarifyingPromise,
fulfilledPromise,
Expand Down Expand Up @@ -36,6 +36,11 @@ export interface PromisesByCategory {
count: number;
}

export interface PromiseSummary
extends Pick<Promise, 'id' | 'statements' | 'party' | 'keywords' | 'categories' | 'status'> {
latestProgressDate: PromiseProgress;
}

const CURRENT_CABINET_ASSEMBLY_ID = 'คณะรัฐมนตรี-64';

export async function load() {
Expand Down
6 changes: 6 additions & 0 deletions src/routes/promises/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script lang="ts">
import PromiseList from '$components/PromiseList/PromiseList.svelte';
export let data;
console.log(JSON.stringify(data, null, 2));
</script>
Expand All @@ -7,3 +9,7 @@
<li><a href={`/promises/1`}>Detail page</a></li>
<li><a href="promises/explore">Explore page</a></li>
</ul>

<div class="mx-auto flex max-w-[1280px] flex-col gap-3 px-4 py-6">
<PromiseList summaries={data.promiseSummaries} />
</div>

0 comments on commit 9a51bb9

Please sign in to comment.