Skip to content

Commit

Permalink
Sun/feat/navbar (#725)
Browse files Browse the repository at this point in the history
* feat: navbar components

* feat: github mark

* feat: navbar option

* feat: border

* refactor: center nav items

* feat: add link to github mark

* feat: collapsible

* refactor: typography

* feat: responsive

* fix: import component

* refactor: collapsible

* fix: minor bugs

* feat: sidebar

* fix: navItems

* refactor: move files

* feat: story book

* fix: shorten display name

* refactor: shorten code

* fix: responsive

* fix: style

* refactor: move file

* fix: migrate to svelte 5

* fix: lint fix

* fix: lint fix + small bugs

* refactor: typography

* fix: small bugs
  • Loading branch information
NhongSun authored Dec 26, 2024
1 parent 1c1856f commit de80bed
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 0 deletions.
4 changes: 4 additions & 0 deletions apps/web/src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { Input } from '@repo/ui/atom/input'
import { RecommendedTag } from '@repo/ui/atom/recommended-tag'
import { CourseCard } from '@repo/ui/molecule/course-card'
import { Navbar } from '@repo/ui/organism/navbar'
let counter = $state(0)
Expand All @@ -15,6 +16,9 @@
}
</script>

<Navbar />
<Navbar isLoggedIn name="Testname testname" />

<h1>Web</h1>

<Button onclick={onButtonClick}>Button</Button>
Expand Down
22 changes: 22 additions & 0 deletions packages/ui/src/components/atom/collapsible/collapsible.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script lang="ts">
import { Collapsible } from 'bits-ui'
import { ChevronDown } from 'lucide-svelte'
import { slide } from 'svelte/transition'
export let name = undefined
</script>

<Collapsible.Root class="relative">
<div class="flex flex-row md:gap-2">
<p class="text-primary text-button1 font-medium">{name}</p>
<Collapsible.Trigger>
<ChevronDown color="#4A70C6" class="hidden md:block" />
</Collapsible.Trigger>
</div>
<Collapsible.Content
class="absolute top-8 right-0 w-28 bg-surface-container border-b-neutral-400 rounded-md"
transition={slide}
>
<slot />
</Collapsible.Content>
</Collapsible.Root>
7 changes: 7 additions & 0 deletions packages/ui/src/components/atom/collapsible/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Root from './collapsible.svelte'

export {
Root as Collapsible,
//
Root,
}
7 changes: 7 additions & 0 deletions packages/ui/src/components/organism/navbar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Root from './navbar.svelte'

export {
//
Root as Navbar,
Root,
}
41 changes: 41 additions & 0 deletions packages/ui/src/components/organism/navbar/navbar.stories.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<script module lang="ts">
import { defineMeta } from '@storybook/addon-svelte-csf'
import { Navbar } from './index.js'
const { Story } = defineMeta<typeof Navbar>({
title: 'Organism/Navbar',
component: Navbar,
tags: ['autodocs'],
argTypes: {
isLoggedIn: {
control: 'boolean',
},
name: {
control: 'text',
},
},
})
</script>

<Story
name="Desktop"
parameters={{ viewport: { defaultViewport: 'tablet' } }}
/>

<Story
name="Desktop & Logged In"
parameters={{ viewport: { defaultViewport: 'tablet' } }}
args={{ isLoggedIn: true, name: 'Testname testname' }}
/>

<Story
name="Mobile"
parameters={{ viewport: { defaultViewport: 'mobile2' } }}
/>

<Story
name="Mobile & Loggin In"
parameters={{ viewport: { defaultViewport: 'mobile2' } }}
args={{ isLoggedIn: true, name: 'Testname testname' }}
/>
184 changes: 184 additions & 0 deletions packages/ui/src/components/organism/navbar/navbar.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
<script lang="ts">
import { Menu, Moon, Search, Settings2 } from 'lucide-svelte'
import { cn } from '@repo/utils'
import { Button } from '../../atom/button'
import { Chip } from '../../atom/chip'
import { Collapsible } from '../../atom/collapsible'
import { IconButton } from '../../atom/icon-button'
import { Input } from '../../atom/input'
import { CUGetRegDarkFull as CUGetRegLogo } from '../../logo/cugetreg'
import { GitHubMark } from '../../logo/vendor'
interface Props {
isLoggedIn?: boolean
name?: string
}
let { isLoggedIn = false, name = undefined }: Props = $props()
let shortenedName = `${name?.split(' ')[0]} ${name?.split(' ')[1]?.charAt(0)}.`
let navItems = ['ค้นหาวิชา', 'จัดตารางเรียน', 'เกี่ยวกับ']
let selected = $state('ค้นหาวิชา')
let collapseItems = ['TEST1', 'TEST2', 'TEST3']
let openSideBar = $state(false)
const toggleSideBar = () => {
openSideBar = !openSideBar
}
</script>

