Skip to content

Commit

Permalink
Merge branch 'next' of github.com:teamshares/shoelace into next
Browse files Browse the repository at this point in the history
  • Loading branch information
CrookedGrin committed Jul 31, 2023
2 parents 88d6787 + 3842403 commit 7184b41
Show file tree
Hide file tree
Showing 15 changed files with 833 additions and 454 deletions.
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ src/react/index.ts
node_modules
package-lock.json
tsconfig.json
src/styles/exports/generated.css

30 changes: 17 additions & 13 deletions docs/assets/plugins/code-block/code-block.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
const version = sessionStorage.getItem('sl-version');

html = html
.replace(/@teamshares\/shoelace/g, `https://cdn.skypack.dev/@teamshares/shoelace@${version}`)
.replace(/@teamshares\/shoelace/g, `https://cdn.jsdelivr.net/npm/@teamshares/shoelace@${version}`)
.replace(/from 'react'/g, `from 'https://cdn.skypack.dev/react@${reactVersion}'`)
.replace(/from "react"/g, `from "https://cdn.skypack.dev/react@${reactVersion}"`);

Expand Down Expand Up @@ -326,7 +326,6 @@

if (button?.classList.contains('code-block__button--codepen')) {
const codeBlock = button.closest('.code-block');
// const htmlExample = codeBlock.querySelector('.code-block__source--html > pre > code')?.textContent;
const reactExample = codeBlock.querySelector('.code-block__source--react > pre > code')?.textContent;
const slimExample = codeBlock.querySelector('.code-block__source--slim > pre > code')?.textContent;
const isReact = flavor === 'react' && typeof reactExample === 'string';
Expand All @@ -345,10 +344,10 @@

// HTML templates
if (!isReact) {
htmlTemplate =
`<script type="module" src="https://cdn.jsdelivr.net/npm/@teamshares/shoelace@${version}/dist/shoelace.js"></script>\n` +
`\n${slimExample}`;
jsTemplate = '';
htmlTemplate = `${slimExample}`;
jsTemplate =
`import { registerExternalLibraries } from 'https://cdn.jsdelivr.net/npm/@teamshares/shoelace@${version}/dist/utilities/icon-library.js';\n` +
`registerExternalLibraries();`;
}

// React templates
Expand All @@ -357,41 +356,46 @@
jsTemplate =
`import React from 'https://cdn.skypack.dev/react@${reactVersion}';\n` +
`import ReactDOM from 'https://cdn.skypack.dev/react-dom@${reactVersion}';\n` +
`import { setBasePath } from 'https://cdn.skypack.dev/@teamshares/shoelace@${version}/dist/utilities/base-path';\n` +
`import { setBasePath } from 'https://cdn.jsdelivr.net/npm/@teamshares/shoelace@${version}/dist/utilities/base-path';\n` +
`\n` +
`// Set the base path for Shoelace assets\n` +
`setBasePath('https://cdn.skypack.dev/@teamshares/shoelace@${version}/dist/')\n` +
`setBasePath('https://cdn.jsdelivr.net/npm/@teamshares/shoelace@${version}/dist/')\n` +
`\n${convertModuleLinks(reactExample)}\n` +
`\n` +
`ReactDOM.render(<App />, document.getElementById('root'));`;
}

// CSS templates
// TODO: Once we have a our Tailwind classes loaded in the docs site, we should also load them here
cssTemplate =
`@import 'https://cdn.jsdelivr.net/npm/@teamshares/shoelace@${version}/dist/themes/${
isDark ? 'dark' : 'light'
}.css';\n` +
`@import 'https://cdn.jsdelivr.net/npm/@teamshares/shoelace@${version}/dist/styles/index.css';\n` +
'\n' +
'body {\n' +
' font: 16px sans-serif;\n' +
' background-color: var(--sl-color-neutral-0);\n' +
' color: var(--sl-color-neutral-900);\n' +
' padding: 1rem;\n' +
'}';

