diff --git a/src/lib/components/Navbar.svelte b/src/lib/components/Navbar.svelte
index 7cb89ea..2b8c514 100644
--- a/src/lib/components/Navbar.svelte
+++ b/src/lib/components/Navbar.svelte
@@ -21,11 +21,11 @@
display: flex;
position: sticky;
width: 100%;
- height: 4rem;
+ height: 3.5rem;
top: 0;
left: 0;
right: 0;
- background: linear-gradient(-77deg, #2e4653, #3a5b56);
+ background: linear-gradient(-77deg, #2e4653, #223a37);
box-shadow: 0rem 0rem 0.5rem #182125;
align-items: center;
overflow: hidden;
diff --git a/src/lib/components/SpaceCard.svelte b/src/lib/components/SpaceCard.svelte
index 076eded..0b1626b 100644
--- a/src/lib/components/SpaceCard.svelte
+++ b/src/lib/components/SpaceCard.svelte
@@ -15,7 +15,11 @@
{space.location}
-
{space.description}
+
+ {#each space.tags as tag (tag)}
+ {tag}
+ {/each}
+
@@ -33,7 +37,6 @@
.description {
padding: 0.5rem;
color: #edebe9;
- font-size: 0.875rem;
}
img {
width: 100%;
@@ -41,4 +44,27 @@
aspect-ratio: 1 / 1;
object-fit: cover;
}
+
+ h1 {
+ margin-bottom: 0.5rem;
+ }
+
+ .tagContainer {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.4rem;
+ border-radius: 0.5rem;
+ background: none;
+ }
+
+ .tag {
+ display: flex;
+ align-items: center;
+ border-radius: 0.25rem;
+ background-color: #2e4653;
+ color: #eaffeb;
+ font-size: 0.875rem;
+ cursor: pointer;
+ padding: 0.2rem 0.6rem;
+ }
diff --git a/src/lib/components/inputs/Text.svelte b/src/lib/components/inputs/Text.svelte
index 494a68d..8488479 100644
--- a/src/lib/components/inputs/Text.svelte
+++ b/src/lib/components/inputs/Text.svelte
@@ -22,6 +22,11 @@
font-size: 1rem;
}
+ ::placeholder {
+ color: #859a90;
+ opacity: 1;
+ }
+
input:focus {
border-color: #007bff;
outline: none;
diff --git a/src/lib/components/inputs/Textarea.svelte b/src/lib/components/inputs/Textarea.svelte
index 9ec4ebf..a167e26 100644
--- a/src/lib/components/inputs/Textarea.svelte
+++ b/src/lib/components/inputs/Textarea.svelte
@@ -25,6 +25,11 @@
font-size: 1rem;
}
+ ::placeholder {
+ color: #859a90;
+ opacity: 1;
+ }
+
textarea:focus {
border-color: #007bff;
outline: none;
diff --git a/src/lib/database.d.ts b/src/lib/database.d.ts
index b254ea8..ba2f1c3 100644
--- a/src/lib/database.d.ts
+++ b/src/lib/database.d.ts
@@ -70,6 +70,7 @@ export type Database = {
description: string | null
id: string
location: string | null
+ tags: string[]
updated_at: string | null
}
Insert: {
@@ -78,6 +79,7 @@ export type Database = {
description?: string | null
id?: string
location?: string | null
+ tags?: string[]
updated_at?: string | null
}
Update: {
@@ -86,6 +88,7 @@ export type Database = {
description?: string | null
id?: string
location?: string | null
+ tags?: string[]
updated_at?: string | null
}
Relationships: []
diff --git a/src/lib/index.ts b/src/lib/index.ts
index 72ed306..3b12f80 100644
--- a/src/lib/index.ts
+++ b/src/lib/index.ts
@@ -23,5 +23,6 @@ export const availableStudySpaceTags = [
"Hot",
"Air conditioned",
"Cold",
- "Cringe"
+ "Cringe",
+ "PCs"
];
diff --git a/src/routes/space/+page.svelte b/src/routes/space/+page.svelte
index af46874..4b0f21c 100644
--- a/src/routes/space/+page.svelte
+++ b/src/routes/space/+page.svelte
@@ -7,7 +7,7 @@
import Button from "$lib/components/Button.svelte";
import Images from "$lib/components/inputs/Images.svelte";
import type { Table } from "$lib";
-
+ import { availableStudySpaceTags } from "$lib";
const { data } = $props();
const { supabase } = $derived(data);
@@ -16,7 +16,8 @@
let studySpaceData = $state, "id" | "created_at" | "updated_at">>({
description: "",
building_location: "",
- location: ""
+ location: "",
+ tags: []
});
async function uploadStudySpace() {
@@ -63,6 +64,31 @@
invalidate: ["db:study_spaces"]
});
}
+
+ // Tag
+ let tagFilter = $state("");
+ let tagFilterElem = $state();
+ let filteredTags = $derived(
+ availableStudySpaceTags
+ .filter((tag) => tag.toLowerCase().includes(tagFilter.toLowerCase()))
+ .filter((tag) => !studySpaceData.tags.includes(tag))
+ );
+ let dropdownVisible = $state(false);
+
+ function deleteTag(tagName: string) {
+ return () => {
+ studySpaceData.tags = studySpaceData.tags.filter((tag) => tag !== tagName);
+ };
+ }
+
+ function addTag(tagName: string) {
+ return () => {
+ if (!studySpaceData.tags.includes(tagName)) {
+ studySpaceData.tags.push(tagName);
+ }
+ tagFilter = "";
+ };
+ }
@@ -89,13 +115,60 @@
required
/>
-
+
+
+ {#each studySpaceData.tags as tagName (tagName)}
+
+ {/each}
+
{
+ dropdownVisible = true;
+ }}
+ onblur={() => {
+ dropdownVisible = false;
+ }}
+ onkeypress={(event) => {
+ if (event.key === "Enter") {
+ const tag = filteredTags[0];
+ if (tag) addTag(tag)();
+ }
+ }}
+ placeholder="Add tags..."
+ />
+ {#if dropdownVisible}
+
+ {#each filteredTags as avaliableTag (avaliableTag)}
+
+ {/each}
+
+ {/if}
+
+
+
@@ -111,7 +184,7 @@
type="submit"
disabled={(spaceImgs?.length || 0) === 0 ||
!studySpaceData.location ||
- !studySpaceData.description ||
+ studySpaceData.tags.length === 0 ||
!studySpaceData.building_location ||
uploading}
>
@@ -143,4 +216,82 @@
margin-left: -0.5rem;
width: calc(100% + 1rem);
}
+ .tagDisplay {
+ display: flex;
+ gap: 0.4rem;
+ flex-wrap: wrap;
+ align-items: left;
+ justify-content: left;
+ position: relative;
+ width: 100%;
+ height: auto;
+ padding: 0.5rem;
+ border-radius: 0.5rem;
+ border: 2px solid #eaffeb;
+ background: none;
+ color: #eaffeb;
+ font-size: 1rem;
+ }
+ .tagInput {
+ width: 100%;
+ height: 100%;
+ background: none;
+ color: #eaffeb;
+ font-size: 1rem;
+ border: none;
+ outline: none;
+ }
+ ::placeholder {
+ color: #859a90;
+ opacity: 1;
+ }
+ .tag {
+ display: flex;
+ align-items: center;
+ border-radius: 0.25rem;
+ background-color: #2e4653;
+ color: #eaffeb;
+ font-size: 0.9rem;
+ cursor: pointer;
+ border-width: 0rem;
+ }
+ .tag img {
+ width: 1rem;
+ height: 1rem;
+ margin-left: 0.2rem;
+ }
+
+ .tagDropdown {
+ width: 100%;
+ display: flex;
+ gap: 0.4rem;
+ flex-wrap: wrap;
+ position: absolute;
+ background-color: #2e4653;
+ box-shadow: 1px 1px 0.5rem rgba(0, 0, 0, 0.5);
+ border-radius: 0.5rem;
+ overflow-y: auto;
+ max-height: 10rem;
+ top: 100%;
+ left: 50%;
+ transform: translateX(-50%);
+ }
+
+ .avaliableTag {
+ width: 100%;
+ text-align: left;
+ background: none;
+ border: none;
+ color: #eaffeb;
+ font-size: 0.9rem;
+ margin: 0%;
+ padding: 0 0.8rem 0.4rem;
+ }
+ .avaliableTag:first-child {
+ padding-top: 0.6rem;
+ background-color: hsl(201, 26%, 60%);
+ }
+ .avaliableTag:last-child {
+ padding-bottom: 0.6rem;
+ }
diff --git a/src/routes/space/[id]/+page.svelte b/src/routes/space/[id]/+page.svelte
index b8121e6..0c099dd 100644
--- a/src/routes/space/[id]/+page.svelte
+++ b/src/routes/space/[id]/+page.svelte
@@ -29,11 +29,21 @@
{space.location}
-
- {space.description}
-
+ {#if space.description != null && space.description.length > 0}
+
+ {space.description}
+
+
+ {/if}
+
+ {#each space.tags as tag (tag)}
+
+ {tag}
+
+ {/each}
+
- Where it is:
+ Where it is:
{space.building_location}
@@ -87,7 +97,7 @@
font-size: 1.2rem;
}
- .whereSubtitle {
+ .subtitle {
font-size: 1.2rem;
font-weight: bold;
color: #ffffff;
@@ -98,4 +108,24 @@
font-size: 1.2rem;
padding: 0rem 1.4rem;
}
+
+ .tagContainer {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.4rem;
+ padding: 1.4rem;
+ border-radius: 0.5rem;
+ background: none;
+ }
+
+ .tag {
+ display: flex;
+ align-items: center;
+ border-radius: 0.25rem;
+ background-color: #2e4653;
+ color: #eaffeb;
+ font-size: 1.1rem;
+ cursor: pointer;
+ padding: 0.2rem 0.6rem;
+ }
diff --git a/supabase/migrations/20250605162005_add_tags.sql b/supabase/migrations/20250605162005_add_tags.sql
new file mode 100644
index 0000000..bc9c798
--- /dev/null
+++ b/supabase/migrations/20250605162005_add_tags.sql
@@ -0,0 +1,3 @@
+alter table "public"."study_spaces" add column "tags" text[] not null default ARRAY[]::text[];
+
+