Bila UiTM Cuti

Bila UiTM Cuti academic calendar and Find My Internship — what ships on bilauitmcuti.com and the design system both features share.

Every semester, UiTM students ask bila cuti? Bila UiTM Cuti is a student-focused web app for academic calendar timelines plus Find My Internship on the same domain.

The Problem

AreaPain point
Academic calendarPDFs and portal pages — not mobile-friendly, not searchable
Group A / Group BWrong group checked → wrong cuti date
Schedule coverageNo single view for registration, lectures, exams, and breaks
InternshipsListings spread across job portals and company career pages
Search costHours lost each application season opening separate sites

The Solution

FeatureURLRole
Academic calendarbilauitmcuti.comRegistration, lectures, exams, and breaks in one app
Find My Internshipbilauitmcuti.com/internshipBrowse internship listings on the same domain
Design systemBoth surfacesShared tokens, type, and components

Academic calendar

Built for phones, tablets, and desktop — same experience across grid and list views.

Bila UiTM Cuti chat page 1 of 4

CapabilityDetail
ViewsGrid and list with activity filters
SessionsGroup A and Group B
RegionsKedah, Kelantan, and Terengganu date filters
CountdownNext activity
ThemeLight and dark
InstallPWA
AI chatGoogle Gemma 4, Llama 4 Scout, Mistral Small 3.1, Nemotron 3 Super on Cloudflare Workers AI — English and Malay
Calendar monitoringFirecrawl — watches the official UiTM academic calendar site for changes
ProgramSupported
Foundation / ProfessionalYes
Pre-DiplomaYes
DiplomaYes
Diploma (Part-Time)Yes
BachelorYes
Bachelor (Part-Time)Yes
MasterYes
PhDYes
AI assistantDetail
HostCloudflare Workers AI
ModelsGoogle Gemma 4, Llama 4 Scout, Mistral Small 3.1, Nemotron 3 Super
LanguagesEnglish, Malay
ContextSelected program and schedule
LimitationAnswers may be incomplete or outdated — verify with official UiTM sources

Find My Internship

URLbilauitmcuti.com/internship
Same domain as calendarNo separate site or student account
SourcesJob portals and company career pages
ScrapingFirecrawl — keeps listings fresh across sources
Per listingRole, company, duration, stipend range, source
BrowseLoad more in one place instead of many tabs

One design system for both features

SurfaceShared treatment
CalendarSemantic tokens, typography, components, dark mode
Find My InternshipSame shell — no visual jump between grid and listings
GoalOne product feel on bilauitmcuti.com and /internship

The sections below document tokens and components used in production.

Stack

Production stack for bilauitmcuti.com:

LayerProduction choice
FrameworkNext.js App Router + React 19
StylingTailwind CSS v4
Componentsshadcn/ui — Base UI
HostingCloudflare Pages + Workers
AI modelsGoogle Gemma 4, Llama 4 Scout, Mistral Small 3.1, Nemotron 3 Super via Cloudflare Workers AI
Web monitoring & scrapingFirecrawl — official calendar monitoring + internship listing scrape
Internship dataCloudflare D1
Themingnext-themes (light / dark)
FontsGeist Sans + Geist Mono
Production source
I wrote this documentation from the app I ship and maintain. The stack below is what runs at bilauitmcuti.com

Framework

Next.js App Router + React 19

Styling

Tailwind CSS v4 (@import 'tailwindcss')

Component primitives

shadcn/ui — Base UI

Base UI

Dialog, Select, Popover, Tooltip, etc.

Icons

Lucide React

Theming

next-themes (class-based light / dark)

Fonts

Geist Sans

Geist Mono

Utilities

cn() — clsx + tailwind-merge

Hosting

Cloudflare Pages + Workers

AI model

Google Gemma 4, Llama 4 Scout, Mistral Small 3.1, Nemotron 3 Super (Cloudflare Workers AI)

Web monitoring & scraping

Firecrawl

Internship storage

Cloudflare D1

Semantic tokens

PrinciplePractice
Role over hexSurfaces declare card, popover, or muted — colour is decided once
Theme flipComponents inherit tokens; no per-layout hardcoded colours
New tokensglobals.css@theme inline → Tailwind utilities
LayerDetail
1CSS custom properties — :root / .dark
2@theme inline--color-* bridge
3Tailwind utilities — bg-background, rounded-lg
TokenCSS variableUtilityRole
Background--backgroundbg-backgroundPage / app shell
Foreground--foregroundtext-foregroundPrimary text
Card--cardbg-cardCard surfaces
Card foreground--card-foregroundtext-card-foregroundCard text
Popover--popoverbg-popoverPopovers, menus, tooltips shell
Popover foreground--popover-foregroundtext-popover-foregroundPopover text
Primary--primarybg-primaryPrimary actions
Primary foreground--primary-foregroundtext-primary-foregroundText on primary
Secondary--secondarybg-secondarySecondary surfaces, chips
Muted--mutedbg-mutedSubtle backgrounds
Muted foreground--muted-foregroundtext-muted-foregroundHelper text
Accent--accentbg-accentHover / focus fills
Destructive--destructivebg-destructiveErrors, destructive actions
Border--borderborder-borderBorders
Input--inputborder-inputForm fields
Ring--ringring-ringFocus rings
Surface elevated--surface-elevatedbg-surface-elevatedElevated dark-mode surfaces
Chart 1–5--chart-1--chart-5bg-chart-*Admin chart series

Where each format lives

  • Token flow: CSS custom properties (:root / .dark) → @theme inline { --color-* } → Tailwind utilities (bg-background, text-muted-foreground).
  • Add new tokens in app/globals.css, bridge in @theme inline, then use as Tailwind utilities.
  • Domain colours extend lib/calendar-activity-colors.ts or lib/data.ts — never scatter hex in components.
  • Activity colour map is shared by grid-view.tsx, calendar-header.tsx, and the legend (previously duplicated).

Token previews follow the site theme. Press D to toggle light/dark.

Background

bg-background

Page / app shell

Foreground

text-foreground

Primary text

Card

bg-card

Card surfaces

Card foreground

text-card-foreground

Card text

Popover

bg-popover

Popovers, menus, tooltips shell

Popover foreground

text-popover-foreground

Popover text

Primary

bg-primary

Primary actions, dark-mode toggle track

Primary foreground

text-primary-foreground

Text on primary

Secondary

bg-secondary

Secondary surfaces, chips

Secondary foreground

text-secondary-foreground

Text on secondary

Muted

bg-muted

Subtle backgrounds

Muted foreground

text-muted-foreground

Secondary / helper text

Accent

bg-accent

Hover / focus fills

Accent foreground

text-accent-foreground

Text on accent

Destructive

bg-destructive, text-destructive

Errors, destructive actions

Border

border-border

Borders

Input

border-input, bg-input/30

Form fields

Ring

ring-ring

Focus rings (ring-3 ring-ring/50)

Surface elevated

bg-surface-elevated

Elevated dark-mode surfaces

Chart 1

bg-chart-1

Admin — page views

Chart 2

bg-chart-2

Admin — unique visitors

Chart 3

bg-chart-3

Internship submissions

Chart 4

bg-chart-4

Bounce rate

Chart 5

bg-chart-5

Reserved / future

Light shell

#ffffff

Dark shell

#1a1a1a

Elevated dark surface

#2A2A2A

Dark mode

LightDark
ApproachDeliberate paletteParallel design — not an inversion
Colour spaceOKLCHPerceived lightness stays consistent across modes
FlashBlocked before hydrationNo wrong-theme flicker on first paint
ShellBackgroundText
Light#ffffff#1a1a1a
Dark#1a1a1a#ffffff
Elevated dark#2A2A2A
NoteDetail
ModesLight (default) and dark only — enableSystem: false
StoragelocalStorage key theme; class on html
PWAtheme-color synced to shell pair
TransitionsDisabled on theme/colour change — instant switch

