Repository: codeAdrian/modern-fluid-typography-editor Branch: develop Commit: 6e1eefa0f0b1 Files: 79 Total size: 170.5 KB Directory structure: gitextract_d9euyxbe/ ├── .eslintrc.cjs ├── .gitignore ├── .prettierrc ├── LICENSE.md ├── README.md ├── package.json ├── postcss.config.cjs ├── src/ │ ├── app.html │ ├── components/ │ │ ├── Footer.svelte │ │ ├── Header.svelte │ │ ├── InputWithRange.svelte │ │ ├── Legend.svelte │ │ ├── LineChart.svelte │ │ ├── Message.svelte │ │ ├── ShareButton.svelte │ │ ├── Snippet.svelte │ │ └── Stats.svelte │ ├── global.d.ts │ ├── modules/ │ │ ├── code/ │ │ │ └── Section.svelte │ │ ├── form/ │ │ │ ├── Form.svelte │ │ │ └── store.ts │ │ ├── graph/ │ │ │ ├── Graph.svelte │ │ │ ├── consts.ts │ │ │ ├── customTooltip.ts │ │ │ ├── derived.ts │ │ │ ├── store.ts │ │ │ └── utils.ts │ │ ├── tabs/ │ │ │ └── Tabs.svelte │ │ └── tracker/ │ │ ├── AddValue.svelte │ │ ├── Sort.svelte │ │ ├── TableDataRow.svelte │ │ ├── Tracker.svelte │ │ ├── derived.ts │ │ ├── store.ts │ │ └── utils.ts │ ├── routes/ │ │ ├── __error.svelte │ │ ├── __layout.svelte │ │ ├── about.svelte │ │ └── index.svelte │ ├── stores/ │ │ └── currentSubtitle.ts │ ├── styles/ │ │ ├── globals.pcss │ │ ├── icons.pcss │ │ ├── media.pcss │ │ ├── normalize.pcss │ │ ├── page.pcss │ │ ├── range.pcss │ │ ├── reset-custom.pcss │ │ ├── scrollbar.pcss │ │ ├── typography.pcss │ │ └── variables.pcss │ └── utils/ │ ├── clampRange.ts │ ├── clickOutside.ts │ ├── getClampValue.ts │ ├── getShareUrl.ts │ ├── parseQueryString.ts │ ├── setToPrecision.ts │ ├── toPx.ts │ └── toRem.ts ├── static/ │ ├── browserconfig.xml │ ├── g/ │ │ └── images/ │ │ ├── editor.5a8f99a.2bb048a65192a85028ae21e277cf3ba1.avif │ │ ├── editor.668f068.2bb048a65192a85028ae21e277cf3ba1.avif │ │ ├── editor.a1d08c9.2bb048a65192a85028ae21e277cf3ba1.avif │ │ ├── editor.d9015d2.2bb048a65192a85028ae21e277cf3ba1.avif │ │ ├── graph-increase.5a8f99a.3e7989db31c3fb99059f7341810d53eb.avif │ │ ├── graph-increase.5eb441f.3e7989db31c3fb99059f7341810d53eb.avif │ │ ├── graph-increase.a1d08c9.3e7989db31c3fb99059f7341810d53eb.avif │ │ ├── graph-increase.d9015d2.3e7989db31c3fb99059f7341810d53eb.avif │ │ ├── snippet.8509b1a.63b149124717d1f23fc75f409f86c762.avif │ │ ├── snippet.a1d08c9.63b149124717d1f23fc75f409f86c762.avif │ │ ├── table.48e1f11.c30557c7f994bcd0da96c3395c69ff71.avif │ │ ├── table.5a8f99a.c30557c7f994bcd0da96c3395c69ff71.avif │ │ ├── table.a1d08c9.c30557c7f994bcd0da96c3395c69ff71.avif │ │ └── table.d9015d2.c30557c7f994bcd0da96c3395c69ff71.avif │ ├── google6e1010a8fae63903.html │ ├── robots.txt │ ├── site.webmanifest │ └── sitemap.xml ├── svelte.config.js └── tsconfig.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .eslintrc.cjs ================================================ module.exports = { root: true, parser: '@typescript-eslint/parser', extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], plugins: ['svelte3', '@typescript-eslint'], ignorePatterns: ['*.cjs'], overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], settings: { 'svelte3/typescript': () => require('typescript') }, parserOptions: { sourceType: 'module', ecmaVersion: 2019 }, env: { browser: true, es2017: true, node: true } }; ================================================ FILE: .gitignore ================================================ .DS_Store node_modules /build /.svelte-kit /package .env .env.* ================================================ FILE: .prettierrc ================================================ { "useTabs": true, "singleQuote": true, "trailingComma": "none", "printWidth": 100 } ================================================ FILE: LICENSE.md ================================================ MIT License Copyright (c) 2021 Adrian Bece Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Modern Fluid Typography Editor