const headTemplate =
`<meta name='viewport' content='width=device-width'>\n` +
`<script type='module' src='https://cdn.jsdelivr.net/npm/@teamshares/shoelace@${version}/dist/shoelace.js'></script>`;

// Docs: https://blog.codepen.io/documentation/prefill/
const data = {
title: '',
description: '',
tags: ['shoelace', 'web components'],
tags: ['shoelace', 'web components', 'teamshares'],
editors,
head: `<meta name="viewport" content="width=device-width">`,
head: headTemplate,
html_classes: `sl-theme-${isDark ? 'dark' : 'light'}`,
html_pre_processor: isReact ? 'none' : 'slim',
css_external: `https://os.teamshares.com/assets/application-cd5dbca3027c43e480efd5a0efc734bb30fd761b.css`,
css_external: '', // Note that we are importing CSS via the template above
css_pre_processor: 'scss',
js_module: true,
js_external: `https://cdn.jsdelivr.net/npm/@teamshares/shoelace@${version}/dist/shoelace.js`, // This doesn't appear to work, perhaps because it lacks type=module (even though module is true below)
js_external: '', // Note that the shoelace module include needs to be in the <head> block rather than here
js_pre_processor: isReact ? 'babel' : 'none',
html: htmlTemplate,
css: cssTemplate,
Expand Down
34 changes: 2 additions & 32 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
<link rel="icon" href="assets/images/ts-alee.svg" type="image/x-icon" />
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/ts-touch-icon.png" />

<!-- Import Shoelace -->
<link rel="stylesheet" href="dist/themes/light.css" />
<link rel="stylesheet" href="dist/themes/dark.css" />
<link rel="stylesheet" href="dist/styles/index.css" />
Expand All @@ -50,37 +49,8 @@

<script type="module" src="/dist/shoelace-autoloader.js"></script>
<script type="module">
import { registerIconLibrary } from '/dist/utilities/icon-library.js';

registerIconLibrary('fa-free', {
resolver: name => {
const filename = name.replace(/^fa[rbs]-/, '');
let folder = 'regular';
if (name.substring(0, 4) === 'fas-') folder = 'solid';
if (name.substring(0, 4) === 'fab-') folder = 'brands';
return `https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.3.0/svgs/${folder}/${filename}.svg`;
},
mutator: svg => svg.setAttribute('fill', 'currentColor')
});

registerIconLibrary('fa', {
resolver: name => {
const filename = name.replace(/^fa([rsltdb]|(ss))-/, '');
const sub = name.substring(0, 4);
const folderHash = {
'fas-': 'solid',
'fal-': 'light',
'fat-': 'thin',
'fad-': 'duotone',
'fab-': 'brands'
};
const folder = folderHash[sub] || 'regular';
/* Note: The token refers to the Teamshares Font Awesome Kit */
/* See https://fontawesome.com/kits/44da2a9d09/setup */
return `https://ka-p.fontawesome.com/releases/v6.4.0/svgs/${folder}/${filename}.svg?token=44da2a9d09`;
},
mutator: svg => svg.setAttribute('fill', 'currentColor')
});
import { registerExternalLibraries } from '/dist/utilities/icon-library.js';
registerExternalLibraries();
</script>
</head>
<body data-shoelace="/dist/">
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@teamshares/shoelace",
"description": "The Teamshares flavor of a forward-thinking library of web components.",
"version": "1.2.1",
"version": "1.2.2",
"upstreamVersion": "2.4.0",
"homepage": "https://github.com/teamshares/shoelace",
"author": "Cory LaViska",
Expand All @@ -23,7 +23,8 @@
"./dist/react/*": "./dist/react/*",
"./dist/translations/*": "./dist/translations/*",
"./dist/styles": "./dist/styles/index.css",
"./dist/styles/*": "./dist/styles/*"
"./dist/styles/*": "./dist/styles/*",
"./dist/tokens": "./dist/styles/tokens.json"
},
"files": [
"dist"
Expand Down
1 change: 1 addition & 0 deletions scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ fs.mkdirSync(outdir, { recursive: true });
execSync(`node scripts/make-search.js --outdir "${outdir}"`, { stdio: 'inherit' });
execSync(`node scripts/make-react.js --outdir "${outdir}"`, { stdio: 'inherit' });
execSync(`node scripts/make-web-types.js --outdir "${outdir}"`, { stdio: 'inherit' });
execSync(`node scripts/make-tokens.js --outdir "${outdir}"`, { stdio: 'inherit' });
execSync(`node scripts/make-themes.js --outdir "${outdir}"`, { stdio: 'inherit' });
execSync(`node scripts/make-styles.js --outdir "${outdir}"`, { stdio: 'inherit' });
execSync(`node scripts/make-icons.js --outdir "${outdir}"`, { stdio: 'inherit' });
Expand Down
11 changes: 9 additions & 2 deletions scripts/make-styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { mkdirSync } from 'fs';
import { globbySync } from 'globby';
import path from 'path';
import prettier from 'prettier';
import stripComments from 'strip-css-comments';

const { outdir } = commandLineArgs({ name: 'outdir', type: String });
const files = globbySync('./src/styles/exports/**/*.css');
Expand All @@ -23,7 +22,7 @@ try {
files.forEach(file => {
let source = fs.readFileSync(file, 'utf8');

const css = prettier.format(stripComments(source), {
const css = prettier.format(source, {
parser: 'css'
});

Expand All @@ -35,3 +34,11 @@ try {
console.error(chalk.red('Error generating export stylesheets!'));
console.error(err);
}

// Copy the tokens.json over
try {
const tokenDistPath = path.join(outdir, 'styles', 'tokens.json');
fs.copyFileSync('./src/styles/tokens.json', tokenDistPath);
} catch (err) {
console.error(chalk.red('Error writing tokens JSON file:'), err);
}
111 changes: 111 additions & 0 deletions scripts/make-tokens.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/* Read from the JSON source of truth and write a css file using the template */

import chalk from 'chalk';
import fs from 'fs';
import path from 'path';
import prettier from 'prettier';
import tokens from './../src/styles/tokens.json' assert { type: 'json' };

const colorFamilies = ['blue', 'gray', 'red', 'green', 'yellow', 'teal', 'purple', 'fuchsia'];
const colors = tokens.colors;
const variablePrefix = '--ts-color-';

function hexToRgb(hex) {
const hexValue = hex.replace('#', '');
const r = parseInt(hexValue.substring(0, 2), 16);
const g = parseInt(hexValue.substring(2, 4), 16);
const b = parseInt(hexValue.substring(4, 6), 16);
return { r, g, b };
}

function generateColorVariables(colorFamily) {
let css = ` /** ${colorFamily} */\n`;
let hexCss = ``;
let rgbCss = ``;
for (const weight in colors[colorFamily]) {
const colorValue = colors[colorFamily][weight];
hexCss += ` ${variablePrefix}${colorFamily}-${weight}: ${colorValue};\n`;
const rgbValue = hexToRgb(colorValue);
rgbCss += ` ${variablePrefix}${colorFamily}-${weight}-rgb: ${rgbValue.r}, ${rgbValue.g}, ${rgbValue.b};\n`;
}
css += hexCss + rgbCss;
return css;
}

function generateSemanticVariants(semanticFamily, colorFamily) {
let css = ` /** ${semanticFamily} => ${colorFamily} */\n`;
for (const weight in colors[colorFamily]) {
css += ` ${variablePrefix}${semanticFamily}-${weight}: var(${variablePrefix}${colorFamily}-${weight});\n`;
}
return css;
}

function generateShoelaceColorOverride(colorFamily) {
let css = ` /** ${colorFamily} override */\n`;
// Use the weights from blue for all of these
for (const weight in colors['blue']) {
css += ` --sl-color-${colorFamily}-${weight}: var(${variablePrefix}${colorFamily}-${weight});\n`;
}
return css;
}

console.log('Generating tokens CSS');

let cssContent =
`/** *********************************************************************\n` +
`/** Tokens generated from /src/styles/tokens.json\n` +
`/** Do not edit this file directly. Make changes in the json\n` +
`/** and then run 'npm run build'\n` +
`/** ********************************************************************* **/\n` +
`\n` +
`:host,\n:root,\n.sl-theme-light {\n` +
`\n\n /***** Generated colors **/\n\n`;

for (const colorFamily of colorFamilies) {
if (colors[colorFamily]) {
cssContent += generateColorVariables(colorFamily);
}
}

cssContent += `\n /***** Semantic color variants **/\n\n`;

const semanticHash = {
primary: 'blue',
success: 'green',
warning: 'yellow',
danger: 'red',
neutral: 'gray'
};
for (const semanticFamily in semanticHash) {
cssContent += generateSemanticVariants(semanticFamily, semanticHash[semanticFamily]);
}

cssContent += `\n /***** Shoelace color overrides **/\n\n`;

const shoelaceColors = colorFamilies.concat(Object.keys(semanticHash));
for (const shoelaceColor of shoelaceColors) {
cssContent += generateShoelaceColorOverride(shoelaceColor);
}

cssContent += `\n /***** Other generated tokens **/\n\n`;

const font = tokens.fontFamily;
cssContent +=
` /**** Generated fonts **/\n` +
` --ts-font-sans: ${font.sans};\n` +
` --ts-font-serif: ${font.serif};\n` +
` --ts-font-mono: ${font.mono};\n` +
` --ts-font-body: var(--ts-font-sans);\n` +
` --ts-font-display: var(--ts-font-serif);\n`;

cssContent += `}\n`;

cssContent = prettier.format(cssContent, { parser: 'css' });

// Write the CSS file
try {
const fileName = path.join('./src/styles/exports', 'generated.css');
fs.writeFileSync(fileName, cssContent, 'utf8');
} catch (err) {
console.error(chalk.red('Error writing CSS file:'), err);
}
35 changes: 35 additions & 0 deletions src/components/icon/external.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { registerIconLibrary } from './library';

/* Teamshares-specific icon libraries */
export function registerExternalLibraries() {
registerIconLibrary('fa-free', {
resolver: name => {
const filename = name.replace(/^fa[rbs]-/, '');
let folder = 'regular';
if (name.startsWith('fas-')) folder = 'solid';
if (name.startsWith('fab-')) folder = 'brands';
return `https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.3.0/svgs/${folder}/${filename}.svg`;
},
mutator: svg => svg.setAttribute('fill', 'currentColor')
});

registerIconLibrary('fa', {
resolver: name => {
const filename = name.replace(/^fa([rsltdb]|(ss))-/, '');
const sub = name.substring(0, 4);
const folderHash = {
'fas-': 'solid',
'fal-': 'light',
'fat-': 'thin',
'fad-': 'duotone',
'fab-': 'brands'
};
const folder: unknown = folderHash[sub as keyof typeof folderHash] || 'regular';
/* Note: The token refers to the Teamshares Font Awesome Kit */
/* See https://fontawesome.com/kits/44da2a9d09/setup */
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
return `https://ka-p.fontawesome.com/releases/v6.4.0/svgs/${folder}/${filename}.svg?token=44da2a9d09`;
},
mutator: svg => svg.setAttribute('fill', 'currentColor')
});
}
2 changes: 2 additions & 0 deletions src/components/icon/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,5 @@ export function registerIconLibrary(
export function unregisterIconLibrary(name: string) {
registry = registry.filter(lib => lib.name !== name);
}

export { registerExternalLibraries } from './external';
Loading

1 comment on commit 7184b41

@vercel
Copy link

@vercel vercel bot commented on 7184b41 Jul 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.