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