Theme preview follows the site toggle. Switch is instant with no colour fade.

App shell before hydration#ffffff

Next break

Mid-semester

12 days left

View calendarShare
  • Two modes only: light (default) and dark — enableSystem: false.
  • Theme stored in localStorage key theme; class toggled on html.
  • PWA theme-color follows shell pair (#ffffff light, #1a1a1a dark), synced by theme-toggle.tsx.
  • @custom-variant dark (&:is(.dark *)); and standalone (@media (display-mode: standalone)) for PWA header tweaks.
  • Transitions disabled globally on theme/color changes — instant switch.

Calendar colour language

ActivityAccentReads as
RegistrationGray #d1d5dbNeutral, administrative
LecturePurple #8b5cf6Teaching — brand colour
ExaminationRed #dc2626Tense accent
BreakGreen #10b981Positive accent
School holidayAmber #f59e0bSecondary hierarchy
WeekendGray-violet #71717aLowest priority
ProgramLightDark
Pre-Diploma#D97706#FBBF24
Diploma#0891B2#22D3EE
Part-Time#65A30D#A3E635
Bachelor#DB2777#F472B6
Master#7C3AED#A78BFA
PhD#BE123C#FDA4AF
All Students#3f3f46#e4e4e7

Title accent in the live app

Bila UiTM Cuti

Mon 12

Registration

#d1d5db

Mon 12

Lecture

#8b5cf6

Mon 12

Examination

#dc2626

Mon 12

Break

#10b981

Mon 12

School Holiday

#f59e0b

Mon 12

Weekend

#71717a

Program badges in list view

Pre-DiplomaDiplomaPart-TimeBachelorMasterPhDAll Students

In the app: bg-[colour]/10 with matching text, plus dark-mode variants per program.

Elevation & radius

LayerToken
Base surfacebackground
Cardscard
Elevated (chat, overlays)surface-elevated
TokenValueUtilityUsage
Base0.625rem (10px)rounded-lgDefault reference
Smallcalc(var(--radius) - 4px)rounded-sm
Mediumcalc(var(--radius) - 2px)rounded-mdButtons, inputs
Largevar(--radius)rounded-lg
XLcalc(var(--radius) + 4px)rounded-xlCards
2XLcalc(var(--radius) * 1.8)rounded-2xl
3XLcalc(var(--radius) * 2.2)rounded-3xl
4XLcalc(var(--radius) * 2.6)rounded-4xlBadges

Base

rounded-lg

Default reference

Small

rounded-sm

Medium

rounded-md

Buttons, inputs

Large

rounded-lg

XL

rounded-xl

Cards

2XL

rounded-2xl

3XL

rounded-3xl

4XL

rounded-4xl

Badges

Motion & typography

Motion ruleDetail
Theme / colour changeInstant — transitions disabled globally
Chat headertransform / translate 300ms — deliberate exception
Nav hoverForeground colour on hover, desktop only
Control hoverOpacity-only transitions (100ms)
Gradient fades24px fades using var(--background) on chat/calendar fades
Theme switchNo cross-dissolve on colour changes
ContextClassesSample
Calendar hero titletext-5xl font-semibold tracking-tightSemester 1 2025/2026
Card titlefont-heading text-base font-mediumNext break
Body / UItext-smForms, chat, controls
Muted copytext-muted-foregroundDays until mid-semester break
Tooltipstext-xsTap to view full calendar
Chat inputtext-smAsk when the next break is…
z-indexUsage
z-[9]Chat / calendar top fade
z-35Calendar scroll-restore overlay
z-40Calendar controls sticky
z-[60]Fixed calendar controls (mobile)
z-[9999]Version banner

Calendar hero title

Geist Sans
text-5xl font-semibold tracking-tight

Semester 1 2025/2026

lib/calendar-title-styles.ts

Card title

Geist Sans
font-heading text-base font-medium

Next break

Body / UI

Geist Sans
text-sm

Forms, chat, and controls — default 14px

Muted copy

Geist Sans
text-muted-foreground

Days until mid-semester break

Tooltips

Geist Sans
text-xs

Tap to view full calendar

Chat input

Geist Sans
text-sm

Ask when the next break is…

Below 16px-equivalent can trigger iOS zoom-on-focus

Chat header

transform/translate transition 300ms — the one deliberate motion exception.

Nav hover

Foreground colour on hover, desktop only (@media (hover: hover)).

Control hover

Most controls use opacity-only transitions (100ms).

Gradient fades

24px fades using var(--background) on .chat-input-area::before, .chat-top-fade, .calendar-controls-fade, and .suggestions-fade-left/-right.

Responsive shell

.responsive-shell-bg forces white in light mode, var(--popover) in dark.

Theme switch

Transitions disabled globally on theme/color changes — instant switch, no fade.

Z-index layers

z-[9]Chat / calendar top fade
z-35Calendar scroll-restore overlay
z-40Calendar controls sticky
z-[60]Fixed calendar controls (mobile)
z-[9999]Version banner

Components

LayerSource
Primitivesshadcn/ui + Base UI — dialogs, tooltips, focus
Custom identityCalendar colours, type scale, elevated surfaces, pill badges
Admin chartsChart series tokens for views, visitors, submissions
Button variantUse
defaultPrimary CTA
outlineSecondary, bordered
secondarySoft filled
ghostIcon / toolbar
destructiveDelete / dangerous
linkInline text actions
Component
alert
avatar
badge
button
card
chart
context-menu
dialog
drawer
dropdown-menu
kbd
markdown-renderer
popover
select
sonner
table
tabs
textarea
tooltip

Button variants

defaultoutlinesecondaryghostdestructivelink
  • defaultPrimary CTA
  • outlineSecondary, bordered
  • secondarySoft filled
  • ghostIcon / toolbar
  • destructiveDelete / dangerous
  • linkInline text actions

Badge variants

defaultsecondarydestructiveoutlineghostlink

Focus & invalid states

Shared focus ring: focus-visible:ring-3 ring-ring/50. Invalid fields pick up destructive ring via aria-invalid.

On X
S
Shahrul@shahrulestar

Thanks @shadcn, for the new components.

Screenshot shared by Shahrul Estar
4likes408views
S
shadcn@shadcn

Replying to @shahrulestar

Neat.

4likes407views

Comment from shadcn, the creator of shadcn/ui and a Design Engineer at Vercel, on a design I shared.

Bila UiTM Cuti
very convenient to check for the events that happening during the week, easy and fast to access .
Good page wish we can personalized it to fit every student
Mantap. Well organised, i love the layout, easy to locate and understand
i am so thankful for the developer, as someone who studies business tech i see big opportunities and talent right here, thank you for developing the websites it is really convenience and easy to use and it helps me mentally, seeing the calendar helps me to cope lagi-lagi time mentally drained and burnout, like knowing the fact that i hv 2wks left to finish my deg, and my 2mnths break, comforts me
Good for all students and also new students to refer but at least if cuti semester making it counting day it could be better so they know on the day the press the button "OUH they still have a days untuk cuti"
Good website and very interactive, keep it up!
Useful to see specific weeks, pretty good
THANK YOUUU FOR MAKING THIS APP
Nice and very helpful
very nice, me likey
Thank you for doing this!!! Genuinely appreciated
Best! Senang nak track cuti and beli ticket balik.
Good apps for students to refer ourselves to academic calendar
syiokk senang nak set timing balik umah instead of bukak calendar kena kira sendiri
thank you for creating this app that really helps me navigate my holidays, i live what you're doing here, it's beneficial to many students

Feedback from UiTM students on the academic calendar app.