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 / PNG
  • img_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.

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 a useT() hook returning t("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