Customization Guide
SkoolyHub is built to be rebranded and re-themed without touching code. Almost everything below is done from the admin Theme Options panel (/admin/settings/theme); changes persist to the database and uploaded assets go to Cloudflare R2, so no rebuild is needed. This guide also points to where each setting lives in code when you want to go deeper.
Theming & Appearance
Path: /admin/settings/theme
Theme settings are saved through GET/PUT /api/v1/admin/theme-settings and applied to the public site at runtime. The public site is wrapped in a .site-theme element so public site theming never affects the admin UI.
Colors
Brand colors are CSS variables defined in src/app/globals.css and overridden per-token from the admin panel. The token map lives in src/lib/theme-tokens.ts; each token has a CSS variable, a settings key, and light/dark defaults:
| Token (settings key) | CSS variable | Light default | Dark default |
|---|---|---|---|
primary_color |
--primary |
#CD4323 (terracotta) |
#E8734F |
primary_fg |
--primary-foreground |
#FFFFFF |
#2A1206 |
secondary_color |
--secondary |
#334155 |
#1E293B |
accent_color |
--accent |
#F7D9CF |
#7C2D12 |
text_color |
--foreground |
#1E293B |
#E2E8F0 |
bg_color |
--background |
#FFFFFF |
#0F172A |
border_color |
--border |
#E2E8F0 |
#334155 |
success_color |
--success |
#16A34A |
#22C55E |
warning_color |
--warning |
#F59E0B |
#FBBF24 |
destructive_color |
--destructive |
#DC2626 |
#EF4444 |
Each token has a dark variant (settings key suffixed _dark). Dark mode is scoped to .site-theme.dark. Change a token once and every component that consumes the variable updates — never hardcode hex values in components.
Typography
Pick a heading font and a body font (Raleway, Lexend, Inter, Poppins, Roboto, Playfair Display, Montserrat, Lato, Open Sans) and a base font size (14–18px). Selections are applied at runtime.
Layout & surfaces
The panel exposes tabs for Appearance (theme mode light/dark/system, gradient surfaces for banner, hero, page headers, footer, CTA, auth), Header (layout, logo/nav alignment, colors, sticky/transparent, search), Menu/Navigation (active color, mobile menu, megamenu mode, pagination type, page size), Footer (background, content background, text/link colors, social icons, back-to-top, copyright), Homepage (section order, stats, intro block), and Hero Slider display (width, height, autoplay, pagination, arrows).
Brand & Site Settings
Path: /admin/settings/theme → General tab
| Field | Purpose |
|---|---|
business_name |
Display name across the site |
legal_name |
Registered company name |
business_description |
Used in meta description / SEO |
website |
Main website link |
logo |
Horizontal logo (transparency preserved) |
app_icon |
Square 1:1 app icon |
favicon |
Browser-tab icon |
placeholder_image |
Fallback when an image is missing |
app_status |
active / inactive / coming_soon |
maintenance_mode |
Show a maintenance page to visitors |
Fee heads, per-class fee structures and concessions live under Fees → Fee Setup.
Images
The Images tab controls the image pipeline used everywhere uploads happen (admin upload → sharp resize/convert → R2):
img_format— WebP / JPG / PNGimg_quality— 1–100 (default 82)img_delete_original— keep or discard the original- Per-type dimensions (
WIDTHxHEIGHT, comma-separated) for avatar, cover photo, category, blog, logo, app icon and partner logo.
Navigation menus
Header and footer menus are managed separately from theme colors via the MenuBuilder in the theme page (stored in a menu_items table; nestable via parent_id), edited through /api/v1/admin/menu-items.
Custom code
Inject header_scripts (into <head>), footer_scripts (before </body>), and custom_css for one-off overrides without editing source.
Editing Site Content (CMS)
Each public site surface is editable from its own admin page. Content lives in dedicated tables and is rendered on the public site.
| Content | Admin page | Editable fields |
|---|---|---|
| Hero slider | /admin/hero-slider |
eyebrow, title + highlight, subtitle, desktop/tablet/mobile images, primary & secondary CTAs, sort order, active |
| Pages | /admin/pages |
slug, title, subtitle, markdown content, image, banner, tags, SEO, per-language translations |
| Theme Builder | /admin/theme-builder |
header, footer, and menu templates for the active theme (block builder) |
| About | /admin/about |
header, hero overlay, Our Story, values, team, journey timeline, stats, SEO |
| Why Choose Us | /admin/why-choose-us |
section title/subtitle, main image, icon/image + title + description items |
| FAQs | /admin/faqs |
category, question, answer, sort order, active |
| Gallery | /admin/gallery |
title, type (image/video), category, tags, description, multi-image, SEO |
| Testimonials | /admin/testimonials |
name, relationship to the school, rating, message, photo, sort order, active |
| Partners | /admin/partners |
name, logo, website URL, sort order, active |
| Blog | /admin/blogs (+ /categories) |
title, slug, category, author, excerpt, markdown content, image, tags, published |
Long-form fields (page content, blog posts, FAQ answers) accept Markdown; image fields run through the optimization pipeline described above.
Message & Notification Templates
Path: /admin/settings/notifications
Transactional templates are managed per channel — Email, SMS, and WhatsApp. A template has a name, category, channel, and (for email) subject, preheader, and from fields, plus a body. Bodies use {{token}} placeholders that are substituted at send time. Commonly available tokens include:
{{first_name}}, {{last_name}}, {{email}}, {{otp}}, {{student_name}}, {{class_name}}, {{section_name}}, {{invoice_no}}, {{receipt_no}}, {{amount}}, {{currency}}, {{due_date}}, {{exam_name}}, {{date}}, {{dashboard_url}}, {{reset_link}}, {{verify_link}}.
Email bodies accept HTML; WhatsApp bodies use WhatsApp markdown (*bold*, _italic_). The editor offers a live preview with sample data, and broadcasts can target all users, a role, or specific recipients. School events — absence alerts, invoice and receipt notices, circulars, result publication and leave decisions — send through these templates across Email, SMS and push.
Adapting the Vocabulary
Different schools call the same things by different names — class or grade, section or division, guardian or parent. You do not need to touch code to change any of them.
Every user-facing string goes through the translation layer, so retitling is a translation edit under Admin → Settings → Languages. Change "Class" to "Grade" once and it changes on every screen, in the apps, and in email templates.
An earlier version of this product shipped a vertical pack system for switching what the site sells. It was removed — with a single vertical there was nothing to switch between. If you are reading older notes that mention Admin → Master Data → Vertical packs, that tab no longer exists.
Master Data — The Lists You Can Edit
Admin → Settings → Master Data holds every lookup list in the product, so most "can I change this dropdown" questions end here:
| Kind | Used by |
|---|---|
blood_group, student_category, house |
Student records |
designation, department, employment_type, qualification |
Staff records |
guardian_relation |
Guardian links |
admission_source |
Admissions and students |
leave_type |
Leave requests |
exam_type |
Examinations |
circular_category |
Communication |
payment_mode |
Fee collection |
transport_mode, room |
Transport and timetabling |
book_category |
Library |
Each item has a name, an optional icon or image, a sort order and an active flag. Deactivating one keeps existing records intact while removing it from future dropdowns.
What you cannot edit, and why
Attendance statuses, invoice statuses and admission stages are not in Master Data. They are TypeScript unions, because queries depend on their exact values — an admin renaming "absent" would break the attendance report, whereas renaming a designation must break nothing. That distinction is deliberate, and it is why there are two mechanisms rather than one.
If you need different wording for a status, translate it. The stored value stays stable while the label changes.
Languages & Internationalization
Path: /admin/settings/languages
SkoolyHub ships a lightweight i18n system (src/lib/i18n.ts). Translation strings are split by surface (frontend / backend) and keyed by the English source string, so any string falls back to English when not translated.
- Manage languages on the Languages screen: code, name, native name, flag emoji, locale, script, and direction (LTR/RTL). You can set a default language and mark languages active/inactive.
- English is the default source language and the fallback for any untranslated string; add further languages (including RTL languages such as Arabic) from the Languages screen.
- Open the translation editor from a language row (the globe action) to edit per-language translations of UI strings:
/admin/settings/languages/[id]/translations. - Server code translates via
getT(lang, scope)/getServerT(scope); admin UI uses auseT()hook returningt("English string").
Locale-related defaults (default language, multi-language switcher, timezone, date format) also live in the theme panel's Localization tab.
© CreativeCape Solutions · creative-cape.com · support@creative-cape.com