Merge branch 'tags-setup' into 'master'

feat: Added avaliable tags and tag column to table

See merge request gk1623/drp-48!4

Co-authored-by: Barf-Vader <47476490+Barf-Vader@users.noreply.github.com>
Co-authored-by: Gleb Koval <gleb@koval.net>
This commit is contained in:
Ling, Alex
2025-06-05 16:49:36 +00:00
6 changed files with 173 additions and 7 deletions

View File

@@ -0,0 +1,3 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 24H38M38 24L24 10M38 24L24 38" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 228 B

View File

@@ -0,0 +1,134 @@
<script lang="ts">
import arrowRightUrl from "$lib/assets/arrow_right.svg";
import crossUrl from "$lib/assets/cross.svg";
import { onMount } from "svelte";
interface Props {
urls?: string[];
ondelete?: (idx: number) => void;
}
const { urls = [], ondelete }: Props = $props();
let carousel = $state<HTMLDivElement>();
let scrollPosition = $state(0);
let scrollWidth = $state(0);
let clientWidth = $state(0);
function updateScroll() {
scrollPosition = carousel?.scrollLeft || 0;
scrollWidth = carousel?.scrollWidth || 0;
clientWidth = carousel?.clientWidth || 0;
}
onMount(updateScroll);
</script>
<div class="controls">
<div class="carousel" bind:this={carousel} onscroll={updateScroll} onscrollend={updateScroll}>
{#each urls as url, idx (`${idx}|${url}`)}
<div class="item">
<img src={url} alt="carousel item" />
{#if ondelete}
<button class="delete" onclick={() => ondelete(idx)}>
<img src={crossUrl} alt="delete item" />
</button>
{/if}
</div>
{/each}
</div>
{#if scrollPosition > clientWidth / 2}
<button
class="arrow left"
onclick={() => {
if (carousel) carousel.scrollLeft -= carousel.clientWidth;
}}
>
<img src={arrowRightUrl} alt="go to previous" />
</button>
{/if}
{#if scrollPosition < scrollWidth - clientWidth * 1.5}
<button
class="arrow right"
onclick={() => {
if (carousel) carousel.scrollLeft += carousel.clientWidth;
}}
>
<img src={arrowRightUrl} alt="go to next" />
</button>
{/if}
<span class="position">
{Math.round(scrollPosition / clientWidth) + 1} / {urls.length}
</span>
</div>
<style>
.carousel {
display: flex;
overflow-x: auto;
overflow-y: hidden;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
scrollbar-width: none;
}
.controls {
position: relative;
}
.item {
position: relative;
min-width: 100%;
max-width: 100%;
scroll-snap-align: center;
}
.item img {
height: 100%;
width: 100%;
object-fit: contain;
}
.delete,
.position,
.arrow {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
z-index: 10;
border: none;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 9999px;
}
.arrow {
cursor: pointer;
width: 2rem;
aspect-ratio: 1 / 1;
}
.arrow img {
width: 1.4rem;
}
.arrow:hover {
opacity: 0.8;
}
.arrow.left {
left: 0.2rem;
top: 50%;
transform: translateY(-50%);
}
.arrow.left img {
transform: rotate(180deg);
}
.arrow.right {
right: 0.2rem;
top: 50%;
transform: translateY(-50%);
}
.delete {
top: 0.1rem;
right: 0.1rem;
}
.position {
font-size: 0.8rem;
bottom: 0.7rem;
border-radius: 1rem;
right: 0.2rem;
padding: 0.3rem 0.5rem;
background-color: rgba(0, 0, 0, 0.7);
}
</style>

View File

@@ -29,6 +29,7 @@
box-shadow: 0rem 0rem 0.5rem #182125; box-shadow: 0rem 0rem 0.5rem #182125;
align-items: center; align-items: center;
overflow: hidden; overflow: hidden;
z-index: 100;
} }
.logo { .logo {

View File

@@ -3,3 +3,25 @@ import type { Database } from "./database.d.ts";
export type Table<T extends keyof Database["public"]["Tables"]> = export type Table<T extends keyof Database["public"]["Tables"]> =
Database["public"]["Tables"][T]["Row"]; Database["public"]["Tables"][T]["Row"];
export type Enum<T extends keyof Database["public"]["Enums"]> = Database["public"]["Enums"][T]; export type Enum<T extends keyof Database["public"]["Enums"]> = Database["public"]["Enums"][T];
export const availableStudySpaceTags = [
"Quiet",
"Loud",
"Silent",
"Group study",
"Individual study",
"Power outlets",
"No power outlets",
"24/7",
"Food allowed",
"No food allowed",
"Good wifi",
"Bad wifi",
"No wifi",
"Whiteboard",
"Restricted access",
"Hot",
"Air conditioned",
"Cold",
"Cringe"
];

View File

@@ -2,16 +2,19 @@
import Navbar from "$lib/components/Navbar.svelte"; import Navbar from "$lib/components/Navbar.svelte";
import crossUrl from "$lib/assets/cross.svg"; import crossUrl from "$lib/assets/cross.svg";
import placeholder from "$lib/assets/study_space.png"; import placeholder from "$lib/assets/study_space.png";
import Carousel from "$lib/components/Carousel.svelte";
const { data } = $props(); const { data } = $props();
const { space, supabase } = $derived(data); const { space, supabase } = $derived(data);
const imgUrl = $derived( const imgUrls = $derived(
space.study_space_images.length > 0 space.study_space_images.length === 0
? supabase.storage ? [placeholder]
.from("files_bucket") : space.study_space_images.map(
.getPublicUrl(space.study_space_images[0].image_path).data.publicUrl (img) =>
: placeholder supabase.storage.from("files_bucket").getPublicUrl(img.image_path).data
.publicUrl
)
); );
</script> </script>
@@ -22,7 +25,7 @@
</Navbar> </Navbar>
<main> <main>
<img src={imgUrl} alt="the study space" /> <Carousel urls={imgUrls} />
<div class="nameContainer"> <div class="nameContainer">
{space.location} {space.location}
</div> </div>
@@ -61,6 +64,7 @@
margin: 0 auto; margin: 0 auto;
} }
.nameContainer { .nameContainer {
z-index: 10;
display: block; display: block;
width: 100%; width: 100%;
padding: 0.6rem; padding: 0.6rem;

View File

@@ -12,6 +12,7 @@ CREATE TABLE study_spaces (
-- Location within building, e.g., "Room 101" -- Location within building, e.g., "Room 101"
location text, location text,
building_location text, building_location text,
tags text[] NOT NULL DEFAULT array[]::text[],
created_at timestamp with time zone DEFAULT now(), created_at timestamp with time zone DEFAULT now(),
updated_at timestamp with time zone DEFAULT now() updated_at timestamp with time zone DEFAULT now()
); );
@@ -24,6 +25,7 @@ CREATE TABLE study_space_images (
PRIMARY KEY (study_space_id, image_path) PRIMARY KEY (study_space_id, image_path)
); );
-- Triggers -- Triggers
CREATE TRIGGER study_spaces_updated_at CREATE TRIGGER study_spaces_updated_at
AFTER UPDATE ON study_spaces AFTER UPDATE ON study_spaces