Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
2ed633b
update: Add timetable conflicted variant and fix cell scaling
Coded5 Jan 2, 2026
fc836cc
feat: Add conflicted(boolean) to CourseSchedule type
Coded5 Jan 2, 2026
c922e7f
feat: Add more mock data
Coded5 Jan 2, 2026
87d7503
feat: created schedule page
Coded5 Jan 2, 2026
ffad03f
feat: Add exam data to course type
Coded5 Jan 3, 2026
690f9bd
feat: Add formatting and conflict logic utility functions
Coded5 Jan 3, 2026
0843f62
feat: Add exam and additional mock data
Coded5 Jan 3, 2026
e649e09
feat: added midterms and finals section of the schedule (List)
Coded5 Jan 3, 2026
570a201
update: Fix typing (temporary)
Coded5 Jan 3, 2026
52ab8e7
update pnpm-lock
Coded5 Jan 3, 2026
ad9e573
update pnpm-lock (again)
Coded5 Jan 3, 2026
8fcc675
feat: Create modal utility component
Coded5 Jan 4, 2026
6818596
chore: Remove import
Coded5 Jan 4, 2026
0a2679d
Merge branch 'mvp1-dev' into mvp1-dev-page/schedule
Coded5 Jan 4, 2026
4e0d31e
feat: Make timetable day customizable
Coded5 Jan 4, 2026
0ba9820
update: change CourseExamDate to use actual Date
Coded5 Jan 5, 2026
b50872f
fix: typing of CourseExamDate
Coded5 Jan 5, 2026
59f7b32
feat: Add TBA exam date and sort exam card by date
Coded5 Jan 5, 2026
dfc285d
fix: change text to Thai
Coded5 Jan 5, 2026
b184a8e
feat: Add exam timetable
Coded5 Jan 5, 2026
294b6cf
feat: Add exam timetable
Coded5 Jan 5, 2026
15a1894
feat: Add exam timetable course card color
Coded5 Jan 6, 2026
3d97a61
update: change and update selected-timetable-nav-bar
Coded5 Jan 9, 2026
135017b
feat: change select-timetable props
Coded5 Jan 9, 2026
fba31e0
feat: multiple schedule
Coded5 Jan 9, 2026
36902cb
feat: Add type for multiple schedule
Coded5 Jan 9, 2026
41fa990
feat: Add mock data for multiple schedule
Coded5 Jan 9, 2026
c10d095
feat: update pick-schedule-and-edit-course-plan with props and etc.
Coded5 Jan 9, 2026
315d4b4
feat: change semester look
Coded5 Jan 9, 2026
28a9737
chore: add @lucide/svelte
Coded5 Jan 9, 2026
1e31398
feat: add select schedule to edit-schedule component
Coded5 Jan 9, 2026
ba818f1
feat: add edit-schedule
Coded5 Jan 9, 2026
2fefb5f
update: change scheduleId type to string
Coded5 Jan 9, 2026
fd67555
chore: update type
Coded5 Jan 9, 2026
9c00d01
Merge branch 'mvp1-dev' into mvp1-dev-page/schedule
Coded5 Jan 9, 2026
77a18ff
chore: update pnpm-lock.yaml
Coded5 Jan 9, 2026
3cfad9f
fix: timetable incorrectly scale card when delete course
Coded5 Jan 10, 2026
19733ee
update: change z-index
Coded5 Jan 10, 2026
3d639ed
feat: add props and change format to svelte 5
Coded5 Jan 10, 2026
4a63830
feat: Add create timetable modal
Coded5 Jan 10, 2026
3879937
feat: make isPublic required
Coded5 Jan 10, 2026
c500d5f
feat: add onclick
Coded5 Jan 10, 2026
36982d6
feat: Add delete schedule
Coded5 Jan 10, 2026
f387372
feat: Add copy schedule
Coded5 Jan 10, 2026
8e12469
feat: Add rename modal
Coded5 Jan 10, 2026
a8d5285
feat: add rename
Coded5 Jan 10, 2026
3b2196c
chore: install html2canvas & html2canvas-pro
Coded5 Jan 10, 2026
b661571
feat: add save timetable image
Coded5 Jan 10, 2026
6fe3442
Merge branch 'mvp1-dev' into mvp1-dev-page/schedule
TeriyakiThames Jan 11, 2026
943b78c
chore: update pnpm-lock.yaml
Coded5 Jan 11, 2026
8c1ad7b
Merge branch 'mvp1-dev' into mvp1-dev-page/schedule
TeriyakiThames Jan 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
"build": "vite build",
"preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json",
"storybook": "storybook dev -p 6006",
"storybook": "storybook dev -p 6006 --ci",
"build-storybook": "storybook build"
},
"devDependencies": {
"@chromatic-com/storybook": "^4.1.3",
"@rodrigodagostino/svelte-sortable-list": "^2.1.9",
"@storybook/addon-a11y": "^10.1.7",
"@storybook/addon-docs": "^10.1.7",
"@storybook/addon-styling-webpack": "^3.0.0",
Expand Down Expand Up @@ -49,10 +50,13 @@
]
},
"dependencies": {
"@lucide/svelte": "^0.562.0",
"@rodrigodagostino/svelte-sortable-list": "^2.1.9",
"@tailwindcss/vite": "^4.1.18",
"bits-ui": "^2.14.4",
"clsx": "^2.1.1",
"html2canvas": "^1.4.1",
"html2canvas-pro": "^1.6.4",
"lucide-svelte": "^0.560.0",
"tailwind-merge": "^3.4.0",
"tailwind-variants": "^3.2.2"
Expand Down
4 changes: 0 additions & 4 deletions frontend/src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +0,0 @@
<script>
</script>

<h1>CUGetReg</h1>
16 changes: 15 additions & 1 deletion frontend/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ export const courseColorVariants = {
sky: 'bg-sky-300 border-sky-500 text-sky-700',
indigo: 'bg-indigo-300 border-indigo-500 text-indigo-700',
purple: 'bg-purple-300 border-purple-500 text-purple-700',
// conflict: 'bg-red-300 border-red-800 text-red-800'
}

export const conflict = 'bg-red-300 border-red-800 text-red-800';

// export const COLOURS = {
// pink: { border: '#F57FC6', fill: '#FDD8EE', text: '#C7117F' },
// tangerine: { border: '#F68E5F', fill: '#FFD7C3', text: '#F05E1F' },
// orange: { border: '#FEA339', fill: '#FFE2BF', text: '#E87D00' },
// yellow: { border: '#F9C93F', fill: '#FFF3D2', text: '#E39600' },
// green: { border: '#6CD62B', fill: '#D1FEB6', text: '#4B991C' },
// teal: { border: '#2BD6AD', fill: '#D9FFF6', text: '#349A82' },
// sky: { border: '#35A1EF', fill: '#DAEFFE', text: '#0C5A93' },
// indigo: { border: '#8170F1', fill: '#DCD7FF', text: '#211090' },
// purple: { border: '#C865EA', fill: '#F3D6FD', text: '#681A83' },
// neutral: { border: '#B2B5C7', fill: '#F6F6F9', text: '#555A74' },
// error: { border: '#F96666', fill: '#F96666', text: '#F96666' },
// }
1 change: 1 addition & 0 deletions frontend/src/lib/components/atoms/modal/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Modal } from './modal.svelte';
18 changes: 18 additions & 0 deletions frontend/src/lib/components/atoms/modal/modal.stories.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script module lang="ts">
import { defineMeta } from "@storybook/addon-svelte-csf"
import Modal from "./modal.svelte";
import { ConfirmDeleteSchedule } from "../../molecules/confirm-delete-schedule"
import CreateTimetable from "../../organisms/create-timetable/create-timetable.svelte"

