Improve Canon docs to include new themes
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
+10
-3
@@ -3,10 +3,13 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "npm run build:css && next build",
|
||||
"build:css": "node scripts/build-css.js",
|
||||
"prebuild": "yarn sync:css",
|
||||
"build": "next build",
|
||||
"lint": "next lint",
|
||||
"start": "npm run build:css && next dev"
|
||||
"prestart": "yarn sync:css",
|
||||
"start": "concurrently \"yarn sync:css:watch\" \"next dev\"",
|
||||
"sync:css": "node scripts/sync-css.js",
|
||||
"sync:css:watch": "node scripts/sync-css.js --watch"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "19.1.8",
|
||||
@@ -14,6 +17,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/lang-sass": "^6.0.2",
|
||||
"@codemirror/view": "^6.34.4",
|
||||
"@lezer/highlight": "^1.2.1",
|
||||
"@mdx-js/loader": "^3.1.0",
|
||||
"@mdx-js/react": "^3.1.0",
|
||||
@@ -25,6 +29,7 @@
|
||||
"motion": "^12.4.1",
|
||||
"next": "15.3.4",
|
||||
"next-mdx-remote-client": "^2.1.2",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"react-frame-component": "^5.2.7",
|
||||
@@ -36,6 +41,8 @@
|
||||
"@types/node": "^20",
|
||||
"@types/react": "19.1.8",
|
||||
"@types/react-dom": "19.1.6",
|
||||
"chokidar": "^3.6.0",
|
||||
"concurrently": "^8.2.2",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "15.3.4",
|
||||
"lightningcss": "^1.28.2",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
@font-face{font-family:CircularSp;font-weight:700;font-display:swap;unicode-range:U+0,U+D,U+20-7E,U+A0-17E,U+18F,U+192,U+1A0-1A1,U+1AF-1B0,U+1B5-1B6,U+1C4-1C6,U+1F1-1F3,U+1FA-1FF,U+218-21B,U+237,U+259,U+2BB-2BC,U+2C6-2C7,U+2C9,U+2D8-2DD,U+300-301,U+303,U+309,U+323,U+394,U+3A9,U+3BC,U+3C0,U+1E80-1E85,U+1E8A-1E8B,U+1EA0-1EF9,U+1FD6,U+2007-2008,U+200B,U+2010-2011,U+2013-2014,U+2018-201A,U+201C-201E,U+2020-2022,U+2026,U+2030,U+2032-2033,U+2039-203A,U+2042,U+2044,U+2051,U+2070,U+2074-2079,U+2080-2089,U+20AB-20AC,U+2113,U+2117,U+2122,U+2126,U+2160-2169,U+216C-216F,U+2190-2193,U+2196-2199,U+21A9,U+21B0-21B5,U+21C6,U+2202,U+2206,U+220F,U+2211-2212,U+2215,U+2219-221A,U+221E,U+222B,U+2248,U+2260,U+2264-2265,U+22C5,U+24C5,U+25A0-25A1,U+25AF,U+25B2-25B3,U+25CA-25CB,U+25CF,U+262E,U+2713,U+2715,U+2780-2788,U+E000,U+E002,U+F6C3,U+FB00-FB04,U+FEFF,U+FF0C,U+FF0E,U+FF1A-FF1B,U+FFFF;src:url(https://encore.scdn.co/fonts/CircularSp-Bold-602e7aefc706aa36c6ec1324b9bbc461.woff2)format("woff2"),url(https://encore.scdn.co/fonts/CircularSp-Bold-856afe2da4ba4e61239b129e2c16d633.woff)format("woff")}[data-theme=dark][data-theme-name=spotify]{--canon-font-text:CircularSp,CircularSp-Arab,CircularSp-Hebr,CircularSp-Cyrl,CircularSp-Grek,CircularSp-Deva;--canon-font-title:CircularSpTitle,CircularSp-Arab,CircularSp-Hebr,CircularSp-Cyrl,CircularSp-Grek,CircularSp-Deva;--canon-font-regular:CircularSp,CircularSp-Arab,CircularSp-Hebr,CircularSp-Cyrl,CircularSp-Grek,CircularSp-Deva;--canon-gray-1:#191919;--canon-gray-2:#242424;--canon-gray-3:#373737;--canon-gray-4:#464646;--canon-gray-5:#575757;--canon-gray-6:#7b7b7b;--canon-gray-7:#9e9e9e;--canon-gray-8:#b4b4b4;--canon-bg:#000;--canon-bg-surface-1:#191919;--canon-bg-surface-2:#242424;--canon-bg-solid:#1ed760;--canon-bg-solid-hover:#3be477;--canon-bg-solid-pressed:#1abc54;--canon-bg-solid-disabled:#0f6c30;--canon-bg-tint:#242424;--canon-bg-tint-hover:#202020;--canon-bg-tint-pressed:#292929;--canon-bg-tint-disabled:#fffc;--canon-bg-danger:#3b1219;--canon-bg-warning:#302008;--canon-bg-success:#132d21;--canon-bg-underline:#d16ecb;--canon-fg-primary:#fff;--canon-fg-secondary:#9e9e9e;--canon-fg-link:#fff;--canon-fg-link-hover:#fff;--canon-fg-disabled:#575757;--canon-fg-solid:#000;--canon-fg-solid-disabled:#083618;--canon-fg-tint:#fff;--canon-fg-tint-disabled:#575757;--canon-fg-danger:#e22b2b;--canon-fg-warning:#e36d05;--canon-fg-success:#1db954;--canon-border:var(--canon-gray-3);--canon-border-hover:#fff6;--canon-border-pressed:#ffffff80;--canon-border-disabled:#fff3;--canon-border-danger:#f87a7a;--canon-border-warning:#e36d05;--canon-border-success:#53db83;--canon-ring:#fff3}#root{padding-top:var(--header-height)}.canon-Button,.canon-IconButton{border-radius:var(--canon-radius-3);transition:background-color .2s ease-in-out,color .2s ease-in-out,box-shadow .2s ease-in-out}.canon-Button--variant-primary,.canon-IconButton--variant-primary{&:hover{box-shadow:inset 0 0 0 1px var(--canon-bg-solid);color:var(--canon-fg-primary);background-color:#0000}&:active{background-color:#1ed7601a}&:disabled{background-color:var(--canon-bg-solid-disabled);color:var(--canon-fg-solid-disabled);box-shadow:none}}.canon-Button[data-size=medium],.canon-Button[data-size=small]{padding-inline:var(--canon-space-3)}.canon-MenuTrigger{all:unset;display:inline-flex}.canon-MenuPopup{box-sizing:border-box;max-width:21.25rem}.canon-MenuSubmenuTrigger,.canon-MenuItem{height:auto;min-height:2rem}.canon-Text{font-family:var(--canon-font-text)}.canon-Heading{font-family:var(--canon-font-title)}.canon-TableRow{border-radius:var(--canon-radius-4);border:none}.canon-TableRow:hover td:first-child{border-top-left-radius:var(--canon-radius-2);border-bottom-left-radius:var(--canon-radius-2)}.canon-TableRow:hover td:last-child{border-top-right-radius:var(--canon-radius-2);border-bottom-right-radius:var(--canon-radius-2)}.canon-TableBody:before,.canon-TableBody:after{line-height:var(--canon-space-1);content:"";display:block}.canon-TableHeader .canon-TableRow{border-bottom:1px solid var(--canon-border)}.canon-TableHead{font-size:var(--canon-font-size-2);color:var(--canon-fg-secondary);font-weight:var(--canon-font-weight-regular)}.canon-ScrollAreaRoot{width:100%;height:unset}.canon-TabsIndicator{background-color:var(--canon-bg-underline)}.canon-TabsTab[data-selected]{background:radial-gradient(at bottom,#d16ecb40 0%,#0000 95%)}
|
||||
@@ -1,34 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { bundle } = require('lightningcss');
|
||||
|
||||
const source = '../../packages/canon/src/css';
|
||||
const destination = '../public';
|
||||
|
||||
const source1 = path.join(__dirname, `${source}/styles.css`);
|
||||
const destination1 = path.join(__dirname, `${destination}/styles.css`);
|
||||
|
||||
// Function to bundle and copy the CSS file
|
||||
const bundleAndCopyFile = async (source, destination) => {
|
||||
try {
|
||||
const result = await bundle({
|
||||
filename: source,
|
||||
minify: true,
|
||||
});
|
||||
|
||||
fs.writeFileSync(destination, result.code);
|
||||
console.log('File bundled and copied successfully!');
|
||||
} catch (err) {
|
||||
console.error('Error bundling file:', err);
|
||||
}
|
||||
};
|
||||
|
||||
// Initial bundle and copy
|
||||
Promise.all([bundleAndCopyFile(source1, destination1)])
|
||||
.then(() => {
|
||||
// Add an empty line after all operations are complete - It looks better in the terminal :)
|
||||
console.log('');
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Error in processing files:', err);
|
||||
});
|
||||
@@ -0,0 +1,149 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { bundle } = require('lightningcss');
|
||||
const chokidar = require('chokidar');
|
||||
|
||||
// Configuration
|
||||
const config = {
|
||||
canonPath: '../../packages/canon',
|
||||
publicPath: '../public',
|
||||
files: [
|
||||
{
|
||||
source: 'css/styles.css',
|
||||
destination: 'theme-backstage.css',
|
||||
name: 'Main Styles',
|
||||
},
|
||||
{
|
||||
source: '.storybook/themes/spotify.css',
|
||||
destination: 'theme-spotify.css',
|
||||
name: 'Spotify Theme',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
class CSSSync {
|
||||
constructor() {
|
||||
this.canonPath = path.resolve(__dirname, config.canonPath);
|
||||
this.publicPath = path.resolve(__dirname, config.publicPath);
|
||||
this.isWatching = process.argv.includes('--watch');
|
||||
}
|
||||
|
||||
async syncFile(fileConfig) {
|
||||
const sourcePath = path.join(this.canonPath, fileConfig.source);
|
||||
const destPath = path.join(this.publicPath, fileConfig.destination);
|
||||
|
||||
try {
|
||||
// Check if source file exists
|
||||
if (!fs.existsSync(sourcePath)) {
|
||||
console.warn(`⚠️ Source file not found: ${sourcePath}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure destination directory exists
|
||||
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
||||
|
||||
// Bundle and optimize CSS
|
||||
const result = await bundle({
|
||||
filename: sourcePath,
|
||||
minify: true,
|
||||
});
|
||||
|
||||
// Write to destination
|
||||
fs.writeFileSync(destPath, result.code);
|
||||
|
||||
console.log(
|
||||
`✅ ${fileConfig.name}: ${fileConfig.source} → ${fileConfig.destination}`,
|
||||
);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(`❌ Error syncing ${fileConfig.name}:`, error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async syncAll() {
|
||||
console.log('🔄 Syncing CSS files...\n');
|
||||
|
||||
let successCount = 0;
|
||||
for (const fileConfig of config.files) {
|
||||
if (await this.syncFile(fileConfig)) {
|
||||
successCount++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
`\n✨ Synced ${successCount}/${config.files.length} CSS files successfully!`,
|
||||
);
|
||||
|
||||
if (successCount > 0) {
|
||||
console.log('\n📁 Available CSS files in public/:');
|
||||
config.files.forEach(file => {
|
||||
const destPath = path.join(this.publicPath, file.destination);
|
||||
if (fs.existsSync(destPath)) {
|
||||
const stats = fs.statSync(destPath);
|
||||
const size = (stats.size / 1024).toFixed(2);
|
||||
console.log(` • ${file.destination} (${size} KB)`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
startWatching() {
|
||||
console.log('👀 Watching for CSS changes...\n');
|
||||
|
||||
// Watch all source files
|
||||
const watchPaths = config.files.map(file =>
|
||||
path.join(this.canonPath, file.source),
|
||||
);
|
||||
|
||||
const watcher = chokidar.watch(watchPaths, {
|
||||
ignored: /node_modules/,
|
||||
persistent: true,
|
||||
});
|
||||
|
||||
watcher.on('change', async filePath => {
|
||||
console.log(
|
||||
`\n🔄 Change detected: ${path.relative(this.canonPath, filePath)}`,
|
||||
);
|
||||
|
||||
// Find which file changed and sync it
|
||||
const fileConfig = config.files.find(file =>
|
||||
filePath.endsWith(file.source.replace(/\//g, path.sep)),
|
||||
);
|
||||
|
||||
if (fileConfig) {
|
||||
await this.syncFile(fileConfig);
|
||||
}
|
||||
});
|
||||
|
||||
watcher.on('error', error => console.error('❌ Watch error:', error));
|
||||
|
||||
// Handle process termination
|
||||
process.on('SIGINT', () => {
|
||||
console.log('\n👋 Stopping CSS sync...');
|
||||
watcher.close();
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
async run() {
|
||||
console.log('🎨 Canon CSS Sync Tool\n');
|
||||
console.log(`📂 Canon path: ${this.canonPath}`);
|
||||
console.log(`📂 Public path: ${this.publicPath}\n`);
|
||||
|
||||
// Initial sync
|
||||
await this.syncAll();
|
||||
|
||||
// Watch for changes if requested
|
||||
if (this.isWatching) {
|
||||
this.startWatching();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run the sync tool
|
||||
const cssSync = new CSSSync();
|
||||
cssSync.run().catch(error => {
|
||||
console.error('❌ CSS Sync failed:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -6,7 +6,8 @@ import { CustomTheme } from '@/components/CustomTheme';
|
||||
import styles from '../css/page.module.css';
|
||||
|
||||
import '../css/globals.css';
|
||||
import '/public/styles.css';
|
||||
import '/public/theme-backstage.css';
|
||||
import '/public/theme-spotify.css';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Canon',
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Auto-generated theme switcher utility
|
||||
|
||||
export const availableThemes = {
|
||||
default: '/styles.css',
|
||||
spotify: '/spotify-theme.css',
|
||||
} as const;
|
||||
|
||||
export type ThemeName = keyof typeof availableThemes;
|
||||
|
||||
export function switchTheme(themeName: ThemeName) {
|
||||
// Remove existing theme links
|
||||
const existingLinks = document.querySelectorAll('link[data-theme]');
|
||||
existingLinks.forEach(link => link.remove());
|
||||
|
||||
// Add new theme link
|
||||
const link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.href = availableThemes[themeName];
|
||||
link.setAttribute('data-theme', themeName);
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
|
||||
export function getCurrentTheme(): ThemeName {
|
||||
const existingLink = document.querySelector('link[data-theme]');
|
||||
if (existingLink) {
|
||||
const href = existingLink.getAttribute('href');
|
||||
for (const [name, path] of Object.entries(availableThemes)) {
|
||||
if (path === href) return name as ThemeName;
|
||||
}
|
||||
}
|
||||
return 'default';
|
||||
}
|
||||
+882
-22
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user