drawing

- Easily create and fine-tune fluid typography values - Modern CSS with CSS `clamp` - Code snippet generation - Supports user-defined font preferences - Build with Svelte ## Setup ``` npm install ``` ## Run project ``` npm run dev ``` ## Bugs and issues? Feel free to open the issue in project's repository and contribute code! ## Support [Buy me a coffee!](https://www.buymeacoffee.com/ubnZ8GgDJ) ================================================ FILE: package.json ================================================ { "name": "modern-fluid-typography-editor", "version": "0.0.1", "scripts": { "dev": "svelte-kit dev", "build": "svelte-kit build", "package": "svelte-kit package", "preview": "svelte-kit preview", "check": "svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch", "lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .", "format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. ." }, "devDependencies": { "@sveltejs/adapter-auto": "next", "@sveltejs/kit": "next", "@typescript-eslint/eslint-plugin": "^4.31.1", "@typescript-eslint/parser": "^4.31.1", "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-svelte3": "^3.2.1", "postcss": "^8.4.4", "postcss-custom-media": "^8.0.0", "postcss-load-config": "^3.1.0", "postcss-preset-env": "^7.0.1", "prettier": "^2.4.1", "prettier-plugin-svelte": "^2.4.0", "svelte": "^3.44.0", "svelte-check": "^2.2.6", "svelte-clipboard": "^1.0.0", "svelte-preprocess": "^4.9.4", "svimg": "^1.1.0", "tslib": "^2.3.1", "typescript": "^4.4.3", "@sveltejs/adapter-vercel": "next", "cssnano": "^5.0.12" }, "type": "module", "dependencies": { "@floating-ui/dom": "^0.1.4", "chart.js": "^3.4.0", "chartjs-plugin-crosshair": "^1.2.0" } } ================================================ FILE: postcss.config.cjs ================================================ module.exports = { plugins: [ require('postcss-preset-env')({ stage: 3, features: { 'nesting-rules': true, 'custom-media-queries': { importFrom: './src/styles/media.pcss', }, }, }), require('cssnano'), ], }; ================================================ FILE: src/app.html ================================================ Modern fluid typography editor %svelte.head% %svelte.body% ================================================ FILE: src/components/Footer.svelte ================================================ ================================================ FILE: src/components/Header.svelte ================================================

Modern fluid typography editor