const { Story } = defineMeta({
title: "Atom/Modal",
component: Modal,
tags: ['autodocs']
});
</script>

<Story name="Default Modal">
<div class="border border-neutral-200 w-50 h-25 flex justify-center items-center rounded-lg bg-surface">
Hello world
</div>
</Story>
58 changes: 58 additions & 0 deletions frontend/src/lib/components/atoms/modal/modal.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<script lang="ts">
import type { Snippet } from "svelte"
import { cn } from "../../../../utils";

function handleClick(e: MouseEvent) {
e.preventDefault();

if (!exitOnBackgroundClick) return;
show = false;
}

function handleKeydown(e: KeyboardEvent) {
if (e.key === 'Escape' && exitOnEsc) show = false;
}

interface ModalProp {
children?: Snippet;
show?: boolean;
centered?: boolean;
dim?: boolean;
exitOnBackgroundClick?: boolean;
exitOnEsc?: boolean;
}

let {
children,
centered = true,
dim = false,
show = $bindable(true),
exitOnBackgroundClick = false,
exitOnEsc = false,
}: ModalProp = $props();
</script>

{#if show}
<div
class={cn(
"fixed top-0 left-0 w-screen h-screen m-0 p-0 z-50",
dim && "bg-black/40",
centered && "flex items-center justify-center"
)}
onclick={handleClick}
onkeydown={handleKeydown}
tabindex="0"
role="dialog"

>
<div
class="z-60"
onclick={(e) => e.stopPropagation()}
onkeydown={(e) => e.stopPropagation()}
tabindex="0"
role="dialog"
>
{@render children?.()}
</div>
</div>
{/if}
9 changes: 6 additions & 3 deletions frontend/src/lib/components/atoms/timetable/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ export const timeTableCourseCardVariant = tv({
"left-[calc(100%/var(--cols)*var(--y))]",
"flex flex-col justify-center items-center",
"border-1 rounded-lg",
"hover:cursor-pointer hover:z-100 select-none"
"hover:cursor-pointer hover:z-100 select-none",
],
variants: {
color: courseColorVariants
color: {
conflict: 'bg-red-300 border-red-800 text-red-800',
...courseColorVariants
}
},
defaultVariants: {
length: 3,
Expand All @@ -36,5 +39,5 @@ export interface TimeTableContext {
amountOfDays: number;
}

export { default as CourseTimeSlot } from './timetable-course-card.svelte';
export { default as TimetableCourseCard } from './timetable-course-card.svelte';
export { default as TimeTable } from './timetable.svelte';
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
import { cn } from "../../../../utils";
import { getContext } from "svelte";

const context = getContext<TimeTableContext>("timetable-context");

const numCol = context.periodPerDay;
const numRow = context.amountOfDays;
let context = getContext<TimeTableContext>("timetable-context");

interface TimeTableCourseCardProp {
course: TimeTableCourse;
Expand All @@ -34,8 +31,8 @@

<div
style="
--cols: {numCol};
--rows: {numRow};
--cols: {context.periodPerDay};
--rows: {context.amountOfDays};
--len: {length};
--x: {row};
--y: {col};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@
periodPerDay: {
defaultValue: 12,
},
schedule: {
control: false,
},
days: {
controls: false,
defaultValue: ["MON", "TUE", "WED", "THU", "FRI"],
}
},
});

Expand Down Expand Up @@ -44,6 +45,13 @@

<Story name="Default" />

<Story name="Custom Days" args={{ days: [
'3 ธ.ค 67',
'4 ธ.ค 67',
'5 ธ.ค 67',
'7 ธ.ค 67',
]}}/>

<Story name="Populated">
<TimetableCourseCard
course={course1}
Expand Down
63 changes: 25 additions & 38 deletions frontend/src/lib/components/atoms/timetable/timetable.svelte
Original file line number Diff line number Diff line change
@@ -1,52 +1,31 @@
<script lang="ts">
import { type TimeTableContext } from "./index";
import type { Day } from "../day-chip";
import { setContext, type Snippet } from "svelte";

import { cn } from "../../../../utils";
import type { ClassValue } from "clsx";

const DAYS5: NonNullable<Day>[] = ["MO", "TU", "WE", "TH", "FR"];
const DAYS7: NonNullable<Day>[] = [
"MO",
"TU",
"WE",
"TH",
"FR",
"SA",
"SU",
];

const days: Record<NonNullable<Day>, string> = {
MO: "MON",
TU: "TUE",
WE: "WED",
TH: "THU",
FR: "FRI",
SA: "SAT",
SU: "SUN",
};
const DAYS5 = ["MON", "TUE", "WED", "THU", "FRI"];

interface TimeTableProp {
periodPerDay?: number;
includeSatSun?: boolean;
startTime: number;
class?: ClassValue;
days?: string[];
children?: Snippet;
[key: string]: unknown;
}

const {
periodPerDay = 12,
includeSatSun = false,
let prop: TimeTableProp = $props();

let {
startTime = 6,
class: className = undefined,
children,
...rest
}: TimeTableProp = $props();
}: TimeTableProp = prop;

const amountOfDays = $derived(includeSatSun ? 7 : 5);
const DAYS = $derived(includeSatSun ? DAYS7 : DAYS5);
let periodPerDay = $derived(prop.periodPerDay ?? 12);
let days = $derived(prop.days ?? DAYS5);
let amountOfDays = $derived(prop.days?.length ?? 5);

setContext<TimeTableContext>("timetable-context", {
get periodPerDay() {
Expand All @@ -59,13 +38,13 @@
</script>

<div
class={cn("grid border border-neutral-200", className)}
class={cn("grid border-l border-t border-neutral-200", className)}
style="
grid-template-columns: repeat({periodPerDay + 1}, minmax(0, 1fr));
grid-template-rows: auto repeat({amountOfDays + 1});
"
>
<div class="bg-indigo-50! py-3.5 cell border-r border-b border-neutral-200">
<div class="bg-indigo-50! py-3.5 cell border-r border-b border-neutral-200 truncate">
วัน/เวลา
</div>
<div
Expand All @@ -77,9 +56,14 @@
>
{#each Array.from({ length: periodPerDay }) as _, i}
<div
class="bg-indigo-50! px-2 py-3.5 cell text-right! items-end! justify-end!"
class="
bg-indigo-50! px-2 py-3.5 cell text-right! items-end! justify-end!
@container-[size]
"
>
{i + startTime}
<span class="text-sm">
{i + startTime}
</span>
</div>
{/each}
</div>
Expand All @@ -88,9 +72,11 @@
class="grid divide-y divide-neutral-200"
style="grid-row: span {amountOfDays} / span {amountOfDays}"
>
{#each DAYS as day}
<div class="cell bg-indigo-50! aspect-square">
{days[day]}
{#each days as day}
<div class="cell bg-indigo-50! aspect-square @container-[size]">
<span class="text-[20cqh]">
{day}
</span>
</div>
{/each}
</div>
Expand Down Expand Up @@ -126,7 +112,8 @@
@reference "../../../../app.css";

.cell {
@apply ring-[1px] ring-neutral-200 bg-white flex justify-center text-center items-center;
@apply bg-white flex justify-center text-center items-center;
@apply border-r border-b border-neutral-200;
@apply text-sm;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script module lang="ts">
import { defineMeta } from "@storybook/addon-svelte-csf";

import { EditSchedule } from "./index";

const { Story } = defineMeta({
title: "Molecule/Edit Schedule",
component: EditSchedule,
tags: ["autodocs"],
argTypes: {
},
});
</script>

<!--👇 Each story then reuses that template-->

<Story name="Default" />
Loading
Loading