new yaks
This commit is contained in:
parent
203b102b55
commit
17f705d167
65 changed files with 7207 additions and 18129 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "Node.js",
|
"name": "Node.js",
|
||||||
"image": "mcr.microsoft.com/devcontainers/javascript-node:0-16",
|
"image": "mcr.microsoft.com/devcontainers/javascript-node:0-20",
|
||||||
"postCreateCommand": "yarn install"
|
"postCreateCommand": "npm install"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
root: true,
|
|
||||||
parser: '@typescript-eslint/parser',
|
|
||||||
ignorePatterns: ['node_modules', 'docs/**', '.eslintrc.cjs'],
|
|
||||||
extends: ['standard', 'plugin:svelte/recommended'],
|
|
||||||
plugins: ['@typescript-eslint'],
|
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: 2020,
|
|
||||||
sourceType: 'module',
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: ['./tsconfig.json'],
|
|
||||||
extraFileExtensions: ['.svelte'],
|
|
||||||
},
|
|
||||||
env: {
|
|
||||||
browser: true,
|
|
||||||
es2022: true,
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
indent: ['error', 2, { SwitchCase: 1 }],
|
|
||||||
semi: ['error', 'always'],
|
|
||||||
'comma-dangle': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
arrays: 'always-multiline',
|
|
||||||
objects: 'always-multiline',
|
|
||||||
imports: 'always-multiline',
|
|
||||||
exports: 'never',
|
|
||||||
functions: 'never',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'operator-linebreak': ['error', 'after'],
|
|
||||||
'space-before-function-paren': ['error', 'never'],
|
|
||||||
},
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: ['*.svelte'],
|
|
||||||
parser: 'svelte-eslint-parser',
|
|
||||||
parserOptions: {
|
|
||||||
parser: '@typescript-eslint/parser',
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
'no-multiple-empty-lines': ['error', { max: 2, maxBOF: 2 }],
|
|
||||||
'import/first': 'off',
|
|
||||||
'import/no-duplicates': 'off',
|
|
||||||
'import/no-mutable-exports': 'off',
|
|
||||||
'import/no-unresolved': 'off',
|
|
||||||
'svelte/no-at-html-tags': 'off',
|
|
||||||
indent: ['error', 2],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
1
.prettierignore
Normal file
1
.prettierignore
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
docs/
|
||||||
15
.prettierrc
15
.prettierrc
|
|
@ -1,15 +0,0 @@
|
||||||
{
|
|
||||||
"svelteStrictMode": true,
|
|
||||||
"arrowParens": "always",
|
|
||||||
"bracketSpacing": true,
|
|
||||||
"embeddedLanguageFormatting": "auto",
|
|
||||||
"endOfLine": "lf",
|
|
||||||
"htmlWhitespaceSensitivity": "css",
|
|
||||||
"printWidth": 80,
|
|
||||||
"proseWrap": "preserve",
|
|
||||||
"semi": true,
|
|
||||||
"singleQuote": true,
|
|
||||||
"tabWidth": 2,
|
|
||||||
"trailingComma": "es5",
|
|
||||||
"useTabs": false
|
|
||||||
}
|
|
||||||
10
.prettierrc.js
Normal file
10
.prettierrc.js
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { svelte as svelteConfig } from '@reuters-graphics/yaks-prettier';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {import("prettier").Config}
|
||||||
|
*/
|
||||||
|
const config = {
|
||||||
|
...svelteConfig,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
|
|
@ -4,6 +4,7 @@ export default create({
|
||||||
base: 'light',
|
base: 'light',
|
||||||
brandTitle: 'Reuters Graphics components',
|
brandTitle: 'Reuters Graphics components',
|
||||||
brandUrl: 'https://reuters-graphics.github.io/graphics-components/',
|
brandUrl: 'https://reuters-graphics.github.io/graphics-components/',
|
||||||
brandImage: 'https://graphics.thomsonreuters.com/style-assets/images/logos/reuters-graphics-logo/svg/graphics-logo-color-dark.svg',
|
brandImage:
|
||||||
|
'https://graphics.thomsonreuters.com/style-assets/images/logos/reuters-graphics-logo/svg/graphics-logo-color-dark.svg',
|
||||||
brandTarget: '_self',
|
brandTarget: '_self',
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,4 @@
|
||||||
<Article>
|
<Article>
|
||||||
<slot />
|
<slot />
|
||||||
</Article>
|
</Article>
|
||||||
</Theme>
|
</Theme>
|
||||||
|
|
|
||||||
|
|
@ -22,4 +22,4 @@ addons.setConfig({
|
||||||
fullscreen: { hidden: false },
|
fullscreen: { hidden: false },
|
||||||
},
|
},
|
||||||
theme,
|
theme,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ SyntaxHighlighter.registerLanguage('svelte', svelte);
|
||||||
SyntaxHighlighter.registerLanguage('markdown', markdown);
|
SyntaxHighlighter.registerLanguage('markdown', markdown);
|
||||||
|
|
||||||
export const parameters = {
|
export const parameters = {
|
||||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
actions: { argTypesRegex: '^on[A-Z].*' },
|
||||||
viewMode: 'docs',
|
viewMode: 'docs',
|
||||||
previewTabs: { 'storybook/docs/panel': { index: -1 } },
|
previewTabs: { 'storybook/docs/panel': { index: -1 } },
|
||||||
controls: {
|
controls: {
|
||||||
|
|
@ -53,23 +53,19 @@ export const parameters = {
|
||||||
'Styles',
|
'Styles',
|
||||||
[
|
[
|
||||||
'Intro',
|
'Intro',
|
||||||
'Colours', [
|
'Colours',
|
||||||
'Intro',
|
['Intro', 'Primary', 'Thematic', '*'],
|
||||||
'Primary',
|
'Tokens',
|
||||||
'Thematic',
|
['Intro', 'Typography', '*'],
|
||||||
'*',
|
|
||||||
],
|
|
||||||
'Tokens', [
|
|
||||||
'Intro',
|
|
||||||
'Typography',
|
|
||||||
'*',
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
'Actions',
|
'Actions',
|
||||||
['Intro', '*'],
|
['Intro', '*'],
|
||||||
'Contributing',
|
'Contributing',
|
||||||
[
|
[
|
||||||
'Quickstart', 'Component Basics', '*', 'Writing Stories',
|
'Quickstart',
|
||||||
|
'Component Basics',
|
||||||
|
'*',
|
||||||
|
'Writing Stories',
|
||||||
'Recipes: Basic story',
|
'Recipes: Basic story',
|
||||||
'Recipes: Story with custom docs',
|
'Recipes: Story with custom docs',
|
||||||
'Recipes: Story with custom controls',
|
'Recipes: Story with custom controls',
|
||||||
|
|
@ -79,7 +75,7 @@ export const parameters = {
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const decorators = [() => Wrapper];
|
export const decorators = [() => Wrapper];
|
||||||
|
|
|
||||||
5
.storybook/svelte-highlighting.d.ts
vendored
5
.storybook/svelte-highlighting.d.ts
vendored
|
|
@ -1,6 +1,7 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
declare function svelte(Prism: any): void;
|
declare function svelte(Prism: any): void;
|
||||||
declare namespace svelte {
|
declare namespace svelte {
|
||||||
let displayName: string;
|
let displayName: string;
|
||||||
let aliases: any[];
|
let aliases: any[];
|
||||||
}
|
}
|
||||||
export default svelte;
|
export default svelte;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
svelte.displayName = 'svelte'
|
svelte.displayName = 'svelte';
|
||||||
svelte.aliases = []
|
svelte.aliases = [];
|
||||||
|
|
||||||
export default function svelte(Prism) {
|
export default function svelte(Prism) {
|
||||||
const blocks = '(if|else if|await|then|catch|each|html|debug)';
|
const blocks = '(if|else if|await|then|catch|each|html|debug)';
|
||||||
|
|
@ -48,7 +48,8 @@ export default function svelte(Prism) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
tag: {
|
tag: {
|
||||||
pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?:"[^"]*"|'[^']*'|{[\s\S]+?}(?=[\s/>])))|(?=[\s/>])))+)?\s*\/?>/i,
|
pattern:
|
||||||
|
/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?:"[^"]*"|'[^']*'|{[\s\S]+?}(?=[\s/>])))|(?=[\s/>])))+)?\s*\/?>/i,
|
||||||
greedy: true,
|
greedy: true,
|
||||||
inside: {
|
inside: {
|
||||||
tag: {
|
tag: {
|
||||||
|
|
@ -59,7 +60,8 @@ export default function svelte(Prism) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'language-javascript': {
|
'language-javascript': {
|
||||||
pattern: /\{(?:(?:\{(?:(?:\{(?:[^{}])*\})|(?:[^{}]))*\})|(?:[^{}]))*\}/,
|
pattern:
|
||||||
|
/\{(?:(?:\{(?:(?:\{(?:[^{}])*\})|(?:[^{}]))*\})|(?:[^{}]))*\}/,
|
||||||
inside: Prism.languages['javascript'],
|
inside: Prism.languages['javascript'],
|
||||||
},
|
},
|
||||||
'attr-value': {
|
'attr-value': {
|
||||||
|
|
@ -97,7 +99,7 @@ export default function svelte(Prism) {
|
||||||
Prism.languages.svelte['tag'].inside['attr-value'].inside['entity'] =
|
Prism.languages.svelte['tag'].inside['attr-value'].inside['entity'] =
|
||||||
Prism.languages.svelte['entity'];
|
Prism.languages.svelte['entity'];
|
||||||
|
|
||||||
Prism.hooks.add('wrap', env => {
|
Prism.hooks.add('wrap', (env) => {
|
||||||
if (env.type === 'entity') {
|
if (env.type === 'entity') {
|
||||||
env.attributes['title'] = env.content.replace(/&/, '&');
|
env.attributes['title'] = env.content.replace(/&/, '&');
|
||||||
}
|
}
|
||||||
|
|
@ -144,4 +146,4 @@ export default function svelte(Prism) {
|
||||||
|
|
||||||
Prism.languages.svelte.tag.addInlined('style', 'css');
|
Prism.languages.svelte.tag.addInlined('style', 'css');
|
||||||
Prism.languages.svelte.tag.addInlined('script', 'javascript');
|
Prism.languages.svelte.tag.addInlined('script', 'javascript');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
|
|
@ -1,7 +1,5 @@
|
||||||
{
|
{
|
||||||
"i18n-ally.localesPaths": ["locales"],
|
"eslint.validate": ["javascript", "javascriptreact", "svelte", "jsx"],
|
||||||
"i18n-ally.keystyle": "nested",
|
|
||||||
"eslint.validate": ["javascript", "svelte", "jsx"],
|
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": "explicit"
|
"source.fixAll.eslint": "explicit"
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,14 @@ const excludedTypeDefs = [
|
||||||
'**/*.stories.svelte.d.ts',
|
'**/*.stories.svelte.d.ts',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
const prettifyImport = (filename) => {
|
const prettifyImport = (filename) => {
|
||||||
return filename
|
return (
|
||||||
// strip index.js
|
filename
|
||||||
.replace(/\/index\.js$|(\/[^/]+)\.js$/, '$1')
|
// strip index.js
|
||||||
// normalize SCSS partials
|
.replace(/\/index\.js$|(\/[^/]+)\.js$/, '$1')
|
||||||
.replace(/\/_?([^/]+)\.scss$/, '/$1');
|
// normalize SCSS partials
|
||||||
|
.replace(/\/_?([^/]+)\.scss$/, '/$1')
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -47,28 +48,32 @@ const build = async () => {
|
||||||
|
|
||||||
// Extract types
|
// Extract types
|
||||||
await emitDts({
|
await emitDts({
|
||||||
libRoot: LIB,
|
libRoot: LIB,
|
||||||
svelteShimsPath: require.resolve('svelte2tsx/svelte-shims.d.ts'),
|
svelteShimsPath: require.resolve('svelte2tsx/svelte-shims.d.ts'),
|
||||||
declarationDir: TYPES,
|
declarationDir: TYPES,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cleanup unwanted types
|
// Cleanup unwanted types
|
||||||
fs.rmSync(path.join(TYPES, 'docs'), { recursive: true, force: true });
|
fs.rmSync(path.join(TYPES, 'docs'), { recursive: true, force: true });
|
||||||
const types = await glob('**/*', { cwd: TYPES, filesOnly: true });
|
const types = await glob('**/*', { cwd: TYPES, filesOnly: true });
|
||||||
for (const t of types) {
|
for (const t of types) {
|
||||||
if(picomatch.isMatch(t, excludedTypeDefs)) fs.unlinkSync(path.join(TYPES, t));
|
if (picomatch.isMatch(t, excludedTypeDefs))
|
||||||
|
fs.unlinkSync(path.join(TYPES, t));
|
||||||
}
|
}
|
||||||
|
|
||||||
const pkgExports = {
|
const pkgExports = {
|
||||||
'./package.json': './package.json'
|
'./package.json': './package.json',
|
||||||
};
|
};
|
||||||
|
|
||||||
const files = await glob('**/*.{js,json,ts,svelte,css,scss}', { cwd: LIB, filesOnly: true });
|
const files = await glob('**/*.{js,json,ts,svelte,css,scss}', {
|
||||||
|
cwd: LIB,
|
||||||
|
filesOnly: true,
|
||||||
|
});
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
if(picomatch.isMatch(file, excludePatterns)) continue;
|
if (picomatch.isMatch(file, excludePatterns)) continue;
|
||||||
if (file.endsWith('.svelte')) {
|
if (file.endsWith('.svelte')) {
|
||||||
await processSvelte(file);
|
await processSvelte(file);
|
||||||
} else if(file.endsWith('.ts') && !file.endsWith('.d.ts')) {
|
} else if (file.endsWith('.ts') && !file.endsWith('.d.ts')) {
|
||||||
await processTypescript(file);
|
await processTypescript(file);
|
||||||
} else {
|
} else {
|
||||||
await processOther(file);
|
await processOther(file);
|
||||||
|
|
@ -83,12 +88,12 @@ const build = async () => {
|
||||||
};
|
};
|
||||||
const pkg = fs.readJSONSync(PACKAGE);
|
const pkg = fs.readJSONSync(PACKAGE);
|
||||||
pkg.type = 'module';
|
pkg.type = 'module';
|
||||||
pkg.types = './dist/@types/index.d.ts',
|
pkg.types = './dist/@types/index.d.ts';
|
||||||
pkg.files = ['dist'];
|
pkg.files = ['dist'];
|
||||||
pkg.private = false;
|
pkg.private = false;
|
||||||
pkg.exports = pkgExports;
|
pkg.exports = pkgExports;
|
||||||
pkg.svelte = './dist/index.js';
|
pkg.svelte = './dist/index.js';
|
||||||
fs.writeFileSync(PACKAGE, JSON.stringify(pkg, null, 2));
|
fs.writeFileSync(PACKAGE, JSON.stringify(pkg, null, 2));
|
||||||
}
|
};
|
||||||
|
|
||||||
build();
|
build();
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,4 @@ export default async (file) => {
|
||||||
const writePath = path.join(DIST, file);
|
const writePath = path.join(DIST, file);
|
||||||
fs.ensureDirSync(path.dirname(writePath));
|
fs.ensureDirSync(path.dirname(writePath));
|
||||||
fs.copyFileSync(filename, writePath);
|
fs.copyFileSync(filename, writePath);
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,22 @@ import path from 'path';
|
||||||
import { preprocess as svelte } from 'svelte/compiler';
|
import { preprocess as svelte } from 'svelte/compiler';
|
||||||
import { sveltePreprocess } from '../../preprocess/index.js';
|
import { sveltePreprocess } from '../../preprocess/index.js';
|
||||||
|
|
||||||
const stripLangTags = (source) =>
|
const stripLangTags = (source) =>
|
||||||
source
|
source
|
||||||
.replace(/(<!--[^]*?-->)|(<script[^>]*?)\s(?:type|lang)=(["']).*?\3/g, '$1$2')
|
.replace(
|
||||||
.replace(/(<!--[^]*?-->)|(<style[^>]*?)\s(?:type|lang)=(["']).*?\3/g, '$1$2');
|
/(<!--[^]*?-->)|(<script[^>]*?)\s(?:type|lang)=(["']).*?\3/g,
|
||||||
|
'$1$2'
|
||||||
|
)
|
||||||
|
.replace(
|
||||||
|
/(<!--[^]*?-->)|(<style[^>]*?)\s(?:type|lang)=(["']).*?\3/g,
|
||||||
|
'$1$2'
|
||||||
|
);
|
||||||
|
|
||||||
export default async (file) => {
|
export default async (file) => {
|
||||||
const filename = path.join(LIB, file);
|
const filename = path.join(LIB, file);
|
||||||
let source = fs.readFileSync(filename, 'utf8');
|
let source = fs.readFileSync(filename, 'utf8');
|
||||||
source = (await svelte(source, sveltePreprocess, { filename })).code
|
source = (await svelte(source, sveltePreprocess, { filename })).code;
|
||||||
const writePath = path.join(DIST, file);
|
const writePath = path.join(DIST, file);
|
||||||
fs.ensureDirSync(path.dirname(writePath));
|
fs.ensureDirSync(path.dirname(writePath));
|
||||||
fs.writeFileSync(writePath, stripLangTags(source));
|
fs.writeFileSync(writePath, stripLangTags(source));
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,10 @@ import ts from 'typescript';
|
||||||
|
|
||||||
async function transpileTypeScript(filename, source) {
|
async function transpileTypeScript(filename, source) {
|
||||||
const { compilerOptions } = fs.readJSONSync(path.join(ROOT, 'tsconfig.json'));
|
const { compilerOptions } = fs.readJSONSync(path.join(ROOT, 'tsconfig.json'));
|
||||||
return ts.transpileModule(source, {
|
return ts.transpileModule(source, {
|
||||||
compilerOptions,
|
compilerOptions,
|
||||||
fileName: filename
|
fileName: filename,
|
||||||
}).outputText;
|
}).outputText;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async (file) => {
|
export default async (file) => {
|
||||||
|
|
@ -19,4 +19,4 @@ export default async (file) => {
|
||||||
const writePath = path.join(DIST, file).replace(/\.ts$/, '.js');
|
const writePath = path.join(DIST, file).replace(/\.ts$/, '.js');
|
||||||
fs.ensureDirSync(path.dirname(writePath));
|
fs.ensureDirSync(path.dirname(writePath));
|
||||||
fs.writeFileSync(writePath, source);
|
fs.writeFileSync(writePath, source);
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ function ownKeys(object, enumerableOnly) {
|
||||||
if (Object.getOwnPropertySymbols) {
|
if (Object.getOwnPropertySymbols) {
|
||||||
let symbols = Object.getOwnPropertySymbols(object);
|
let symbols = Object.getOwnPropertySymbols(object);
|
||||||
if (enumerableOnly) {
|
if (enumerableOnly) {
|
||||||
symbols = symbols.filter(function(sym) {
|
symbols = symbols.filter(function (sym) {
|
||||||
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -51,14 +51,18 @@ function _objectSpread2(target) {
|
||||||
var source = arguments[i] != null ? arguments[i] : {};
|
var source = arguments[i] != null ? arguments[i] : {};
|
||||||
|
|
||||||
if (i % 2) {
|
if (i % 2) {
|
||||||
ownKeys(Object(source), true).forEach(function(key) {
|
ownKeys(Object(source), true).forEach(function (key) {
|
||||||
_defineProperty(target, key, source[key]);
|
_defineProperty(target, key, source[key]);
|
||||||
});
|
});
|
||||||
} else if (Object.getOwnPropertyDescriptors) {
|
} else if (Object.getOwnPropertyDescriptors) {
|
||||||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
||||||
} else {
|
} else {
|
||||||
ownKeys(Object(source)).forEach(function(key) {
|
ownKeys(Object(source)).forEach(function (key) {
|
||||||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
Object.defineProperty(
|
||||||
|
target,
|
||||||
|
key,
|
||||||
|
Object.getOwnPropertyDescriptor(source, key)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -67,7 +71,9 @@ function _objectSpread2(target) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function _slicedToArray(arr, i) {
|
function _slicedToArray(arr, i) {
|
||||||
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
|
return (
|
||||||
|
_arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _arrayWithHoles(arr) {
|
function _arrayWithHoles(arr) {
|
||||||
|
|
@ -75,7 +81,12 @@ function _arrayWithHoles(arr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function _iterableToArrayLimit(arr, i) {
|
function _iterableToArrayLimit(arr, i) {
|
||||||
if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === '[object Arguments]')) {
|
if (
|
||||||
|
!(
|
||||||
|
Symbol.iterator in Object(arr) ||
|
||||||
|
Object.prototype.toString.call(arr) === '[object Arguments]'
|
||||||
|
)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,7 +96,11 @@ function _iterableToArrayLimit(arr, i) {
|
||||||
let _e;
|
let _e;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
|
for (
|
||||||
|
var _i = arr[Symbol.iterator](), _s;
|
||||||
|
!(_n = (_s = _i.next()).done);
|
||||||
|
_n = true
|
||||||
|
) {
|
||||||
_arr.push(_s.value);
|
_arr.push(_s.value);
|
||||||
|
|
||||||
if (i && _arr.length === i) break;
|
if (i && _arr.length === i) break;
|
||||||
|
|
@ -121,7 +136,7 @@ const addProperty = function addProperty(obj, key, value) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const camelize = function camelize(str) {
|
const camelize = function camelize(str) {
|
||||||
return str.replace(/-([a-z])/g, function(g) {
|
return str.replace(/-([a-z])/g, function (g) {
|
||||||
return g[1].toUpperCase();
|
return g[1].toUpperCase();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -148,7 +163,7 @@ const fontface = function fontface(rule, result) {
|
||||||
let name = '';
|
let name = '';
|
||||||
let obj = {};
|
let obj = {};
|
||||||
const fontObj = {};
|
const fontObj = {};
|
||||||
rule.declarations.forEach(function(declaration) {
|
rule.declarations.forEach(function (declaration) {
|
||||||
const cssProperty = camelize(declaration.property);
|
const cssProperty = camelize(declaration.property);
|
||||||
fontObj[cssProperty] = declaration.value;
|
fontObj[cssProperty] = declaration.value;
|
||||||
name = capitalize(camelize(fontObj.fontFamily).replace(/"/g, ''));
|
name = capitalize(camelize(fontObj.fontFamily).replace(/"/g, ''));
|
||||||
|
|
@ -157,7 +172,7 @@ const fontface = function fontface(rule, result) {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
let dupeFlag = false;
|
let dupeFlag = false;
|
||||||
Object.keys(result).forEach(function(key) {
|
Object.keys(result).forEach(function (key) {
|
||||||
if (key.split('_')[0] === name) {
|
if (key.split('_')[0] === name) {
|
||||||
if (JSON.stringify(result[key]) === JSON.stringify(obj)) {
|
if (JSON.stringify(result[key]) === JSON.stringify(obj)) {
|
||||||
dupeFlag = true;
|
dupeFlag = true;
|
||||||
|
|
@ -166,7 +181,7 @@ const fontface = function fontface(rule, result) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!dupeFlag) {
|
if (!dupeFlag) {
|
||||||
const numVar = Object.entries(result).filter(function(resObj) {
|
const numVar = Object.entries(result).filter(function (resObj) {
|
||||||
return resObj[0].split('_')[0] === name;
|
return resObj[0].split('_')[0] === name;
|
||||||
}).length;
|
}).length;
|
||||||
|
|
||||||
|
|
@ -183,9 +198,13 @@ const fontface = function fontface(rule, result) {
|
||||||
|
|
||||||
const keyframes = function keyframes(rule) {
|
const keyframes = function keyframes(rule) {
|
||||||
const keyFrameObj = {};
|
const keyFrameObj = {};
|
||||||
rule.keyframes.forEach(function(keyframe) {
|
rule.keyframes.forEach(function (keyframe) {
|
||||||
keyframe.declarations.forEach(function(decl) {
|
keyframe.declarations.forEach(function (decl) {
|
||||||
keyFrameObj[keyframe.values[0]] = _objectSpread2({}, keyFrameObj[keyframe.values[0]], _defineProperty({}, decl.property, decl.value));
|
keyFrameObj[keyframe.values[0]] = _objectSpread2(
|
||||||
|
{},
|
||||||
|
keyFrameObj[keyframe.values[0]],
|
||||||
|
_defineProperty({}, decl.property, decl.value)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
let name = camelize('keyframes-'.concat(rule.name));
|
let name = camelize('keyframes-'.concat(rule.name));
|
||||||
|
|
@ -198,11 +217,11 @@ const keyframes = function keyframes(rule) {
|
||||||
const standard = function standard(rule, result) {
|
const standard = function standard(rule, result) {
|
||||||
const obj = {};
|
const obj = {};
|
||||||
let retObj = {};
|
let retObj = {};
|
||||||
rule.declarations.forEach(function(declaration) {
|
rule.declarations.forEach(function (declaration) {
|
||||||
const cssProperty = camelize(declaration.property);
|
const cssProperty = camelize(declaration.property);
|
||||||
obj[cssProperty] = declaration.value;
|
obj[cssProperty] = declaration.value;
|
||||||
});
|
});
|
||||||
rule.selectors.forEach(function(selector) {
|
rule.selectors.forEach(function (selector) {
|
||||||
let name; // Check if selector contains a pseudo selector
|
let name; // Check if selector contains a pseudo selector
|
||||||
|
|
||||||
const pseudoSelectorIndex = selector.indexOf(':');
|
const pseudoSelectorIndex = selector.indexOf(':');
|
||||||
|
|
@ -210,11 +229,18 @@ const standard = function standard(rule, result) {
|
||||||
if (pseudoSelectorIndex !== -1) {
|
if (pseudoSelectorIndex !== -1) {
|
||||||
// Find end of pseudo selector
|
// Find end of pseudo selector
|
||||||
let endPseudoSelectorIndex = selector.indexOf(' ', pseudoSelectorIndex);
|
let endPseudoSelectorIndex = selector.indexOf(' ', pseudoSelectorIndex);
|
||||||
if (endPseudoSelectorIndex === -1) endPseudoSelectorIndex = selector.length; // Split selector
|
if (endPseudoSelectorIndex === -1)
|
||||||
|
endPseudoSelectorIndex = selector.length; // Split selector
|
||||||
|
|
||||||
const primarySelector = selector.slice(0, pseudoSelectorIndex);
|
const primarySelector = selector.slice(0, pseudoSelectorIndex);
|
||||||
const pseudoSelector = selector.slice(pseudoSelectorIndex, endPseudoSelectorIndex);
|
const pseudoSelector = selector.slice(
|
||||||
const secondarySelector = selector.slice(endPseudoSelectorIndex, selector.length);
|
pseudoSelectorIndex,
|
||||||
|
endPseudoSelectorIndex
|
||||||
|
);
|
||||||
|
const secondarySelector = selector.slice(
|
||||||
|
endPseudoSelectorIndex,
|
||||||
|
selector.length
|
||||||
|
);
|
||||||
const pseudoObj = {};
|
const pseudoObj = {};
|
||||||
pseudoObj['&'.concat(pseudoSelector).concat(secondarySelector)] = obj;
|
pseudoObj['&'.concat(pseudoSelector).concat(secondarySelector)] = obj;
|
||||||
name = sanitize(primarySelector.trim());
|
name = sanitize(primarySelector.trim());
|
||||||
|
|
@ -228,9 +254,10 @@ const standard = function standard(rule, result) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const convertRules = function convertRules(rules) {
|
const convertRules = function convertRules(rules) {
|
||||||
const res = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
const res =
|
||||||
|
arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
||||||
let result = res;
|
let result = res;
|
||||||
rules.forEach(function(rule) {
|
rules.forEach(function (rule) {
|
||||||
if (rule.type === 'media') {
|
if (rule.type === 'media') {
|
||||||
// Convert @media rules
|
// Convert @media rules
|
||||||
const name = '@media '.concat(rule.media);
|
const name = '@media '.concat(rule.media);
|
||||||
|
|
@ -248,7 +275,7 @@ const convertRules = function convertRules(rules) {
|
||||||
} else if (rule.type === 'rule') {
|
} else if (rule.type === 'rule') {
|
||||||
// Convert standard CSS rules
|
// Convert standard CSS rules
|
||||||
const standardProp = standard(rule, result);
|
const standardProp = standard(rule, result);
|
||||||
Object.entries(standardProp).forEach(function(_ref) {
|
Object.entries(standardProp).forEach(function (_ref) {
|
||||||
const _ref2 = _slicedToArray(_ref, 2);
|
const _ref2 = _slicedToArray(_ref, 2);
|
||||||
const key = _ref2[0];
|
const key = _ref2[0];
|
||||||
const value = _ref2[1];
|
const value = _ref2[1];
|
||||||
|
|
@ -275,8 +302,9 @@ const reverseMediaQueries = function reverseMediaQueries(inputData) {
|
||||||
const exportObject = {};
|
const exportObject = {};
|
||||||
|
|
||||||
const moveMediaInsideClass = function moveMediaInsideClass(object) {
|
const moveMediaInsideClass = function moveMediaInsideClass(object) {
|
||||||
const media = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
const media =
|
||||||
Object.entries(object).forEach(function(_ref) {
|
arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
||||||
|
Object.entries(object).forEach(function (_ref) {
|
||||||
const _ref2 = _slicedToArray(_ref, 2);
|
const _ref2 = _slicedToArray(_ref, 2);
|
||||||
const key = _ref2[0];
|
const key = _ref2[0];
|
||||||
const value = _ref2[1];
|
const value = _ref2[1];
|
||||||
|
|
@ -288,7 +316,12 @@ const reverseMediaQueries = function reverseMediaQueries(inputData) {
|
||||||
tempObj[media] = value;
|
tempObj[media] = value;
|
||||||
|
|
||||||
if (exportObject[key]) {
|
if (exportObject[key]) {
|
||||||
exportObject[key] = _objectSpread2({}, exportObject[key], {}, tempObj);
|
exportObject[key] = _objectSpread2(
|
||||||
|
{},
|
||||||
|
exportObject[key],
|
||||||
|
{},
|
||||||
|
tempObj
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
exportObject[key] = tempObj;
|
exportObject[key] = tempObj;
|
||||||
}
|
}
|
||||||
|
|
@ -317,7 +350,8 @@ const convertStringToJson = function convertStringToJson(input, mediaReverse) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const convert = function convert(input) {
|
const convert = function convert(input) {
|
||||||
const config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
const config =
|
||||||
|
arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
||||||
const outputType = config.outputType;
|
const outputType = config.outputType;
|
||||||
const outputPath = config.outputPath;
|
const outputPath = config.outputPath;
|
||||||
let mediaReverse = config.mediaReverse;
|
let mediaReverse = config.mediaReverse;
|
||||||
|
|
@ -331,7 +365,7 @@ const convert = function convert(input) {
|
||||||
|
|
||||||
if (!outputType) {
|
if (!outputType) {
|
||||||
if (Array.isArray(convertedCss)) {
|
if (Array.isArray(convertedCss)) {
|
||||||
return convertedCss.map(function(obj) {
|
return convertedCss.map(function (obj) {
|
||||||
return obj.contents;
|
return obj.contents;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -340,7 +374,7 @@ const convert = function convert(input) {
|
||||||
} else {
|
} else {
|
||||||
const writeRecur = function writeRecur(input) {
|
const writeRecur = function writeRecur(input) {
|
||||||
if (Array.isArray(input)) {
|
if (Array.isArray(input)) {
|
||||||
input.forEach(function(obj) {
|
input.forEach(function (obj) {
|
||||||
writeRecur(obj);
|
writeRecur(obj);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ const ROOT = path.resolve(__dirname, '../../');
|
||||||
const LIB = path.join(ROOT, 'src/components');
|
const LIB = path.join(ROOT, 'src/components');
|
||||||
const TEMPLATE = path.join(__dirname, 'template');
|
const TEMPLATE = path.join(__dirname, 'template');
|
||||||
|
|
||||||
const makeNewComponent = async() => {
|
const makeNewComponent = async () => {
|
||||||
const{ name } = await prompts({
|
const { name } = await prompts({
|
||||||
type: 'text',
|
type: 'text',
|
||||||
name: 'name',
|
name: 'name',
|
||||||
message: 'What should we call your new component, e.g., ImagePack?',
|
message: 'What should we call your new component, e.g., ImagePack?',
|
||||||
|
|
@ -21,24 +21,29 @@ const makeNewComponent = async() => {
|
||||||
const componentName = pascalCase(name);
|
const componentName = pascalCase(name);
|
||||||
const componentDir = path.join(LIB, componentName);
|
const componentDir = path.join(LIB, componentName);
|
||||||
|
|
||||||
if(fs.existsSync(componentDir)) {
|
if (fs.existsSync(componentDir)) {
|
||||||
console.log('Oops! That component already exists. Try another name?');
|
console.log('Oops! That component already exists. Try another name?');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.mkdirSync(componentDir);
|
fs.mkdirSync(componentDir);
|
||||||
|
|
||||||
const files = await glob('**/*', { cwd: TEMPLATE, filesOnly: true });
|
const files = await glob('**/*', { cwd: TEMPLATE, filesOnly: true });
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const content = fs.readFileSync(path.join(TEMPLATE, file), 'utf8');
|
const content = fs.readFileSync(path.join(TEMPLATE, file), 'utf8');
|
||||||
const writeContent = content.replace(/YourComponent/g, componentName);
|
const writeContent = content.replace(/YourComponent/g, componentName);
|
||||||
const writePath = path.join(LIB, file.replace(/YourComponent/g, componentName));
|
const writePath = path.join(
|
||||||
|
LIB,
|
||||||
|
file.replace(/YourComponent/g, componentName)
|
||||||
|
);
|
||||||
fs.ensureDirSync(path.dirname(writePath));
|
fs.ensureDirSync(path.dirname(writePath));
|
||||||
fs.writeFileSync(writePath, writeContent);
|
fs.writeFileSync(writePath, writeContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`${green('✔')} ${bold('Your component is ready at:')}\n📁 ${cyan(`src/component/${bold(componentName)}/${componentName}.svelte`)}`);
|
console.log(
|
||||||
|
`${green('✔')} ${bold('Your component is ready at:')}\n📁 ${cyan(`src/component/${bold(componentName)}/${componentName}.svelte`)}`
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
makeNewComponent();
|
makeNewComponent();
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
// You can declare custom types to help users implement your component.
|
// You can declare custom types to help users implement your component.
|
||||||
type ContainerWidth = 'normal' | 'wide' | 'wider' | 'widest' | 'fluid';
|
type ContainerWidth = 'normal' | 'wide' | 'wider' | 'widest' | 'fluid';
|
||||||
|
|
||||||
/** Width of the component within the text well. */
|
/** Width of the component within the text well. */
|
||||||
export let width: ContainerWidth = 'normal';
|
export let width: ContainerWidth = 'normal';
|
||||||
|
|
||||||
|
|
@ -34,9 +34,9 @@
|
||||||
|
|
||||||
<Block {width} {id} cls="photo {cls}">
|
<Block {width} {id} cls="photo {cls}">
|
||||||
<div
|
<div
|
||||||
style:background-image={`url(${src})`}
|
style:background-image="{`url(${src})`}"
|
||||||
style:height={`${height}px`}
|
style:height="{`${height}px`}"
|
||||||
/>
|
></div>
|
||||||
<p class="visually-hidden">{altText}</p>
|
<p class="visually-hidden">{altText}</p>
|
||||||
</Block>
|
</Block>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,13 @@ export const scss = {
|
||||||
includePaths: ['src/', 'node_modules/bootstrap/scss/'],
|
includePaths: ['src/', 'node_modules/bootstrap/scss/'],
|
||||||
importer: [
|
importer: [
|
||||||
(url) => {
|
(url) => {
|
||||||
if (/^\$lib/.test(url)) { return { file: `src/${url.replace('$lib', '')}` }; }
|
if (/^\$lib/.test(url)) {
|
||||||
|
return { file: `src/${url.replace('$lib', '')}` };
|
||||||
|
}
|
||||||
// Redirect tilde-prefixed imports to node_modules
|
// Redirect tilde-prefixed imports to node_modules
|
||||||
if (/^~/.test(url)) { return { file: `node_modules/${url.replace('~', '')}` }; }
|
if (/^~/.test(url)) {
|
||||||
|
return { file: `node_modules/${url.replace('~', '')}` };
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
||||||
24
eslint.config.js
Normal file
24
eslint.config.js
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { svelte } from '@reuters-graphics/yaks-eslint';
|
||||||
|
import reactPlugin from 'eslint-plugin-react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {import("eslint").Linter.Config[]}
|
||||||
|
*/
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
files: ['src/**/*.{js,ts,svelte,jsx,tsx}', '.storybook/**/*'],
|
||||||
|
ignores: ['node_modules', 'docs/**/*'],
|
||||||
|
},
|
||||||
|
...svelte,
|
||||||
|
reactPlugin.configs.flat.recommended,
|
||||||
|
{
|
||||||
|
rules: {
|
||||||
|
'react/prop-types': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
skipUndeclared: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
13820
package-lock.json
generated
13820
package-lock.json
generated
File diff suppressed because it is too large
Load diff
40
package.json
40
package.json
|
|
@ -28,16 +28,13 @@
|
||||||
"dist"
|
"dist"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.19"
|
"node": ">=18.20"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@americanexpress/css-to-js": "^1.0.1",
|
"@americanexpress/css-to-js": "^1.0.1",
|
||||||
"@babel/core": "^7.21.4",
|
"@evilmartians/lefthook": "^1.7.14",
|
||||||
"@babel/eslint-parser": "^7.21.3",
|
"@reuters-graphics/yaks-eslint": "^0.0.6",
|
||||||
"@babel/eslint-plugin": "^7.19.1",
|
"@reuters-graphics/yaks-prettier": "^0.0.4",
|
||||||
"@babel/preset-env": "^7.21.4",
|
|
||||||
"@evilmartians/lefthook": "^1.3.10",
|
|
||||||
"@reuters-graphics/eslint-config": "^0.0.2",
|
|
||||||
"@storybook/addon-actions": "^7.4.2",
|
"@storybook/addon-actions": "^7.4.2",
|
||||||
"@storybook/addon-docs": "^7.4.2",
|
"@storybook/addon-docs": "^7.4.2",
|
||||||
"@storybook/addon-essentials": "^7.4.2",
|
"@storybook/addon-essentials": "^7.4.2",
|
||||||
|
|
@ -54,41 +51,29 @@
|
||||||
"@storybook/testing-library": "^0.1.0",
|
"@storybook/testing-library": "^0.1.0",
|
||||||
"@storybook/theming": "^7.4.2",
|
"@storybook/theming": "^7.4.2",
|
||||||
"@sveltejs/vite-plugin-svelte": "^2.4.1",
|
"@sveltejs/vite-plugin-svelte": "^2.4.1",
|
||||||
"@tsconfig/svelte": "^4.0.1",
|
"@types/eslint": "^9.6.0",
|
||||||
"@types/google-publisher-tag": "^1.20240219.0",
|
"@types/google-publisher-tag": "^1.20240219.0",
|
||||||
"@types/gtag.js": "^0.0.12",
|
"@types/gtag.js": "^0.0.12",
|
||||||
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/mdx": "^2.0.5",
|
"@types/mdx": "^2.0.5",
|
||||||
"@types/proper-url-join": "^2.1.1",
|
"@types/proper-url-join": "^2.1.1",
|
||||||
"@types/react-syntax-highlighter": "^15.5.7",
|
"@types/react-syntax-highlighter": "^15.5.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
|
||||||
"@typescript-eslint/parser": "^5.59.0",
|
|
||||||
"auto": "^11.0.0",
|
"auto": "^11.0.0",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"babel-loader": "^9.1.2",
|
|
||||||
"change-case": "^4.1.2",
|
"change-case": "^4.1.2",
|
||||||
"chromatic": "^7.1.0",
|
"chromatic": "^7.1.0",
|
||||||
"colord": "^2.9.3",
|
"colord": "^2.9.3",
|
||||||
"css-color-converter": "^2.0.0",
|
"css-color-converter": "^2.0.0",
|
||||||
"deep-object-diff": "^1.1.9",
|
"deep-object-diff": "^1.1.9",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^9.9.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-plugin-react": "^7.35.0",
|
||||||
"eslint-config-standard-jsx": "^11.0.0",
|
|
||||||
"eslint-config-standard-react": "^13.0.0",
|
|
||||||
"eslint-plugin-import": "^2.27.5",
|
|
||||||
"eslint-plugin-n": "^16.0.0",
|
|
||||||
"eslint-plugin-node": "^11.1.0",
|
|
||||||
"eslint-plugin-promise": "^6.1.1",
|
|
||||||
"eslint-plugin-react": "^7.32.2",
|
|
||||||
"eslint-plugin-storybook": "^0.6.12",
|
|
||||||
"eslint-plugin-svelte": "^2.35.1",
|
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
"kleur": "^4.1.5",
|
"kleur": "^4.1.5",
|
||||||
"mermaid": "^10.3.0",
|
"mermaid": "^10.3.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"postcss": "^8.4.24",
|
"postcss": "^8.4.24",
|
||||||
"postcss-load-config": "^4.0.1",
|
"postcss-load-config": "^4.0.1",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^3.3.3",
|
||||||
"prettier-plugin-svelte": "^2.10.1",
|
|
||||||
"prompts": "^2.4.2",
|
"prompts": "^2.4.2",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
|
@ -104,7 +89,7 @@
|
||||||
"svelte-preprocess": "^5.1.3",
|
"svelte-preprocess": "^5.1.3",
|
||||||
"svelte2tsx": "^0.6.27",
|
"svelte2tsx": "^0.6.27",
|
||||||
"tiny-glob": "^0.2.9",
|
"tiny-glob": "^0.2.9",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.5.4",
|
||||||
"vite": "^4.4.9"
|
"vite": "^4.4.9"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -115,14 +100,13 @@
|
||||||
"@sveltejs/svelte-scroller": "^2.0.7",
|
"@sveltejs/svelte-scroller": "^2.0.7",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"dayjs": "^1.11.3",
|
"dayjs": "^1.11.3",
|
||||||
"journalize": "^2.5.1",
|
"journalize": "^2.6.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"lottie-web": "^5.7.13",
|
|
||||||
"marked": "^4.0.8",
|
"marked": "^4.0.8",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"proper-url-join": "^2.1.1",
|
"proper-url-join": "^2.1.1",
|
||||||
"pym.js": "^1.3.2",
|
"pym.js": "^1.3.2",
|
||||||
"slugify": "^1.6.5",
|
"slugify": "^1.6.6",
|
||||||
"standard": "^17.1.0",
|
"standard": "^17.1.0",
|
||||||
"svelte-fa": "^2.4.0",
|
"svelte-fa": "^2.4.0",
|
||||||
"svelte-intersection-observer": "^0.10.0",
|
"svelte-intersection-observer": "^0.10.0",
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,14 @@ export type Option = {
|
||||||
/**
|
/**
|
||||||
* Used for any props that restrict width of a container to one of pre-fab widths.
|
* Used for any props that restrict width of a container to one of pre-fab widths.
|
||||||
*/
|
*/
|
||||||
export type ContainerWidth = 'narrower' | 'narrow' | 'normal' | 'wide' | 'wider' | 'widest' | 'fluid';
|
export type ContainerWidth =
|
||||||
|
| 'narrower'
|
||||||
|
| 'narrow'
|
||||||
|
| 'normal'
|
||||||
|
| 'wide'
|
||||||
|
| 'wider'
|
||||||
|
| 'widest'
|
||||||
|
| 'fluid';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to set headline class fluid size from text-2xl to text-6xl
|
* Used to set headline class fluid size from text-2xl to text-6xl
|
||||||
|
|
@ -30,7 +37,7 @@ export interface ScrollerStep {
|
||||||
/**
|
/**
|
||||||
* Optional props for background component
|
* Optional props for background component
|
||||||
*/
|
*/
|
||||||
backgroundProps?: Object;
|
backgroundProps?: object;
|
||||||
/**
|
/**
|
||||||
* Foreground can either be a component or markdown-formatted string.
|
* Foreground can either be a component or markdown-formatted string.
|
||||||
* @required
|
* @required
|
||||||
|
|
@ -39,5 +46,5 @@ export interface ScrollerStep {
|
||||||
/**
|
/**
|
||||||
* Optional props for foreground component
|
* Optional props for foreground component
|
||||||
*/
|
*/
|
||||||
foregroundProps?: Object;
|
foregroundProps?: object;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,30 +23,36 @@ export type SponsorshipAd = {
|
||||||
export type InlineAd = {
|
export type InlineAd = {
|
||||||
mobile: {
|
mobile: {
|
||||||
adType: 'mpu' | 'native' | 'mpu2';
|
adType: 'mpu' | 'native' | 'mpu2';
|
||||||
placementName: 'reuters_mobile_mpu_1' | 'reuters_mobile_mpu_2' | 'reuters_mobile_mpu_3';
|
placementName:
|
||||||
|
| 'reuters_mobile_mpu_1'
|
||||||
|
| 'reuters_mobile_mpu_2'
|
||||||
|
| 'reuters_mobile_mpu_3';
|
||||||
};
|
};
|
||||||
desktop: {
|
desktop: {
|
||||||
adType: 'native' | 'canvas' | 'flex';
|
adType: 'native' | 'canvas' | 'flex';
|
||||||
placementName: 'reuters_desktop_native_1' | 'reuters_desktop_native_2' | 'reuters_desktop_native_3';
|
placementName:
|
||||||
|
| 'reuters_desktop_native_1'
|
||||||
|
| 'reuters_desktop_native_2'
|
||||||
|
| 'reuters_desktop_native_3';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DesktopPlacementName = |
|
export type DesktopPlacementName =
|
||||||
LeaderboardAd['desktop']['placementName'] |
|
| LeaderboardAd['desktop']['placementName']
|
||||||
SponsorshipAd['desktop']['placementName'] |
|
| SponsorshipAd['desktop']['placementName']
|
||||||
InlineAd['desktop']['placementName'];
|
| InlineAd['desktop']['placementName'];
|
||||||
|
|
||||||
export type MobilePlacementName = |
|
export type MobilePlacementName =
|
||||||
LeaderboardAd['mobile']['placementName'] |
|
| LeaderboardAd['mobile']['placementName']
|
||||||
SponsorshipAd['mobile']['placementName'] |
|
| SponsorshipAd['mobile']['placementName']
|
||||||
InlineAd['mobile']['placementName'];
|
| InlineAd['mobile']['placementName'];
|
||||||
|
|
||||||
export type DesktopAdType = |
|
export type DesktopAdType =
|
||||||
LeaderboardAd['desktop']['adType'] |
|
| LeaderboardAd['desktop']['adType']
|
||||||
SponsorshipAd['desktop']['adType'] |
|
| SponsorshipAd['desktop']['adType']
|
||||||
InlineAd['desktop']['adType'];
|
| InlineAd['desktop']['adType'];
|
||||||
|
|
||||||
export type MobileAdType = |
|
export type MobileAdType =
|
||||||
LeaderboardAd['mobile']['adType'] |
|
| LeaderboardAd['mobile']['adType']
|
||||||
SponsorshipAd['mobile']['adType'] |
|
| SponsorshipAd['mobile']['adType']
|
||||||
InlineAd['mobile']['adType'];
|
| InlineAd['mobile']['adType'];
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
type: adType,
|
type: adType,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
// @ts-ignore
|
// @ts-ignore window global
|
||||||
const freestar = window?.freestar;
|
const freestar = window?.freestar;
|
||||||
// Add adSlot to freestar queue directly if already initialised
|
// Add adSlot to freestar queue directly if already initialised
|
||||||
if (freestar) {
|
if (freestar) {
|
||||||
|
|
@ -41,7 +41,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
// @ts-ignore
|
// @ts-ignore window global
|
||||||
const freestar = window?.freestar;
|
const freestar = window?.freestar;
|
||||||
if (freestar) {
|
if (freestar) {
|
||||||
freestar.queue.push(function () {
|
freestar.queue.push(function () {
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,13 @@
|
||||||
const desktopPlacementName: InlineAd['desktop']['placementName'] = `reuters_desktop_native_${n}`;
|
const desktopPlacementName: InlineAd['desktop']['placementName'] = `reuters_desktop_native_${n}`;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Block id="{id}" class="freestar-adslot {cls}">
|
<Block {id} class="freestar-adslot {cls}">
|
||||||
<div class="ad-block">
|
<div class="ad-block">
|
||||||
<div class="ad-label">Advertisement · Scroll to continue</div>
|
<div class="ad-label">Advertisement · Scroll to continue</div>
|
||||||
<div class="ad-container">
|
<div class="ad-container">
|
||||||
<div class="ad-slot__inner">
|
<div class="ad-slot__inner">
|
||||||
<div>
|
<div>
|
||||||
<ResponsiveAd desktopPlacementName="{desktopPlacementName}" />
|
<ResponsiveAd {desktopPlacementName} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore raw
|
||||||
import adDocs from './stories/docs/leaderboard.md?raw';
|
import adDocs from './stories/docs/leaderboard.md?raw';
|
||||||
|
|
||||||
import AdScripts from './AdScripts.svelte';
|
import AdScripts from './AdScripts.svelte';
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
<Meta title="Components/LeaderboardAd" {...meta} />
|
<Meta title="Components/LeaderboardAd" {...meta} />
|
||||||
|
|
||||||
<Template let:args>
|
<Template>
|
||||||
<div>
|
<div>
|
||||||
<AdScripts />
|
<AdScripts />
|
||||||
<LeaderboardAd />
|
<LeaderboardAd />
|
||||||
|
|
|
||||||
|
|
@ -48,16 +48,16 @@
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="leaderboard__sticky {cls}"
|
class="leaderboard__sticky {cls}"
|
||||||
class:sticky="{sticky}"
|
class:sticky
|
||||||
class:unstick="{unstick}"
|
class:unstick
|
||||||
id="{id}"
|
{id}
|
||||||
style="--height: {adSize}px;"
|
style="--height: {adSize}px;"
|
||||||
>
|
>
|
||||||
<div class="ad-block">
|
<div class="ad-block">
|
||||||
<div class="ad-slot__container">
|
<div class="ad-slot__container">
|
||||||
<div class="ad-slot__inner">
|
<div class="ad-slot__inner">
|
||||||
<div>
|
<div>
|
||||||
<ResponsiveAd desktopPlacementName="{desktopPlacementName}" />
|
<ResponsiveAd {desktopPlacementName} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,9 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
$: placementName =
|
$: placementName =
|
||||||
windowWidth && windowWidth < mobileBreakpoint
|
windowWidth && windowWidth < mobileBreakpoint ?
|
||||||
? getMobilePlacementName(desktopPlacementName)
|
getMobilePlacementName(desktopPlacementName)
|
||||||
: desktopPlacementName;
|
: desktopPlacementName;
|
||||||
$: adType = getAdType(placementName);
|
$: adType = getAdType(placementName);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -68,6 +68,6 @@
|
||||||
|
|
||||||
{#if windowWidth}
|
{#if windowWidth}
|
||||||
{#key placementName}
|
{#key placementName}
|
||||||
<AdSlot placementName="{placementName}" adType="{adType}" />
|
<AdSlot {placementName} {adType} />
|
||||||
{/key}
|
{/key}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore raw
|
||||||
import adDocs from './stories/docs/sponsorship.md?raw';
|
import adDocs from './stories/docs/sponsorship.md?raw';
|
||||||
|
|
||||||
import AdScripts from './AdScripts.svelte';
|
import AdScripts from './AdScripts.svelte';
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
<Meta title="Components/SponsorshipAd" {...meta} />
|
<Meta title="Components/SponsorshipAd" {...meta} />
|
||||||
|
|
||||||
<Template let:args>
|
<Template>
|
||||||
<div>
|
<div>
|
||||||
<AdScripts />
|
<AdScripts />
|
||||||
<SponsorshipAd />
|
<SponsorshipAd />
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
'reuters_sponsorlogo';
|
'reuters_sponsorlogo';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Block id="{id}" class="freestar-adslot {cls}">
|
<Block {id} class="freestar-adslot {cls}">
|
||||||
<div class="ad-block">
|
<div class="ad-block">
|
||||||
{#if adLabel}
|
{#if adLabel}
|
||||||
<div class="ad-label">
|
<div class="ad-label">
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
<div class="ad-container">
|
<div class="ad-container">
|
||||||
<div class="ad-slot__inner">
|
<div class="ad-slot__inner">
|
||||||
<div>
|
<div>
|
||||||
<ResponsiveAd desktopPlacementName="{desktopPlacementName}" />
|
<ResponsiveAd {desktopPlacementName} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import getParameterByName from './getParameterByName';
|
import getParameterByName from './getParameterByName';
|
||||||
import Ias from './ias';
|
import Ias from './ias';
|
||||||
|
|
||||||
|
|
@ -12,10 +13,12 @@ export const loadBootstrap = () => {
|
||||||
freestar.queue = freestar.queue || [];
|
freestar.queue = freestar.queue || [];
|
||||||
freestar.config = freestar.config || {};
|
freestar.config = freestar.config || {};
|
||||||
freestar.config.enabled_slots = [];
|
freestar.config.enabled_slots = [];
|
||||||
freestar.initCallback = function() {
|
freestar.initCallback = function () {
|
||||||
freestar.config.enabled_slots.length === 0 ?
|
if (freestar.config.enabled_slots.length === 0) {
|
||||||
(freestar.initCallbackCalled = false) :
|
freestar.initCallbackCalled = false;
|
||||||
|
} else {
|
||||||
freestar.newAdSlots(freestar.config.enabled_slots);
|
freestar.newAdSlots(freestar.config.enabled_slots);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
freestar.config.channel = '/4735792/reuters.com/graphics';
|
freestar.config.channel = '/4735792/reuters.com/graphics';
|
||||||
|
|
@ -40,7 +43,7 @@ export const loadBootstrap = () => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
(<any>window).bootstrap.getResults((result) => {
|
(<any>window).bootstrap.getResults(() => {
|
||||||
// Set GAM
|
// Set GAM
|
||||||
window.googletag = (<any>window).googletag || { cmd: [] };
|
window.googletag = (<any>window).googletag || { cmd: [] };
|
||||||
window.googletag.cmd.push(() => {
|
window.googletag.cmd.push(() => {
|
||||||
|
|
@ -48,24 +51,29 @@ export const loadBootstrap = () => {
|
||||||
/**
|
/**
|
||||||
* @TODO Property 'enableAsyncRendering' does not exist on type 'PubAdsService'.
|
* @TODO Property 'enableAsyncRendering' does not exist on type 'PubAdsService'.
|
||||||
*/
|
*/
|
||||||
// @ts-ignore
|
// @ts-ignore window global
|
||||||
window.googletag.pubads().enableAsyncRendering();
|
window.googletag.pubads().enableAsyncRendering();
|
||||||
window.googletag.pubads().collapseEmptyDivs(true);
|
window.googletag.pubads().collapseEmptyDivs(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set page-level key-values
|
// Set page-level key-values
|
||||||
// cf: https://help.freestar.com/help/using-key-values
|
// cf: https://help.freestar.com/help/using-key-values
|
||||||
freestar.queue.push(function() {
|
freestar.queue.push(function () {
|
||||||
// Global Ads test targeting
|
// Global Ads test targeting
|
||||||
const adstest = new URL(document.location.href).searchParams.get('adstest');
|
const adstest = new URL(document.location.href).searchParams.get(
|
||||||
|
'adstest'
|
||||||
|
);
|
||||||
if (adstest) {
|
if (adstest) {
|
||||||
window.googletag.pubads().setTargeting('adstest', adstest);
|
window.googletag.pubads().setTargeting('adstest', adstest);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the URL path to create a unique ID for the page.
|
// Use the URL path to create a unique ID for the page.
|
||||||
const graphicId = window.location.pathname.split('/')
|
const graphicId =
|
||||||
// Get the first lowercase slug in the pathname, which is the graphic UID.
|
window.location.pathname
|
||||||
.filter(d => d.match(/[a-z0-9]+/) && d !== 'graphics')[0] || 'unknown-graphic';
|
.split('/')
|
||||||
|
// Get the first lowercase slug in the pathname, which is the graphic UID.
|
||||||
|
.filter((d) => d.match(/[a-z0-9]+/) && d !== 'graphics')[0] ||
|
||||||
|
'unknown-graphic';
|
||||||
window.googletag.pubads().setTargeting('template', 'graphics');
|
window.googletag.pubads().setTargeting('template', 'graphics');
|
||||||
window.googletag.pubads().setTargeting('graphicId', graphicId);
|
window.googletag.pubads().setTargeting('graphicId', graphicId);
|
||||||
});
|
});
|
||||||
|
|
@ -74,8 +82,11 @@ export const loadBootstrap = () => {
|
||||||
console.error('Ad queue not initialized!');
|
console.error('Ad queue not initialized!');
|
||||||
}
|
}
|
||||||
|
|
||||||
freestar.queue.push(function() {
|
freestar.queue.push(function () {
|
||||||
freestar.newAdSlots((<any>window).graphicsAdQueue || [], freestar.config.channel);
|
freestar.newAdSlots(
|
||||||
|
(<any>window).graphicsAdQueue || [],
|
||||||
|
freestar.config.channel
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
const IAS_REQUEST_TIMEOUT = 600;
|
const IAS_REQUEST_TIMEOUT = 600;
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
interface attributesInterface {
|
interface attributesInterface {
|
||||||
onload?: () => void,
|
onload?: () => void;
|
||||||
async?: boolean
|
async?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loadScript = (src: string, attributes?: attributesInterface) => {
|
export const loadScript = (src: string, attributes?: attributesInterface) => {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
<script>
|
<script>
|
||||||
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
||||||
|
|
||||||
// Don't lose the "?raw" in markdown imports!
|
// @ts-ignore raw
|
||||||
// @ts-ignore
|
|
||||||
import componentDocs from './stories/docs/component.md?raw';
|
import componentDocs from './stories/docs/component.md?raw';
|
||||||
// @ts-ignore
|
// @ts-ignore raw
|
||||||
import environmentsDocs from './stories/docs/environments.md?raw';
|
import environmentsDocs from './stories/docs/environments.md?raw';
|
||||||
// @ts-ignore
|
// @ts-ignore raw
|
||||||
import multipageDocs from './stories/docs/multipage.md?raw';
|
import multipageDocs from './stories/docs/multipage.md?raw';
|
||||||
|
|
||||||
import Analytics from './Analytics.svelte';
|
import Analytics from './Analytics.svelte';
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
||||||
|
|
||||||
// Don't lose the "?raw" in markdown imports!
|
// @ts-ignore raw
|
||||||
// @ts-ignore
|
|
||||||
import componentDocs from './stories/docs/component.md?raw';
|
import componentDocs from './stories/docs/component.md?raw';
|
||||||
// @ts-ignore
|
// @ts-ignore raw
|
||||||
import customWellWidthsDocs from './stories/docs/customWellWidths.md?raw';
|
import customWellWidthsDocs from './stories/docs/customWellWidths.md?raw';
|
||||||
|
|
||||||
import Article from './Article.svelte';
|
import Article from './Article.svelte';
|
||||||
|
|
|
||||||
|
|
@ -43,12 +43,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<article
|
<article {id} class:embedded {role} use:cssVariables="{columnWidthVars}">
|
||||||
id="{id}"
|
|
||||||
class:embedded
|
|
||||||
role="{role}"
|
|
||||||
use:cssVariables="{columnWidthVars}"
|
|
||||||
>
|
|
||||||
<!-- Article content -->
|
<!-- Article content -->
|
||||||
<slot />
|
<slot />
|
||||||
</article>
|
</article>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
<script>
|
<script>
|
||||||
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore raw
|
||||||
import componentDocs from './stories/docs/component.md?raw';
|
import componentDocs from './stories/docs/component.md?raw';
|
||||||
// @ts-ignore
|
// @ts-ignore raw
|
||||||
import withOverlaysDocs from './stories/docs/withOverlays.md?raw';
|
import withOverlaysDocs from './stories/docs/withOverlays.md?raw';
|
||||||
// @ts-ignore
|
// @ts-ignore raw
|
||||||
import ariaDescriptionsDocs from './stories/docs/ariaDescriptions.md?raw';
|
import ariaDescriptionsDocs from './stories/docs/ariaDescriptions.md?raw';
|
||||||
|
|
||||||
import BeforeAfter from './BeforeAfter.svelte';
|
import BeforeAfter from './BeforeAfter.svelte';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore raw
|
||||||
import beforeImg from './stories/myrne-before.jpg';
|
import beforeImg from './stories/myrne-before.jpg';
|
||||||
// @ts-ignore
|
// @ts-ignore raw
|
||||||
import afterImg from './stories/myrne-after.jpg';
|
import afterImg from './stories/myrne-after.jpg';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|
@ -90,13 +90,13 @@
|
||||||
afterAlt="Satellite image of Russian base at Myrne taken on Oct. 20, 2020."
|
afterAlt="Satellite image of Russian base at Myrne taken on Oct. 20, 2020."
|
||||||
>
|
>
|
||||||
<div let:description="{id}" slot="beforeOverlay" class="overlay p-3">
|
<div let:description="{id}" slot="beforeOverlay" class="overlay p-3">
|
||||||
<p class="body-caption" id="{id}">
|
<p class="body-caption" {id}>
|
||||||
On July 7, 2020, the base contained only a few transport vehicles.
|
On July 7, 2020, the base contained only a few transport vehicles.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div let:description="{id}" slot="afterOverlay" class="overlay p-3">
|
<div let:description="{id}" slot="afterOverlay" class="overlay p-3">
|
||||||
<!-- 👇 id can also be used on an element containing multiple text elements -->
|
<!-- 👇 id can also be used on an element containing multiple text elements -->
|
||||||
<div id="{id}">
|
<div {id}>
|
||||||
<p class="body-caption">
|
<p class="body-caption">
|
||||||
But by October, tanks and artillery could be seen.
|
But by October, tanks and artillery could be seen.
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
|
|
@ -116,16 +116,15 @@
|
||||||
const move = (e) => {
|
const move = (e) => {
|
||||||
if (sliding && imgOffset) {
|
if (sliding && imgOffset) {
|
||||||
const el = e.touches ? e.touches[0] : e;
|
const el = e.touches ? e.touches[0] : e;
|
||||||
const figureOffset = figure
|
const figureOffset =
|
||||||
? parseInt(window.getComputedStyle(figure).marginLeft.slice(0, -2))
|
figure ?
|
||||||
|
parseInt(window.getComputedStyle(figure).marginLeft.slice(0, -2))
|
||||||
: 0;
|
: 0;
|
||||||
let x = el.pageX - figureOffset - imgOffset.left;
|
let x = el.pageX - figureOffset - imgOffset.left;
|
||||||
x =
|
x =
|
||||||
x < handleMargin
|
x < handleMargin ? handleMargin
|
||||||
? handleMargin
|
: x > w - handleMargin ? w - handleMargin
|
||||||
: x > w - handleMargin
|
: x;
|
||||||
? w - handleMargin
|
|
||||||
: x;
|
|
||||||
offset = x / w;
|
offset = x / w;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -160,7 +159,7 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{#if beforeSrc && beforeAlt && afterSrc && afterAlt}
|
{#if beforeSrc && beforeAlt && afterSrc && afterAlt}
|
||||||
<Block width="{width}" id="{id}" class="photo before-after fmy-6 {cls}">
|
<Block {width} {id} class="photo before-after fmy-6 {cls}">
|
||||||
<div
|
<div
|
||||||
style="height: {containerHeight}px;"
|
style="height: {containerHeight}px;"
|
||||||
bind:clientWidth="{containerWidth}"
|
bind:clientWidth="{containerWidth}"
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
<script>
|
<script>
|
||||||
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore raw
|
||||||
import componentDocs from './stories/docs/component.md?raw';
|
import componentDocs from './stories/docs/component.md?raw';
|
||||||
// @ts-ignore
|
// @ts-ignore raw
|
||||||
import customLayoutsDocs from './stories/docs/customLayouts.md?raw';
|
import customLayoutsDocs from './stories/docs/customLayouts.md?raw';
|
||||||
// @ts-ignore
|
// @ts-ignore raw
|
||||||
import snapWidthsDocs from './stories/docs/snapWidths.md?raw';
|
import snapWidthsDocs from './stories/docs/snapWidths.md?raw';
|
||||||
|
|
||||||
import Block from './Block.svelte';
|
import Block from './Block.svelte';
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,10 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
id="{id}"
|
{id}
|
||||||
class="article-block fmx-auto {width} {cls}"
|
class="article-block fmx-auto {width} {cls}"
|
||||||
class:snap="{snap && width !== 'fluid' && width !== 'widest'}"
|
class:snap="{snap && width !== 'fluid' && width !== 'widest'}"
|
||||||
role="{role}"
|
{role}
|
||||||
aria-label="{ariaLabel}"
|
aria-label="{ariaLabel}"
|
||||||
>
|
>
|
||||||
<!-- block content -->
|
<!-- block content -->
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore raw
|
||||||
import componentDocs from './stories/docs/component.md?raw';
|
import componentDocs from './stories/docs/component.md?raw';
|
||||||
|
|
||||||
import BodyText from './BodyText.svelte';
|
import BodyText from './BodyText.svelte';
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,6 @@
|
||||||
import Block from '../Block/Block.svelte';
|
import Block from '../Block/Block.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Block id="{id}" class="fmy-6 {cls}">
|
<Block {id} class="fmy-6 {cls}">
|
||||||
<Markdown source="{text}" />
|
<Markdown source="{text}" />
|
||||||
</Block>
|
</Block>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore raw
|
||||||
import componentDocs from './stories/docs/component.md?raw';
|
import componentDocs from './stories/docs/component.md?raw';
|
||||||
|
|
||||||
import Byline from './Byline.svelte';
|
import Byline from './Byline.svelte';
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
first.getDate() === second.getDate();
|
first.getDate() === second.getDate();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Block id="{id}" class="byline-container {alignmentClass} {cls}" width="normal">
|
<Block {id} class="byline-container {alignmentClass} {cls}" width="normal">
|
||||||
<aside class="article-metadata font-subhed">
|
<aside class="article-metadata font-subhed">
|
||||||
<div class="byline body-caption fmb-1">
|
<div class="byline body-caption fmb-1">
|
||||||
{#if $$slots.byline}
|
{#if $$slots.byline}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import SyntaxHighlighter from 'react-syntax-highlighter/dist/esm/prism-light';
|
import SyntaxHighlighter from 'react-syntax-highlighter/dist/esm/prism-light';
|
||||||
// @ts-ignore
|
// @ts-ignore scss
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
import prism from 'react-syntax-highlighter/dist/esm/styles/prism/prism';
|
import prism from 'react-syntax-highlighter/dist/esm/styles/prism/prism';
|
||||||
import scss from 'react-syntax-highlighter/dist/esm/languages/prism/scss';
|
import scss from 'react-syntax-highlighter/dist/esm/languages/prism/scss';
|
||||||
|
|
@ -18,15 +18,17 @@ const Copyable = (props) => {
|
||||||
let timeout;
|
let timeout;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(timeout) clearTimeout(timeout);
|
if (timeout) clearTimeout(timeout);
|
||||||
timeout = setTimeout(() => { setCopied(false); }, 1500);
|
timeout = setTimeout(() => {
|
||||||
|
setCopied(false);
|
||||||
|
}, 1500);
|
||||||
}, [copied]);
|
}, [copied]);
|
||||||
|
|
||||||
const handleClick = async({ partial }) => {
|
const handleClick = async ({ partial }) => {
|
||||||
const copyText = `@import "@reuters-graphics/graphics-components/scss/colours/${formatPartial(partial)}";`
|
const copyText = `@import "@reuters-graphics/graphics-components/scss/colours/${formatPartial(partial)}";`;
|
||||||
await navigator.clipboard.writeText(copyText);
|
await navigator.clipboard.writeText(copyText);
|
||||||
setCopied(true);
|
setCopied(true);
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button className="copy-btn" onClick={() => handleClick(props)}>
|
<button className="copy-btn" onClick={() => handleClick(props)}>
|
||||||
|
|
@ -34,21 +36,19 @@ const Copyable = (props) => {
|
||||||
{copied && <span className="copy-tag">Copied</span>}
|
{copied && <span className="copy-tag">Copied</span>}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
const ImportSnippet = ({ included = false, partial = 'thematic/_tr.scss' }) => {
|
|
||||||
return included ? (
|
|
||||||
<div className={classes.importsnippet}>
|
|
||||||
<p>Included</p>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className={classes.importsnippet}>
|
|
||||||
<SyntaxHighlighter language="scss" style={prism}>
|
|
||||||
{`// global.scss \n@import "@reuters-graphics/graphics-components/scss/colours/${formatPartial(partial)}";`}
|
|
||||||
</SyntaxHighlighter>
|
|
||||||
<Copyable partial={partial} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ImportSnippet;
|
const ImportSnippet = ({ included = false, partial = 'thematic/_tr.scss' }) => {
|
||||||
|
return included ?
|
||||||
|
<div className={classes.importsnippet}>
|
||||||
|
<p>Included</p>
|
||||||
|
</div>
|
||||||
|
: <div className={classes.importsnippet}>
|
||||||
|
<SyntaxHighlighter language="scss" style={prism}>
|
||||||
|
{`// global.scss \n@import "@reuters-graphics/graphics-components/scss/colours/${formatPartial(partial)}";`}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
<Copyable partial={partial} />
|
||||||
|
</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ImportSnippet;
|
||||||
|
|
|
||||||
|
|
@ -2,23 +2,24 @@ import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import ImportSnippet from './ImportSnippet';
|
import ImportSnippet from './ImportSnippet';
|
||||||
import { Unstyled } from '@storybook/blocks';
|
import { Unstyled } from '@storybook/blocks';
|
||||||
// @ts-ignore
|
// @ts-ignore scss
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
|
|
||||||
const Copyable = (props) => {
|
const Copyable = (props) => {
|
||||||
const handleClick = async(props) => {
|
const handleClick = async (props) => {
|
||||||
const copyText = props.wrap ? `var(${props.children})` : props.children;
|
const copyText = props.wrap ? `var(${props.children})` : props.children;
|
||||||
await navigator.clipboard.writeText(copyText);
|
await navigator.clipboard.writeText(copyText);
|
||||||
props.setCopied(true);
|
props.setCopied(true);
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button className="copy-btn" onClick={() => handleClick(props)}>
|
<button className="copy-btn" onClick={() => handleClick(props)}>
|
||||||
<span className="material-symbols-outlined">content_copy</span>{props.children}
|
<span className="material-symbols-outlined">content_copy</span>
|
||||||
|
{props.children}
|
||||||
{props.copied && <div className="copy-tag">Copied</div>}
|
{props.copied && <div className="copy-tag">Copied</div>}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
const Cell = (props) => {
|
const Cell = (props) => {
|
||||||
const [copied, setCopied] = useState(false);
|
const [copied, setCopied] = useState(false);
|
||||||
|
|
@ -26,50 +27,80 @@ const Cell = (props) => {
|
||||||
let timeout;
|
let timeout;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(timeout) clearTimeout(timeout);
|
if (timeout) clearTimeout(timeout);
|
||||||
timeout = setTimeout(() => { setCopied(false); }, 1000);
|
timeout = setTimeout(() => {
|
||||||
|
setCopied(false);
|
||||||
|
}, 1000);
|
||||||
}, [copied]);
|
}, [copied]);
|
||||||
|
|
||||||
const copyProps = {...props, ...{ copied, setCopied } };
|
const copyProps = { ...props, ...{ copied, setCopied } };
|
||||||
|
|
||||||
return props.column === 0 ?
|
return props.column === 0 ?
|
||||||
<div className="swatch-container">
|
<div className="swatch-container">
|
||||||
<div className="swatch" style={{ backgroundColor: props.children }}></div>
|
<div
|
||||||
<span>
|
className="swatch"
|
||||||
<Copyable {...copyProps}>{props.children}</Copyable>
|
style={{ backgroundColor: props.children }}
|
||||||
</span>
|
></div>
|
||||||
</div>
|
<span>
|
||||||
: props.children.map(css => (
|
<Copyable {...copyProps}>{props.children}</Copyable>
|
||||||
<div key={css}>
|
</span>
|
||||||
<Copyable {...copyProps} wrap>{css}</Copyable>
|
</div>
|
||||||
</div>
|
: props.children.map((css) => (
|
||||||
));
|
<div key={css}>
|
||||||
}
|
<Copyable {...copyProps} wrap>
|
||||||
|
{css}
|
||||||
|
</Copyable>
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
const TD = (props) => <td><Cell {...props}>{props.children}</Cell></td>
|
const TD = (props) => (
|
||||||
const TR = (props) => <tr>{props.children.map((c, i) => (<TD {...props} column={i} key={i}>{c}</TD>))}</tr>
|
<td>
|
||||||
|
<Cell {...props}>{props.children}</Cell>
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
const TR = (props) => (
|
||||||
|
<tr>
|
||||||
|
{props.children.map((c, i) => (
|
||||||
|
<TD {...props} column={i} key={i}>
|
||||||
|
{c}
|
||||||
|
</TD>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
const TH = (props) => <th>{props.children}</th>;
|
const TH = (props) => <th>{props.children}</th>;
|
||||||
|
|
||||||
const CopyTable = ({ title = null, body, copyable, mdnLink = null, included = false, partial }) => {
|
const CopyTable = ({
|
||||||
const header=['Colour', 'CSS variable'];
|
title = null,
|
||||||
|
body,
|
||||||
|
copyable,
|
||||||
|
mdnLink = null,
|
||||||
|
included = false,
|
||||||
|
partial,
|
||||||
|
}) => {
|
||||||
|
const header = ['Colour', 'CSS variable'];
|
||||||
return (
|
return (
|
||||||
<Unstyled>
|
<Unstyled>
|
||||||
<div className={classes.title}>
|
<div className={classes.title}>{title}</div>
|
||||||
{title}
|
|
||||||
</div>
|
|
||||||
<ImportSnippet included={included} partial={partial} />
|
<ImportSnippet included={included} partial={partial} />
|
||||||
<table className={classes.table}>
|
<table className={classes.table}>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
{header.map(h => (<TH key={h}>{h}</TH>))}
|
{header.map((h) => (
|
||||||
|
<TH key={h}>{h}</TH>
|
||||||
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{body.map((b, i) => (<TR {...{ title, header, body, copyable, mdnLink}} key={i}>{b}</TR>))}
|
{body.map((b, i) => (
|
||||||
|
<TR {...{ title, header, body, copyable, mdnLink }} key={i}>
|
||||||
|
{b}
|
||||||
|
</TR>
|
||||||
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</Unstyled>
|
</Unstyled>
|
||||||
)
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CopyTable;
|
export default CopyTable;
|
||||||
|
|
|
||||||
|
|
@ -1,66 +1,99 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { Unstyled } from '@storybook/blocks';
|
import { Unstyled } from '@storybook/blocks';
|
||||||
// @ts-ignore
|
// @ts-ignore scss
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
|
|
||||||
const MultiLine = (props) => props.children.split('\n').map(t => (<div key={t}>{t}</div>))
|
const MultiLine = (props) =>
|
||||||
|
props.children.split('\n').map((t) => <div key={t}>{t}</div>);
|
||||||
|
|
||||||
const Copyable = (props) => {
|
const Copyable = (props) => {
|
||||||
const handleClick = async(props) => {
|
const handleClick = async (props) => {
|
||||||
const copyText = typeof props.copyable[props.column] === 'function' ?
|
const copyText =
|
||||||
props.copyable[props.column](`${props.children}`) : `${props.children}`;
|
typeof props.copyable[props.column] === 'function' ?
|
||||||
|
props.copyable[props.column](`${props.children}`)
|
||||||
|
: `${props.children}`;
|
||||||
await navigator.clipboard.writeText(copyText);
|
await navigator.clipboard.writeText(copyText);
|
||||||
setCopied(true);
|
setCopied(true);
|
||||||
}
|
};
|
||||||
|
|
||||||
const [copied, setCopied] = useState(false);
|
const [copied, setCopied] = useState(false);
|
||||||
|
|
||||||
let timeout;
|
let timeout;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(timeout) clearTimeout(timeout);
|
if (timeout) clearTimeout(timeout);
|
||||||
timeout = setTimeout(() => { setCopied(false); }, 1000);
|
timeout = setTimeout(() => {
|
||||||
|
setCopied(false);
|
||||||
|
}, 1000);
|
||||||
}, [copied]);
|
}, [copied]);
|
||||||
|
|
||||||
return props.copyable && props.copyable[props.column] ?
|
return props.copyable && props.copyable[props.column] ?
|
||||||
<button className="copy-btn" onClick={() => handleClick(props)}>
|
<button className="copy-btn" onClick={() => handleClick(props)}>
|
||||||
<span className="material-symbols-outlined">content_copy</span>{props.children}
|
<span className="material-symbols-outlined">content_copy</span>
|
||||||
{copied && <div className="copy-tag">Copied</div>}
|
{props.children}
|
||||||
</button> :
|
{copied && <div className="copy-tag">Copied</div>}
|
||||||
<MultiLine>{props.children}</MultiLine>;
|
</button>
|
||||||
}
|
: <MultiLine>{props.children}</MultiLine>;
|
||||||
|
};
|
||||||
|
|
||||||
const TD = (props) => <td><Copyable {...props}>{props.children}</Copyable></td>
|
const TD = (props) => (
|
||||||
const TR = (props) => <tr>{props.children.map((c, i) => (<TD {...props} column={i} key={i}>{c}</TD>))}</tr>
|
<td>
|
||||||
|
<Copyable {...props}>{props.children}</Copyable>
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
const TR = (props) => (
|
||||||
|
<tr>
|
||||||
|
{props.children.map((c, i) => (
|
||||||
|
<TD {...props} column={i} key={i}>
|
||||||
|
{c}
|
||||||
|
</TD>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
const TH = (props) => <th>{props.children}</th>;
|
const TH = (props) => <th>{props.children}</th>;
|
||||||
|
|
||||||
const CopyTable = ({ title = null, note = null, header, body, copyable, mdnLink = null }) => {
|
const CopyTable = ({
|
||||||
|
title = null,
|
||||||
|
note = null,
|
||||||
|
header,
|
||||||
|
body,
|
||||||
|
copyable,
|
||||||
|
mdnLink = null,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Unstyled>
|
<Unstyled>
|
||||||
<div className={classes.title}>
|
<div className={classes.title}>
|
||||||
{title}
|
{title}
|
||||||
{(title && mdnLink) && (
|
{title && mdnLink && (
|
||||||
<a href={`https://developer.mozilla.org/en-US/docs/Web/CSS/${mdnLink}`} target="_blank">
|
<a
|
||||||
|
href={`https://developer.mozilla.org/en-US/docs/Web/CSS/${mdnLink}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
<span className="material-symbols-outlined">link</span>
|
<span className="material-symbols-outlined">link</span>
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
{(note) && (
|
{note && <p>{note}</p>}
|
||||||
<p>{note}</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<table className={classes.table}>
|
<table className={classes.table}>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
{header.map(h => (<TH key={h}>{h}</TH>))}
|
{header.map((h) => (
|
||||||
|
<TH key={h}>{h}</TH>
|
||||||
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{body.map((b, i) => (<TR {...{ title, header, body, copyable, mdnLink}} key={i}>{b}</TR>))}
|
{body.map((b, i) => (
|
||||||
|
<TR {...{ title, header, body, copyable, mdnLink }} key={i}>
|
||||||
|
{b}
|
||||||
|
</TR>
|
||||||
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</Unstyled>
|
</Unstyled>
|
||||||
)
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CopyTable;
|
export default CopyTable;
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import lightTheme from '../../../components/Theme/themes/light';
|
||||||
const ThemeWrapper = (props) => {
|
const ThemeWrapper = (props) => {
|
||||||
const theme = flatten(lightTheme);
|
const theme = flatten(lightTheme);
|
||||||
const styleObj = {};
|
const styleObj = {};
|
||||||
Object.keys(theme).forEach(key => {
|
Object.keys(theme).forEach((key) => {
|
||||||
styleObj[`--theme-${key}`] = theme[key];
|
styleObj[`--theme-${key}`] = theme[key];
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,10 @@ export default function Mermaid(props) {
|
||||||
setGraphSvg(svg);
|
setGraphSvg(svg);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setGraphSvg('');
|
setGraphSvg('');
|
||||||
/* eslint-disable-next-line no-console */
|
|
||||||
console.error('Invalid mermaid syntax: %o', err);
|
console.error('Invalid mermaid syntax: %o', err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
parseMermaid(code);
|
parseMermaid(code);
|
||||||
}, [code]);
|
}, [code]);
|
||||||
|
|
@ -29,4 +29,4 @@ export default function Mermaid(props) {
|
||||||
dangerouslySetInnerHTML={{ __html: graphSvg || '' }}
|
dangerouslySetInnerHTML={{ __html: graphSvg || '' }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,6 @@ const VariableTable = (props) => {
|
||||||
copyable={[(v) => `var(${v})`]}
|
copyable={[(v) => `var(${v})`]}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default VariableTable;
|
export default VariableTable;
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,25 @@
|
||||||
import { HexAlphaColorPicker, HexColorInput } from 'react-colorful';
|
import { HexAlphaColorPicker, HexColorInput } from 'react-colorful';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
// @ts-ignore scss
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
import { fromString } from 'css-color-converter';
|
import { fromString } from 'css-color-converter';
|
||||||
|
|
||||||
const ColourPicker = ({ colour, onChange }) => {
|
const ColourPicker = ({ colour, onChange }) => {
|
||||||
return (
|
return (
|
||||||
<div className={classes.colourpicker}>
|
<div className={classes.colourpicker}>
|
||||||
<HexColorInput color={fromString(colour.trim()).toHexString()} onChange={onChange} alpha prefixed />
|
<HexColorInput
|
||||||
<HexAlphaColorPicker color={fromString(colour.trim()).toHexString()} onChange={onChange} />
|
color={fromString(colour.trim()).toHexString()}
|
||||||
|
onChange={onChange}
|
||||||
|
alpha
|
||||||
|
prefixed
|
||||||
|
/>
|
||||||
|
<HexAlphaColorPicker
|
||||||
|
color={fromString(colour.trim()).toHexString()}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ColourPicker;
|
export default ColourPicker;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import Key from './Key.jsx';
|
import Key from './Key.jsx';
|
||||||
import { Unstyled } from '@storybook/blocks';
|
// @ts-ignore scss
|
||||||
import Value from './Value.jsx';
|
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
|
|
||||||
const Customiser = ({ theme, themeName, setTheme }) => {
|
const Customiser = ({ theme, themeName, setTheme }) => {
|
||||||
|
|
@ -19,10 +18,10 @@ const Customiser = ({ theme, themeName, setTheme }) => {
|
||||||
value,
|
value,
|
||||||
key: themeName + key,
|
key: themeName + key,
|
||||||
};
|
};
|
||||||
return <Key {...props} />;
|
return <Key {...props} key={props.key} />;
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default Customiser;
|
export default Customiser;
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,18 @@ const Key = ({ value, name, map, themeName, setTheme, theme }) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
return (
|
return (
|
||||||
<div className="key">
|
<div className="key">
|
||||||
<button className={isOpen ? 'open' : ''} onClick={() => setIsOpen(o => !o)}>
|
<button
|
||||||
|
className={isOpen ? 'open' : ''}
|
||||||
|
onClick={() => setIsOpen((o) => !o)}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<span className="material-symbols-outlined">{isOpen ? 'expand_less' : 'expand_more'}</span>
|
<span className="material-symbols-outlined">
|
||||||
</div> {name}
|
{isOpen ? 'expand_less' : 'expand_more'}
|
||||||
|
</span>
|
||||||
|
</div>{' '}
|
||||||
|
{name}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{Object.entries(value).map(([key, value]) => {
|
{Object.entries(value).map(([key, value]) => {
|
||||||
const props = {
|
const props = {
|
||||||
theme,
|
theme,
|
||||||
|
|
@ -23,11 +29,12 @@ const Key = ({ value, name, map, themeName, setTheme, theme }) => {
|
||||||
key: themeName + map + key,
|
key: themeName + map + key,
|
||||||
};
|
};
|
||||||
if (!isOpen) return null;
|
if (!isOpen) return null;
|
||||||
if (typeof value === 'object') return <Key {...props} />;
|
if (typeof value === 'object')
|
||||||
return <Value {...props} />;
|
return <Key {...props} key={props.key} />;
|
||||||
|
return <Value {...props} key={props.key} />;
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default Key;
|
export default Key;
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,17 @@ const Input = ({ value, onChange }) => {
|
||||||
// this is buggy...
|
// this is buggy...
|
||||||
// if ((value || value === 0) && !isNaN(value)) return <input type="number" value={value} onChange={(e) => onChange(Number(e.target.value))}/>;
|
// if ((value || value === 0) && !isNaN(value)) return <input type="number" value={value} onChange={(e) => onChange(Number(e.target.value))}/>;
|
||||||
// Colour type
|
// Colour type
|
||||||
if (!/var\(.*\)/i.test(value) && CSS.supports('color', value)) return (
|
if (!/var\(.*\)/i.test(value) && CSS.supports('color', value))
|
||||||
<ColourPicker colour={value} onChange={onChange} />
|
return <ColourPicker colour={value} onChange={onChange} />;
|
||||||
);
|
|
||||||
// Text for the rest...
|
// Text for the rest...
|
||||||
return <input type="text" value={value} onChange={(e) => onChange(e.target.value)} />;
|
return (
|
||||||
}
|
<input
|
||||||
|
type="text"
|
||||||
|
value={value}
|
||||||
|
onChange={(e) => onChange(e.target.value)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const Value = ({ value, name, map, themeName, theme, setTheme }) => {
|
const Value = ({ value, name, map, themeName, theme, setTheme }) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
@ -30,20 +35,26 @@ const Value = ({ value, name, map, themeName, theme, setTheme }) => {
|
||||||
<div className="value">
|
<div className="value">
|
||||||
<label>
|
<label>
|
||||||
<div>
|
<div>
|
||||||
<button className={isOpen ? 'open' : ''} onClick={() => setIsOpen(o => !o)}>
|
<button
|
||||||
|
className={isOpen ? 'open' : ''}
|
||||||
|
onClick={() => setIsOpen((o) => !o)}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<span className="material-symbols-outlined">{isOpen ? 'expand_less' : 'expand_more'}</span>
|
<span className="material-symbols-outlined">
|
||||||
</div> {isColour && (<div style={{ background: value }}></div>)} {name}
|
{isOpen ? 'expand_less' : 'expand_more'}
|
||||||
|
</span>
|
||||||
|
</div>{' '}
|
||||||
|
{isColour && <div style={{ background: value }}></div>} {name}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<div className="input-container">
|
<div className="input-container">
|
||||||
<Input value={value} key={themeName+map} onChange={onChange}/>
|
<Input value={value} key={themeName + map} onChange={onChange} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default Value;
|
export default Value;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter';
|
import { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter';
|
||||||
import { Unstyled } from '@storybook/blocks';
|
|
||||||
import VariableTable from '../CSSVariables/VariableTable';
|
import VariableTable from '../CSSVariables/VariableTable';
|
||||||
|
// @ts-ignore scss
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
import darkTheme from '../../../../components/Theme/themes/dark';
|
import darkTheme from '../../../../components/Theme/themes/dark';
|
||||||
import { docco } from 'react-syntax-highlighter/dist/esm/styles/hljs';
|
|
||||||
import lightTheme from '../../../../components/Theme/themes/light';
|
import lightTheme from '../../../../components/Theme/themes/light';
|
||||||
import prism from 'react-syntax-highlighter/dist/esm/styles/prism/prism';
|
import prism from 'react-syntax-highlighter/dist/esm/styles/prism/prism';
|
||||||
import scss from 'react-syntax-highlighter/dist/esm/languages/prism/scss';
|
import scss from 'react-syntax-highlighter/dist/esm/languages/prism/scss';
|
||||||
|
|
@ -23,27 +22,34 @@ const NewTheme = ({ theme, themeName }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.newtheme}>
|
<div className={classes.newtheme}>
|
||||||
<p>Use the code below to adapt the <code>Theme</code> component for your new design:</p>
|
<p>
|
||||||
<SyntaxHighlighter language="svelte" style={prism}>
|
Use the code below to adapt the <code>Theme</code> component for your
|
||||||
{`<Theme
|
new design:
|
||||||
|
</p>
|
||||||
|
<SyntaxHighlighter language="svelte" style={prism}>
|
||||||
|
{`<Theme
|
||||||
base="${themeName}"
|
base="${themeName}"
|
||||||
theme={${JSON.stringify(updates, null, 2).replaceAll('"', '\'')}}
|
theme={${JSON.stringify(updates, null, 2).replaceAll('"', "'")}}
|
||||||
>
|
>
|
||||||
<!-- ... -->
|
<!-- ... -->
|
||||||
</Theme>
|
</Theme>
|
||||||
`}
|
`}
|
||||||
</SyntaxHighlighter>
|
</SyntaxHighlighter>
|
||||||
{bgChanged && (
|
{bgChanged && (
|
||||||
<SyntaxHighlighter language="scss" style={prism} customStyle={{ maxHeight: '140px' }}>
|
<SyntaxHighlighter
|
||||||
{`// global.scss
|
language="scss"
|
||||||
|
style={prism}
|
||||||
|
customStyle={{ maxHeight: '140px' }}
|
||||||
|
>
|
||||||
|
{`// global.scss
|
||||||
body {
|
body {
|
||||||
background-color: ${theme.colour.background};
|
background-color: ${theme.colour.background};
|
||||||
}`}
|
}`}
|
||||||
</SyntaxHighlighter>
|
</SyntaxHighlighter>
|
||||||
)}
|
)}
|
||||||
<VariableTable theme={theme} />
|
<VariableTable theme={theme} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default NewTheme;
|
export default NewTheme;
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,13 @@ import Customiser from './Customiser/Customiser';
|
||||||
import NewTheme from './NewTheme/NewTheme.jsx';
|
import NewTheme from './NewTheme/NewTheme.jsx';
|
||||||
import ThemeSwitch from './ThemeSwitch/Switch';
|
import ThemeSwitch from './ThemeSwitch/Switch';
|
||||||
import { Unstyled } from '@storybook/blocks';
|
import { Unstyled } from '@storybook/blocks';
|
||||||
|
// @ts-ignore scss
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
import darkTheme from '../../../components/Theme/themes/dark';
|
import darkTheme from '../../../components/Theme/themes/dark';
|
||||||
import lightTheme from '../../../components/Theme/themes/light';
|
import lightTheme from '../../../components/Theme/themes/light';
|
||||||
|
|
||||||
const ThemeBuilder = (props) => {
|
const ThemeBuilder = (_props) => {
|
||||||
const [themeName, setThemeName] = useState('light');
|
const [themeName, setThemeName] = useState('light');
|
||||||
const [theme, setTheme] = useState(cloneDeep(lightTheme));
|
const [theme, setTheme] = useState(cloneDeep(lightTheme));
|
||||||
|
|
||||||
|
|
@ -23,7 +24,12 @@ const ThemeBuilder = (props) => {
|
||||||
<div className={classes.themebuilder}>
|
<div className={classes.themebuilder}>
|
||||||
<div className="column">
|
<div className="column">
|
||||||
<ThemeSwitch setThemeName={setThemeName} themeName={themeName} />
|
<ThemeSwitch setThemeName={setThemeName} themeName={themeName} />
|
||||||
<Customiser theme={theme} setTheme={setTheme} themeName={themeName} key={themeName} />
|
<Customiser
|
||||||
|
theme={theme}
|
||||||
|
setTheme={setTheme}
|
||||||
|
themeName={themeName}
|
||||||
|
key={themeName}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="column">
|
<div className="column">
|
||||||
<NewTheme theme={theme} themeName={themeName} />
|
<NewTheme theme={theme} themeName={themeName} />
|
||||||
|
|
@ -31,6 +37,6 @@ const ThemeBuilder = (props) => {
|
||||||
</div>
|
</div>
|
||||||
</Unstyled>
|
</Unstyled>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ThemeBuilder;
|
export default ThemeBuilder;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Unstyled } from '@storybook/blocks';
|
// @ts-ignore scss
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
|
|
||||||
const ThemeSwitch = ({ themeName, setThemeName }) => {
|
const ThemeSwitch = ({ themeName, setThemeName }) => {
|
||||||
|
|
@ -11,14 +11,18 @@ const ThemeSwitch = ({ themeName, setThemeName }) => {
|
||||||
<button
|
<button
|
||||||
className={themeName === 'light' ? 'active' : ''}
|
className={themeName === 'light' ? 'active' : ''}
|
||||||
onClick={() => setThemeName('light')}
|
onClick={() => setThemeName('light')}
|
||||||
><span className="material-symbols-outlined">light_mode</span></button>
|
>
|
||||||
|
<span className="material-symbols-outlined">light_mode</span>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
className={themeName === 'dark' ? 'active' : ''}
|
className={themeName === 'dark' ? 'active' : ''}
|
||||||
onClick={() => setThemeName('dark')}
|
onClick={() => setThemeName('dark')}
|
||||||
><span className="material-symbols-outlined">dark_mode</span></button>
|
>
|
||||||
|
<span className="material-symbols-outlined">dark_mode</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ThemeSwitch;
|
export default ThemeSwitch;
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ export const cssStringToTableArray = (cssString, withInclude = false) => {
|
||||||
)};`;
|
)};`;
|
||||||
})
|
})
|
||||||
.join('\n');
|
.join('\n');
|
||||||
return withInclude
|
return withInclude ?
|
||||||
? [className, className, properties]
|
[className, className, properties]
|
||||||
: [className, properties];
|
: [className, properties];
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -33,7 +33,7 @@ export const scssVariablesToTableArray = (scssString) => {
|
||||||
export const extractCssColourVariables = (cssString) => {
|
export const extractCssColourVariables = (cssString) => {
|
||||||
const variableRegexp = /(--[a-zA-Z][a-zA-Z0-9-]+):\s*(.+);/g;
|
const variableRegexp = /(--[a-zA-Z][a-zA-Z0-9-]+):\s*(.+);/g;
|
||||||
const cssVariables = [...cssString.matchAll(variableRegexp)].map(
|
const cssVariables = [...cssString.matchAll(variableRegexp)].map(
|
||||||
([all, g1, g2]) => [g2, g1]
|
([_, g1, g2]) => [g2, g1]
|
||||||
);
|
);
|
||||||
const colours = {};
|
const colours = {};
|
||||||
for (const variable of cssVariables) {
|
for (const variable of cssVariables) {
|
||||||
|
|
|
||||||
12
src/globals.d.ts
vendored
12
src/globals.d.ts
vendored
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
interface ChartbeatConfig {
|
interface ChartbeatConfig {
|
||||||
uid?: number;
|
uid?: number;
|
||||||
domain?: string;
|
domain?: string;
|
||||||
|
|
@ -9,18 +10,17 @@ interface ChartbeatConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
interface Window {
|
interface Window {
|
||||||
/** Google analytics dataLayer */
|
/** Google analytics dataLayer */
|
||||||
dataLayer: Record<string, any>,
|
dataLayer: Record<string, any>;
|
||||||
/** Chartbeat config */
|
/** Chartbeat config */
|
||||||
_sf_async_config: ChartbeatConfig,
|
_sf_async_config: ChartbeatConfig;
|
||||||
/** Chartbeat method */
|
/** Chartbeat method */
|
||||||
pSUPERFLY: {
|
pSUPERFLY: {
|
||||||
virtualPage: (config: { path: string, title: string }) => void,
|
virtualPage: (config: { path: string; title: string }) => void;
|
||||||
},
|
};
|
||||||
/** Graphics ads */
|
/** Graphics ads */
|
||||||
graphicsAdQueue: any[],
|
graphicsAdQueue: any[];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ export { default as resizeObserver } from './actions/resizeObserver/index.js';
|
||||||
// Components
|
// Components
|
||||||
export {
|
export {
|
||||||
default as Analytics,
|
default as Analytics,
|
||||||
registerPageview
|
registerPageview,
|
||||||
} from './components/Analytics/Analytics.svelte';
|
} from './components/Analytics/Analytics.svelte';
|
||||||
export { default as Article } from './components/Article/Article.svelte';
|
export { default as Article } from './components/Article/Article.svelte';
|
||||||
export { default as AdScripts } from './components/AdSlot/AdScripts.svelte';
|
export { default as AdScripts } from './components/AdSlot/AdScripts.svelte';
|
||||||
|
|
@ -45,11 +45,7 @@ export { default as SiteHeadline } from './components/SiteHeadline/SiteHeadline.
|
||||||
export { default as Spinner } from './components/Spinner/Spinner.svelte';
|
export { default as Spinner } from './components/Spinner/Spinner.svelte';
|
||||||
export { default as SponsorshipAd } from './components/AdSlot/SponsorshipAd.svelte';
|
export { default as SponsorshipAd } from './components/AdSlot/SponsorshipAd.svelte';
|
||||||
export { default as Table } from './components/Table/Table.svelte';
|
export { default as Table } from './components/Table/Table.svelte';
|
||||||
export {
|
export { default as Theme, themes } from './components/Theme/Theme.svelte';
|
||||||
default as Theme,
|
|
||||||
// @ts-ignore
|
|
||||||
themes
|
|
||||||
} from './components/Theme/Theme.svelte';
|
|
||||||
export { default as ToolsHeader } from './components/ToolsHeader/ToolsHeader.svelte';
|
export { default as ToolsHeader } from './components/ToolsHeader/ToolsHeader.svelte';
|
||||||
export { default as Video } from './components/Video/Video.svelte';
|
export { default as Video } from './components/Video/Video.svelte';
|
||||||
export { default as Visible } from './components/Visible/Visible.svelte';
|
export { default as Visible } from './components/Visible/Visible.svelte';
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "Bundler",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"checkJs": true,
|
"checkJs": true,
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,7 @@ const config = defineConfig({
|
||||||
$docs: './src/docs',
|
$docs: './src/docs',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [svelte({})],
|
||||||
svelte({}),
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue