feat: migrate course UI from supabase (#615)

* chore: fix storybook build

* chore: implement theming

* community list not showing properly

* refactor: migrate Chip component to @cio/ui/custom/chip

- Updated imports for the Chip component across multiple files to use the new location in the @cio/ui package.
- Replaced the previous Chip implementation with a new version that utilizes a Badge for better styling and functionality.
- Adjusted related components to ensure consistent usage of the updated Chip component.

* fix: align course sidebar design to match organization design (#611)

* fix: align course sidebar design to match organization design

* feat: add hideSearch prop to AppHeader and update sidebar layout

---------

Co-authored-by: Rotimi Best <best@classroomio.com>

* refactor: replace PrimaryButton with Button component across multiple files

- Updated various components to use the new Button component from @cio/ui/base/button instead of the deprecated PrimaryButton.
- Ensured consistent button usage throughout the application for improved styling and functionality.
- Removed the PrimaryButton component and its associated constants from the codebase.

* refactor: standardize button and input usage across components

- Replaced instances of deprecated components such as TextField, TextArea, and IconButton with their updated counterparts (InputField, TextareaField, and updated IconButton).
- Ensured consistent event handling by changing `onClick` to `onclick` for better alignment with Svelte's event binding conventions.
- Removed unused components and streamlined imports to enhance code maintainability and readability.

* chore: themeing, course card, use $features

* refactor: centralize UI components and update modal implementations

- Refactored various components to centralize UI elements, improving discoverability and maintainability.
- Replaced deprecated modal components with the new Dialog component for consistent modal behavior across the application.
- Removed unused components and streamlined imports to enhance code clarity and reduce complexity.

* feat: add new documentation and refactor org and lms UI components

- Introduced new documentation files for Auth Flow, Breadcrumbs Refactoring, Page and Route Creation, and Route Page Setup to enhance developer onboarding and reference.
- Refactored various UI components, including the Course Sidebar and Lesson Modal, to improve layout and functionality.
- Removed deprecated components and streamlined imports for better maintainability.
- Updated translations across multiple languages to ensure consistency in user experience.

* refactor: update UI components and improve styling consistency

- Refactored various components to enhance styling consistency, including updates to button and text color classes.
- Removed deprecated components and streamlined imports for better maintainability.
- Replaced instances of PageBody with a more flexible Page component structure across multiple routes.
- Updated translations and UI elements to align with the new design system.
- Deleted unused components to reduce code complexity and improve clarity.

* update output.css

---------

Co-authored-by: Abdulmuizz Hamzat <103611443+canhamzacode@users.noreply.github.com>
This commit is contained in:
Rotimi Best
2025-12-22 02:36:48 +01:00
committed by GitHub
co-authored by Abdulmuizz Hamzat
parent e6a3cf9332
commit 9fb6c7cbaa
401 changed files with 10489 additions and 11679 deletions
@@ -1,5 +1,5 @@
import { lesson } from '$lib/components/Course/components/Lesson/store/lessons';
import { snackbar } from '$lib/components/Snackbar/store';
import { snackbar } from '$features/ui/snackbar/store';
export function formatYoutubeVideo(url: string, errors: Record<string, string>) {
console.log(`url`, url);
@@ -1,4 +1,4 @@
import { appInitApi } from '$lib/features/app/init.svelte';
import { appInitApi } from '$features/app/init.svelte';
import { authClient } from '$lib/utils/services/auth/client';
import { capturePosthogEvent } from '$lib/utils/services/posthog';
import { goto } from '$app/navigation';
+39 -85
View File
@@ -1,51 +1,17 @@
import { tc } from '$lib/utils/functions/trycatch';
import { darken, lighten } from 'color2k';
function updateThemeClassInBody(newClass: string, customRegex?: string) {
const regex = /theme-[\w]+/gi;
document.body.className = document.body.className.replace(customRegex ?? regex, newClass);
}
import { tc } from '$lib/utils/functions/trycatch';
export function setTheme(_theme?: string) {
const theme = _theme || '';
// this condition checks if it's a hex code from the db or a specified theme
if (theme && !theme.includes('theme-')) {
// add the "custom-theme" styles to the head tag
injectCustomTheme(theme);
// add the "custom-theme" classname to the head tag
setCustomTheme('theme-custom');
} else if (!theme && document.body.className.includes('theme-')) {
// if no theme and a theme is already applied, remove it
updateThemeClassInBody(theme);
return;
}
// In case theme already exists in dom, don't add
if (document.body.className.includes(theme)) return;
// set the new theme
export function setTheme(theme: string) {
localStorage.setItem('theme', theme);
document.body.className = document.body.className.concat(' ', theme);
}
export function setCustomTheme(theme?: string) {
// In case the default theme is added but another theme exists
if (!theme && document.body.className.includes('theme-')) {
updateThemeClassInBody(theme || '');
return;
}
if (theme.includes('#')) {
const escapedHex = theme.replace(/"/g, '\\"');
document.body.setAttribute('data-theme', escapedHex);
// Remove any class starting with "theme-"
updateThemeClassInBody('');
const _theme = theme || '';
// Add the new theme if it doesn't already exist
if (!document.body.className.includes(_theme)) {
localStorage.setItem('theme', _theme);
document.body.className = document.body.className.concat(' ', _theme);
injectCustomTheme(escapedHex);
} else {
document.body.setAttribute('data-theme', theme);
}
}
@@ -54,10 +20,8 @@ const _lighten = (hex: string, no: number) => tc(() => lighten(hex, no), hex);
const _darken = (hex: string, no: number) => tc(() => darken(hex, no), hex);
export function injectCustomTheme(hex: string) {
const styleId = 'theme-custom';
let styleElement = document.getElementById(styleId);
// generate shades using color2k's lighten function
// Generate shades using color2k's lighten/darken functions
// Following the same pattern as predefined themes (e.g., purple)
const shades = {
50: _lighten(hex, 0.7),
100: _lighten(hex, 0.6),
@@ -72,46 +36,36 @@ export function injectCustomTheme(hex: string) {
};
const styleContent = `
.theme-custom .bg-primary-50 { background-color: ${shades[50]} !important; }
.theme-custom .bg-primary-100 { background-color: ${shades[100]} !important; }
.theme-custom .bg-primary-200 { background-color: ${shades[200]} !important; }
.theme-custom .bg-primary-300 { background-color: ${shades[300]} !important; }
.theme-custom .bg-primary-400 { background-color: ${shades[400]} !important; }
.theme-custom .bg-primary-500 { background-color: ${shades[500]} !important; }
.theme-custom .bg-primary-600 { background-color: ${shades[600]} !important; }
.theme-custom .bg-primary-700 { background-color: ${shades[700]} !important; }
.theme-custom .bg-primary-800 { background-color: ${shades[800]} !important; }
.theme-custom .bg-primary-900 { background-color: ${shades[900]} !important; }
body[data-theme="${hex}"] {
--primary: ${shades[600]};
--primary-foreground: ${shades[50]};
--ring: ${shades[400]};
--chart-1: ${shades[300]};
--chart-2: ${shades[500]};
--chart-3: ${shades[600]};
--chart-4: ${shades[700]};
--chart-5: ${shades[800]};
--sidebar-primary: ${shades[600]};
--sidebar-primary-foreground: ${shades[50]};
--sidebar-accent: ${shades[50]};
--sidebar-accent-foreground: ${shades[700]};
--sidebar-ring: ${shades[400]};
}
.theme-custom .text-primary-50 { color: ${shades[50]} !important; }
.theme-custom .text-primary-100 { color: ${shades[100]} !important; }
.theme-custom .text-primary-200 { color: ${shades[200]} !important; }
.theme-custom .text-primary-300 { color: ${shades[300]} !important; }
.theme-custom .text-primary-400 { color: ${shades[400]} !important; }
.theme-custom .text-primary-500 { color: ${shades[500]} !important; }
.theme-custom .text-primary-600 { color: ${shades[600]} !important; }
.theme-custom .text-primary-700 { color: ${shades[700]} !important; }
.theme-custom .text-primary-800 { color: ${shades[800]} !important; }
.theme-custom .text-primary-900 { color: ${shades[900]} !important; }
.theme-custom .border-primary-50 { border-color: ${shades[50]} !important; }
.theme-custom .border-primary-100 { border-color: ${shades[100]} !important; }
.theme-custom .border-primary-200 { border-color: ${shades[200]} !important; }
.theme-custom .border-primary-300 { border-color: ${shades[300]} !important; }
.theme-custom .border-primary-400 { border-color: ${shades[400]} !important; }
.theme-custom .border-primary-500 { border-color: ${shades[500]} !important; }
.theme-custom .border-primary-600 { border-color: ${shades[600]} !important; }
.theme-custom .border-primary-700 { border-color: ${shades[700]} !important; }
.theme-custom .border-primary-800 { border-color: ${shades[800]} !important; }
.theme-custom .border-primary-900 { border-color: ${shades[900]} !important; }
body.dark[data-theme="${hex}"],
html.dark body[data-theme="${hex}"] {
--primary: ${shades[500]};
--primary-foreground: ${shades[50]};
--ring: ${shades[900]};
--sidebar-primary: ${shades[500]};
--sidebar-primary-foreground: ${shades[50]};
--sidebar-accent: oklch(0.268 0.007 34.298);
--sidebar-accent-foreground: ${shades[500]};
--sidebar-ring: ${shades[900]};
}
`;
if (styleElement) {
styleElement.innerHTML = styleContent;
} else {
styleElement = document.createElement('style');
styleElement.id = styleId;
styleElement.innerHTML = styleContent;
document.head.appendChild(styleElement);
}
const styleElement = document.createElement('style');
styleElement.innerHTML = styleContent;
document.head.appendChild(styleElement);
}
@@ -4,7 +4,7 @@ export function tc<T>(tryFunc: () => T, catchFunc: T | ((e?: Error) => T)) {
val = tryFunc();
} catch (e: unknown) {
if (typeof catchFunc === 'function') {
// @ts-ignore
// @ts-expect-error - catchFunc is a function
val = catchFunc(e);
} else {
val = catchFunc;