{#if $currentSubtitle} {$currentSubtitle} Adrian Bece {:else}   {/if}

================================================ FILE: src/components/InputWithRange.svelte ================================================
{unit}
================================================ FILE: src/components/Legend.svelte ================================================ ================================================ FILE: src/components/LineChart.svelte ================================================
================================================ FILE: src/components/Message.svelte ================================================
================================================ FILE: src/components/ShareButton.svelte ================================================ ================================================ FILE: src/components/Snippet.svelte ================================================
        

            {text}
        
    
================================================ FILE: src/components/Stats.svelte ================================================ ================================================ FILE: src/global.d.ts ================================================ /// ================================================ FILE: src/modules/code/Section.svelte ================================================ {#if $minSize >= $maxSize} Fluid snippet doesn't have any effect. Minimum size is larger than maximum size. {/if} {#if $relativeSize > -1 && $relativeSize < 1} It's recommended to set "Relative Size" to a value -1 or less or 1 and greater to support user font size preferences. {/if} ================================================ FILE: src/modules/form/Form.svelte ================================================
  • {#if $rootFontSize <= 0} Incorrect font size value. {/if}
  • {#if $minSize > $maxSize} Fluid snippet doesn't have any effect. Minimum size is larger than maximum size. {/if}
  • {#if $minSize > $maxSize} Fluid snippet doesn't have any effect. Minimum size is larger than maximum size. {/if}
  • {#if $fluidSize === 0} Fluid snippet doesn't have any effect. Fluid size should be above 0 {/if}
  • {#if $relativeSize > -1 && $relativeSize < 1} Value should be -1 and less or 1 and more to support user font size settings. {/if}
================================================ FILE: src/modules/form/store.ts ================================================ import { getClampValue } from 'src/utils/getClampValue'; import { getShareUrl } from 'src/utils/getShareUrl'; import { parseQueryString } from 'src/utils/parseQueryString'; import { toPx } from 'src/utils/toPx'; import { toRem } from 'src/utils/toRem'; import { derived, writable } from 'svelte/store'; const rootFontSize = writable(parseQueryString('rootFontSize') || 16); const minSize = writable(parseQueryString('minSize') || 24); const maxSize = writable(parseQueryString('maxSize') || 36); const fluidSize = writable(parseQueryString('fluidSize') || 2); const relativeSize = writable(parseQueryString('relativeSize') || 1); const minSizeRem = derived([minSize, rootFontSize], toRem); const maxSizeRem = derived([maxSize, rootFontSize], toRem); const relativeSizePx = derived([relativeSize, rootFontSize], toPx); const clampValue = derived([minSizeRem, fluidSize, relativeSize, maxSizeRem], getClampValue); const shareUrl = derived([rootFontSize, minSize, fluidSize, relativeSize, maxSize], getShareUrl); export { rootFontSize, minSize, maxSize, fluidSize, relativeSize, minSizeRem, maxSizeRem, clampValue, relativeSizePx, shareUrl }; ================================================ FILE: src/modules/graph/Graph.svelte ================================================ ================================================ FILE: src/modules/graph/consts.ts ================================================ import type { ChartConfiguration } from 'chart.js'; import { externalTooltipHandler } from './customTooltip'; export const CHART_OPTIONS: ChartConfiguration<'line'> = { type: 'scatter', data: { datasets: [ { borderColor: 'hsl(169, 82%, 69%)', tension: 0, showLine: true, lineTension: 0, interpolate: true, pointRadius: 0, borderWidth: 4, borderJoinStyle: 'round', fill: true } ] }, options: { animation: false, responsive: true, plugins: { legend: { display: false }, crosshair: { line: { color: 'hsl(182, 29%, 51%)', width: 2 }, zoom: { enabled: false }, sync: { enabled: false } }, tooltip: { enabled: false, mode: 'interpolate', intersect: false, yAlign: 'bottom', external: externalTooltipHandler, callbacks: { title: function (a) { const { x, y } = a[0].element; return `${Math.round(y)}px at ${Math.round(x)}px`; }, label: () => null } } }, scales: { x: { min: 300, suggestedMax: 1024, type: 'linear', title: { text: 'Viewport width (pixels)', display: true, color: 'hsl(215, 22%, 85%)', font: { size: 16, family: 'Ubuntu' } }, grid: { drawTicks: false, lineWidth: 2, borderWidth: 2, color: 'hsla(182, 29%, 51%, 0.25)' }, ticks: { stepSize: 1, count: 12, precision: 0, padding: 10, color: (c) => c['tick']['value'] <= 1400 ? 'hsla(215, 22%, 85%, 0.8)' : 'hsla(215, 22%, 85%, 0.5)', font: { size: 14 } } }, y: { min: 0, suggestedMin: 16, suggestedMax: 48, title: { text: 'Fluid size (pixels)', display: true, color: 'hsl(215, 22%, 85%)', font: { size: 16, family: 'Ubuntu' }, padding: 8 }, grid: { drawTicks: false, lineWidth: 2, borderWidth: 2, color: 'hsla(182, 29%, 51%, 0.25)' }, ticks: { padding: 8, font: { size: 14 }, color: 'hsla(215, 22%, 85%, 0.6)', callback: function (value, index) { return index === 0 ? '' : value; } } } } } }; ================================================ FILE: src/modules/graph/customTooltip.ts ================================================ export const getOrCreateTooltip = (chart) => { let tooltipEl = chart.canvas.parentNode.querySelector('#chart-tooltip'); if (!tooltipEl) { tooltipEl = document.createElement('div'); tooltipEl.id = 'chart-tooltip'; tooltipEl.style.pointerEvents = 'none'; tooltipEl.style.position = 'absolute'; tooltipEl.style.top = '0px'; tooltipEl.style.border = '2px solid var(--color-secondary-tint)'; tooltipEl.style.color = 'var(--color-secondary)'; tooltipEl.style.background = 'var(--color-secondary-faded)'; tooltipEl.style.fontWeight = 'var(--font-weight-bold)'; tooltipEl.style.fontSize = 'var(--font-size-small)'; tooltipEl.style.padding = 'var(--spacing-n2)'; tooltipEl.style.lineHeight = '1'; tooltipEl.style.textAlign = 'center'; const span = document.createElement('span'); tooltipEl.appendChild(span); chart.canvas.parentNode.appendChild(tooltipEl); } return tooltipEl; }; export const externalTooltipHandler = (context) => { const { chart, tooltip } = context; const tooltipEl = getOrCreateTooltip(chart, tooltip); tooltipEl.style.opacity = tooltip.opacity === 0 ? 0 : 1; if (tooltip.body) { const titleLines = tooltip.title || []; let text; titleLines.forEach((title) => { text = document.createTextNode(title); }); const tableRoot = tooltipEl.querySelector('span'); while (tableRoot.firstChild) { tableRoot.firstChild.remove(); } tableRoot.appendChild(text); } const { offsetLeft: positionX, offsetTop: positionY } = chart.canvas; const isLeft = tooltip.caretX < chart.width / 2; if (isLeft) { tooltipEl.style.transform = 'translate3d(-1px,calc(-50% + 3px),0)'; tooltipEl.style.borderRadius = '4px 4px 4px 0'; } else { tooltipEl.style.transform = 'translate3d(calc(-100% + 1px),calc(-50% + 3px),0)'; tooltipEl.style.borderRadius = '4px 4px 0 4px'; } tooltipEl.style.top = '0'; tooltipEl.style.left = positionX + tooltip.caretX + 'px'; tooltipEl.style.minWidth = '20ch'; tooltipEl.style.top = positionY + 'px'; }; ================================================ FILE: src/modules/graph/derived.ts ================================================ import { derived } from 'svelte/store'; import { fluidSize, maxSize, minSize, relativeSizePx } from 'src/modules/form/store'; import { clampRange } from 'src/utils/clampRange'; export const graphChangeStart = derived( [minSize, maxSize, fluidSize, relativeSizePx], ([$minSize, $maxSize, $fluidSize, $relativeSizePx]) => { if ($minSize >= $maxSize) { return { x: 0, y: $minSize }; } return { x: Math.round((100 * ($minSize - $relativeSizePx)) / $fluidSize), y: $minSize }; } ); export const graphChangeEnd = derived( [minSize, maxSize, fluidSize, relativeSizePx], ([$minSize, $maxSize, $fluidSize, $relativeSizePx]) => { if ($minSize >= $maxSize) { return { x: 1900, y: $minSize }; } return { x: Math.round((100 * ($maxSize - $relativeSizePx)) / $fluidSize), y: $maxSize }; } ); export const graphStart = derived( [minSize, maxSize, fluidSize, relativeSizePx, graphChangeStart], ([$minSize, $maxSize, $fluidSize, $relativeSizePx, $graphChangeStart]) => { if ($minSize >= $maxSize) { return { x: 100, y: $minSize }; } const x = Math.min($graphChangeStart.x - 100, 100); return { x, y: clampRange(($fluidSize / 100) * x + $relativeSizePx, $minSize, $maxSize) }; } ); export const graphEnd = derived( [minSize, maxSize, fluidSize, relativeSizePx, graphChangeEnd], ([$minSize, $maxSize, $fluidSize, $relativeSizePx, $graphChangeEnd]) => { if ($minSize >= $maxSize) { return { x: 1400, y: $minSize }; } const x = Math.max($graphChangeEnd.x + 100, 1400); return { x, y: clampRange(($fluidSize / 100) * x + $relativeSizePx, $minSize, $maxSize) }; } ); export const graphPoints = derived( [graphStart, graphChangeStart, graphChangeEnd, graphEnd], ([$graphStart, $graphChangeStart, $graphChangeEnd, $graphEnd]) => { return [$graphStart, $graphChangeStart, $graphChangeEnd, $graphEnd].sort((a, b) => a.x - b.x); } ); ================================================ FILE: src/modules/graph/store.ts ================================================ import { writable } from 'svelte/store'; const minResolution = writable(300); const maxResolution = writable(1920); export { minResolution, maxResolution }; ================================================ FILE: src/modules/graph/utils.ts ================================================ export const getScalesConfig = (y: { min: number; max: number; grid?: any }) => { y.min = x.min + 10; y.max = x.max + 10; y.grid = { display: false }; return { scales: { x: { min: 200, max: 2000 }, y } }; }; ================================================ FILE: src/modules/tabs/Tabs.svelte ================================================
================================================ FILE: src/modules/tracker/AddValue.svelte ================================================
px
================================================ FILE: src/modules/tracker/Sort.svelte ================================================ ================================================ FILE: src/modules/tracker/TableDataRow.svelte ================================================ {width} px {sizeValue} px {setToPrecision(sizeValue / $rootFontSize, 3)}rem ================================================ FILE: src/modules/tracker/Tracker.svelte ================================================
9} class="tracker-wrapper"> {#key `${isAsc ? 'asc' : 'desc'}`} {#each items as item} {/each} {/key}
Screen width Fluid size value
================================================ FILE: src/modules/tracker/derived.ts ================================================ import { derived } from 'svelte/store'; import { trackers } from './store'; export const trackersAsc = derived([trackers], ([$trackers]) => { const sorted = $trackers.sort((a, b) => a.width - b.width); return sorted; }); export const trackersDesc = derived([trackersAsc], ([$trackersAsc]) => { return [...$trackersAsc].reverse(); }); ================================================ FILE: src/modules/tracker/store.ts ================================================ import { writable } from 'svelte/store'; export const trackers = writable([ { id: 10, width: 300 }, { id: 11, width: 360 }, { id: 12, width: 480 }, { id: 13, width: 568 }, { id: 14, width: 768 }, { id: 15, width: 920 }, { id: 16, width: 1024 }, { id: 17, width: 1280 }, { id: 18, width: 1440 } ]); ================================================ FILE: src/modules/tracker/utils.ts ================================================ import { clampRange } from 'src/utils/clampRange'; export const generateUniqueId = () => Math.floor(Math.random() * Date.now()); export const calculateSizeValue = (screenSize, fluidSize, relativeSizePx, minValue, maxValue) => { if (minValue >= maxValue) return minValue; return clampRange( Math.round((fluidSize / 100) * screenSize + relativeSizePx), minValue, maxValue ); }; ================================================ FILE: src/routes/__error.svelte ================================================

Game over.
Or is it?

Start again
================================================ FILE: src/routes/__layout.svelte ================================================