<div
class=" h-20 py-3 px-5 md:py-3 lg:px-10 flex justify-between items-center z-50 border-b-2 border-surface-container-low"
>
<div class="flex flex-row gap-3 items-center xl:gap-6">
<a href="/">
<CUGetRegLogo class="w-24 h-8 lg:w-32 lg:h-10" />
</a>
<div class="relative hidden w-36 lg:w-full md:flex items-center">
<Search
class="absolute right-[15%] my-auto"
size="16"
color="#898EA7"
strokeWidth="3"
/>
<Input
placeholder="ค้นหาวิชา"
class="w-11/12 xl:w-52 bg-surface-container-lowest placeholder:text-neutral-400"
/>
</div>
</div>
<div
class="hidden absolute left-1/2 transform -translate-x-1/2 md:flex flex-row justify-center items-center gap-3 lg:gap-4"
>
<!-- To be implemented: add page from navItems-->
{#each navItems as item}
<a
class={cn(
'text-neutral-500 text-button1 font-medium text-nowrap xl:w-32 text-center cursor-pointer hover:text-neutral-800',
selected === item && 'text-primary',
)}
onclick={() => (selected = item)}
href="/"
>
{item}
</a>
{/each}
</div>
<div class="flex flex-row justify-between items-center gap-2 md:gap-4">
<a
href="https://github.com/thinc-org/cugetreg"
target="_blank"
rel="noreferrer"
class="hidden md:flex"
>
<GitHubMark class="w-8 h-8 text-neutral-500 " />
</a>
<IconButton color="neutral" class="hidden md:flex"
><Moon strokeWidth="3" size="16" /></IconButton
>
{#if isLoggedIn}
<!-- To be implemented: Collapsible component -->
<Collapsible name={shortenedName}>
{#each collapseItems as item}
<p class="p-2 cursor-pointer">{item}</p>
{/each}
</Collapsible>
{:else}
<!-- To be implemented: add real href in Button -->
<Button href="login" class="w-24 md:w-28"
><p class="font-medium text-button2">เข้าสู่ระบบ</p></Button
>
{/if}
<IconButton variant="ghost" class="md:hidden" onclick={toggleSideBar}>
<Menu size="16" strokeWidth="3" color="#353745" />
</IconButton>
</div>

{#if openSideBar}
<div
class="fixed inset-0 bg-[#353745CC]/80 backdrop-blur-[3px] z-10"
role="button"
tabindex="0"
aria-label="Close sidebar"
onclick={toggleSideBar}
onkeydown={(e) => e.key === 'Enter' && toggleSideBar()}
></div>
{/if}
<div
class={cn(
'fixed top-0 right-0 flex flex-col justify-between h-screen bg-surface z-50 transform transition-transform duration-300 ease-in-out',
openSideBar ? 'translate-x-0' : 'translate-x-full',
)}
hidden={!openSideBar}
>
<div class="p-3 flex flex-col gap-5">
<div class="flex flex-row gap-2">
<IconButton variant="ghost" class="md:hidden" onclick={toggleSideBar}>
<Menu size="16" strokeWidth="3" color="#353745" />
</IconButton>
<div class="w-48 flex flex-col gap-2">
<p class="text-on-surface-placeholder text-caption">
คุณกำลังจัดตารางเรียน...
</p>
<p class="text-primary text-subtitle">
ปี 2 ภาคฤดูร้อนที่ยาวมาก บลาบลา
</p>
<Chip class="w-32 flex items-center text-nowrap justify-center"
>นานาชาติ 66 / ฤดูร้อน</Chip
>
</div>
<IconButton variant="ghost">
<Settings2 size="16" strokeWidth="2.5" color="#353745" />
</IconButton>
</div>
<div class="relative flex items-center px-3">
<Search
class="absolute right-6 my-auto"
size="16"
color="#898EA7"
strokeWidth="3"
/>
<Input
placeholder="ค้นหาวิชา"
class="w-full h-8 bg-surface-container-lowest placeholder:text-neutral-400"
/>
</div>
<div class="flex flex-col px-3 gap-3">
{#each navItems as item}
<a
class={cn(
'text-neutral-500 text-button1 font-medium cursor-pointer hover:text-neutral-800',
selected === item && 'text-primary',
)}
onclick={() => {
selected = item
toggleSideBar()
}}
href="/"
>
{item}
</a>
{/each}
</div>
</div>
{#if isLoggedIn}
<div
class="flex flex-row gap-2 p-3 items-center border-t-2 border-surface-container-low"
>
<img
src="https://upload.wikimedia.org/wikipedia/commons/a/ac/Default_pfp.jpg"
alt="profile pic"
class="w-10 h-10 rounded-full"
/>
<div class="flex flex-col">
<p class="text-on-surface text-subtitle font-medium">{name}</p>
<p class="text-on-surface-placeholder text-body2 font-medium">
6XXXXXXXXX
</p>
</div>
</div>
{/if}
</div>
</div>

0 comments on commit de80bed

Please sign in to comment.