Add LoremIpsum, Update tools

This commit is contained in:
MrLetsplay 2023-10-27 17:37:14 +02:00
parent 1362386fdc
commit deda433535
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
10 changed files with 138 additions and 57 deletions

View File

@ -1,16 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="shortcut icon" type="image/ico" href="/src/assets/favicon.ico" />
<title>Solid App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="/src/index.tsx" type="module"></script>
</body>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="shortcut icon" type="image/svg" href="/src/assets/favicon.svg" />
<title>(Possibly) Useful Tools</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="/src/index.tsx" type="module"></script>
</body>
</html>

View File

@ -7,7 +7,7 @@ const Navigation: Component = () => {
<A href='/strlen'>String Length</A>
<A href='/strrev'>String Reverse</A>
<A href='/strnoise'>String Noise</A>
{/* Tools: string length, string reverse, string noise */}
<A href='/loremipsum'>Lorem Ipsum</A>
</>
);
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

1
src/assets/favicon.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#dddddd"><path d="M22.7,19L13.6,9.9C14.5,7.6 14,4.9 12.1,3C10.1,1 7.1,0.6 4.7,1.7L9,6L6,9L1.6,4.7C0.4,7.1 0.9,10.1 2.9,12.1C4.8,14 7.5,14.5 9.8,13.6L18.9,22.7C19.3,23.1 19.9,23.1 20.3,22.7L22.6,20.4C23.1,20 23.1,19.3 22.7,19Z" /></svg>

After

Width:  |  Height:  |  Size: 302 B

View File

@ -7,6 +7,7 @@ import { Route, Router, Routes, hashIntegration } from '@solidjs/router';
import StrLen from './pages/StrLen';
import StrRev from './pages/StrRev';
import StrNoise from './pages/StrNoise';
import LoremIpsum from './pages/LoremIpsum';
const root = document.getElementById('root');
@ -23,6 +24,7 @@ render(() => (
<Route path="/strlen" component={StrLen} />
<Route path="/strrev" component={StrRev} />
<Route path="/strnoise" component={StrNoise} />
<Route path="/loremipsum" component={LoremIpsum} />
</Routes>
</Router>
), root!);

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 166 155.3"><path d="M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z" fill="#76b3e1"/><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="27.5" y1="3" x2="152" y2="63.5"><stop offset=".1" stop-color="#76b3e1"/><stop offset=".3" stop-color="#dcf2fd"/><stop offset="1" stop-color="#76b3e1"/></linearGradient><path d="M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z" opacity=".3" fill="url(#a)"/><path d="M52 35l-4 1c-17 5-22 21-13 35 10 13 31 20 48 15l62-21S92 26 52 35z" fill="#518ac8"/><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="95.8" y1="32.6" x2="74" y2="105.2"><stop offset="0" stop-color="#76b3e1"/><stop offset=".5" stop-color="#4377bb"/><stop offset="1" stop-color="#1f3b77"/></linearGradient><path d="M52 35l-4 1c-17 5-22 21-13 35 10 13 31 20 48 15l62-21S92 26 52 35z" opacity=".3" fill="url(#b)"/><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="18.4" y1="64.2" x2="144.3" y2="149.8"><stop offset="0" stop-color="#315aa9"/><stop offset=".5" stop-color="#518ac8"/><stop offset="1" stop-color="#315aa9"/></linearGradient><path d="M134 80a45 45 0 00-48-15L24 85 4 120l112 19 20-36c4-7 3-15-2-23z" fill="url(#c)"/><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="75.2" y1="74.5" x2="24.4" y2="260.8"><stop offset="0" stop-color="#4377bb"/><stop offset=".5" stop-color="#1a336b"/><stop offset="1" stop-color="#1a336b"/></linearGradient><path d="M114 115a45 45 0 00-48-15L4 120s53 40 94 30l3-1c17-5 23-21 13-34z" fill="url(#d)"/></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

65
src/pages/LoremIpsum.tsx Normal file
View File

@ -0,0 +1,65 @@
import { Component, createEffect, createSignal, on } from 'solid-js';
import styles from './Page.module.css';
import Navigation from '../Navigation';
import { createRandomGenerator } from '../random';
const LOREM_IPSUM = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vestibulum velit nec vehicula viverra. Cras fermentum neque id faucibus mollis. Maecenas malesuada tellus vitae turpis maximus tempus. Donec sit amet ipsum lorem. Fusce vel eleifend elit, vel maximus mauris. Nam sed erat euismod, consectetur lorem vitae, lobortis est. Cras convallis tempus dapibus. Praesent convallis ac dui quis ultrices. Integer porta semper purus id placerat. Aliquam sed enim ut lorem dapibus luctus. Nulla ultrices ullamcorper ex in cursus. Maecenas augue libero, rhoncus ac porttitor id, dignissim at velit. Praesent pellentesque nec augue sit amet luctus. Nam finibus ultricies ligula ac pharetra. Aliquam pretium congue diam fringilla fermentum. Sed non lorem vel velit feugiat dignissim. Phasellus ultricies, eros at suscipit condimentum, dui tellus pretium libero, sed consectetur sapien mi ut ipsum. Ut mollis convallis ex sed aliquam. Sed sed lacus eu lectus ultrices ultrices. Quisque tincidunt leo non risus vehicula, eu congue ipsum molestie. Suspendisse laoreet ac mauris a fermentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum varius sem nec sagittis viverra. Mauris facilisis neque turpis, quis ultricies nisl mollis eget. Donec et leo id lectus vulputate maximus. Nullam bibendum ex massa, non tempus tortor molestie ac. Sed euismod libero libero, et consectetur sapien sagittis at. Etiam posuere, erat eu accumsan tempor, urna urna tempus purus, eu commodo odio erat nec tortor. Proin hendrerit, elit in pharetra efficitur, enim nunc facilisis felis, nec faucibus elit sem ut est. Morbi fermentum, arcu et venenatis aliquam, ex enim luctus purus, in elementum mauris turpis molestie ante. In hac habitasse platea dictumst. Curabitur sit amet ante arcu. Quisque ut fringilla ipsum. Fusce aliquet lorem quis sem maximus ultricies. Sed ex magna, euismod non faucibus at, maximus viverra risus. Curabitur eu nulla viverra, congue nisl eu, consequat odio. Mauris a posuere augue. Morbi lectus sem, iaculis sed orci sed, mollis pharetra nisl. Donec dolor felis, dictum id nibh quis, fringilla vulputate tellus. Suspendisse non nisi blandit, placerat tellus at, laoreet magna. Nam dignissim sollicitudin feugiat. Sed mattis diam quis erat gravida, quis auctor tellus varius. Maecenas commodo consequat interdum. Aenean pulvinar dictum tempus. Praesent pulvinar nibh ut auctor vestibulum. Morbi hendrerit nulla enim, ac sodales massa ornare id. Aenean quis pharetra nunc. Praesent sed hendrerit ex. Vestibulum faucibus sapien et tellus cursus, eget auctor lorem venenatis. Vestibulum porttitor turpis eget neque pretium, imperdiet sagittis quam posuere. Nullam cursus semper sodales. Nunc ante ante, volutpat vel felis lobortis, congue cursus purus. In sit amet felis ut felis fringilla imperdiet. In hac habitasse platea dictumst.';
const LOREM_WORDS = LOREM_IPSUM.replaceAll(/[,.]/g, '').split(' ').filter(i => i != '').map(w => w.toLowerCase());
const LoremIpsum: Component = () => {
const [output, setOutput] = createSignal('');
const [length, setLength] = createSignal(300);
const [seed, setSeed] = createSignal('0');
createEffect(on([length, seed], () => {
const generator = createRandomGenerator(seed());
let str = '';
let wordsSinceLastPeriod = 0;
while (str.trim().length < length() - 1) {
let word = LOREM_WORDS[Math.floor(generator() * LOREM_WORDS.length)];
if (wordsSinceLastPeriod == 0) {
word = word.charAt(0).toUpperCase() + word.substring(1);
}
str += word + ' ';
wordsSinceLastPeriod++;
console.log(wordsSinceLastPeriod);
if (generator() < wordsSinceLastPeriod * wordsSinceLastPeriod * 0.002) {
str = str.trim() + '. ';
wordsSinceLastPeriod = 0;
}
}
str = str.trim() + '.';
setOutput(str);
}));
let outputField: HTMLTextAreaElement | undefined;
const copy = async () => {
outputField!.select();
document.execCommand('copy');
};
return (
<div class={styles.page}>
<h1>String Length</h1>
<h2>Input</h2>
<h3>Length</h3>
<input type={'range'} min={0} max={5000} value={length()} oninput={e => setLength(parseInt(e.currentTarget.value))} />
<input type={'number'} min={0} value={length()} oninput={e => setLength(parseInt(e.currentTarget.value))} />
<h3>Seed</h3>
<input min={0} max={100} value={seed()} onInput={e => setSeed(e.currentTarget.value)} />
<h2>Output</h2>
<textarea value={output()} ref={outputField} />
<button onclick={copy}>Copy Output</button>
<h2>All Tools</h2>
<Navigation />
</div>
);
};
export default LoremIpsum;

View File

@ -4,19 +4,22 @@ import styles from './Page.module.css';
import { JSX } from 'solid-js';
import Navigation from '../Navigation';
function copy(field: HTMLInputElement) {
field.select();
document.execCommand('copy');
}
const StrLen: Component = () => {
const [output, setOutput] = createSignal(0);
const [outputWords, setOutputWords] = createSignal(0);
const onChange: JSX.EventHandler<HTMLTextAreaElement, InputEvent> = (event) => {
setOutput(event.currentTarget.value.length);
setOutputWords(event.currentTarget.value.split(' ').filter(i => i != '').length);
};
let outputField: HTMLInputElement | undefined;
const copy = async () => {
outputField!.select();
document.execCommand('copy');
};
let outputWordsField: HTMLInputElement | undefined;
return (
<div class={styles.page}>
@ -24,8 +27,12 @@ const StrLen: Component = () => {
<h2>Input</h2>
<textarea oninput={onChange} />
<h2>Output</h2>
<h3>Length</h3>
<input value={output()} ref={outputField} />
<button onclick={copy}>Copy Output</button>
<button onclick={() => copy(outputField!)}>Copy Output</button>
<h3>Word Count</h3>
<input value={outputWords()} ref={outputWordsField} />
<button onclick={() => copy(outputWordsField!)}>Copy Output</button>
<h2>All Tools</h2>
<Navigation />
</div>

View File

@ -2,41 +2,10 @@ import { Component, createEffect, createSignal, on } from 'solid-js';
import styles from './Page.module.css';
import Navigation from '../Navigation';
import { createRandomGenerator } from '../random';
const SYMBOLS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 _#+';
function murmurHash3(string: string) {
let i = 0, hash: number;
for (hash = 1779033703 ^ string.length; i < string.length; i++) {
const bitwise_xor_from_character = hash ^ string.charCodeAt(i);
hash = Math.imul(bitwise_xor_from_character, 3432918353);
hash = hash << 13 | hash >>> 19;
}
return () => {
// Return the hash that you can use as a seed
hash = Math.imul(hash ^ (hash >>> 16), 2246822507);
hash = Math.imul(hash ^ (hash >>> 13), 3266489909);
return (hash ^= hash >>> 16) >>> 0;
};
}
function simpleFastCounter32(seed_1: number, seed_2: number, seed_3: number, seed_4: number) {
return () => {
seed_1 >>>= 0;
seed_2 >>>= 0;
seed_3 >>>= 0;
seed_4 >>>= 0;
let cast32 = (seed_1 + seed_2) | 0;
seed_1 = seed_2 ^ seed_2 >>> 9;
seed_2 = seed_3 + (seed_3 << 3) | 0;
seed_3 = (seed_3 << 21 | seed_3 >>> 11);
seed_4 = seed_4 + 1 | 0;
cast32 = cast32 + seed_4 | 0;
seed_3 = seed_3 + cast32 | 0;
return (cast32 >>> 0) / 4294967296;
};
}
const StrNoise: Component = () => {
const [output, setOutput] = createSignal('');
const [input, setInput] = createSignal('');
@ -48,8 +17,7 @@ const StrNoise: Component = () => {
const [swapAdjacent, setSwapAdjancent] = createSignal(false);
createEffect(on([input, noiseLevel, seed, shuffle, randomize, swapAdjacent], () => {
const s = murmurHash3(seed());
const generator = simpleFastCounter32(s(), s(), s(), s());
const generator = createRandomGenerator(seed());
const types = [];
if (shuffle()) types.push('shuffle');
@ -88,9 +56,9 @@ const StrNoise: Component = () => {
<h1>String Noise</h1>
<h2>Input</h2>
<textarea value={input()} oninput={e => setInput(e.currentTarget.value)} />
<h2>Noise Level</h2>
<h3>Noise Level</h3>
<input type={'range'} min={0} max={100} value={noiseLevel()} oninput={e => setNoiseLevel(parseInt(e.currentTarget.value))} />
<h2>Noise Types</h2>
<h3>Noise Types</h3>
<div class={styles.checkbox}>
<input type={'checkbox'} checked={shuffle()} onchange={e => setShuffle(e.currentTarget.checked)} />
<label>Shuffle</label>
@ -103,7 +71,7 @@ const StrNoise: Component = () => {
<input type={'checkbox'} checked={swapAdjacent()} onchange={e => setSwapAdjancent(e.currentTarget.checked)} />
<label>Swap Adjacent</label>
</div>
<h2>Seed</h2>
<h3>Seed</h3>
<input min={0} max={100} value={seed()} onInput={e => setSeed(e.currentTarget.value)} />
<h2>Output</h2>
<input value={output()} ref={outputField} />

36
src/random.ts Normal file
View File

@ -0,0 +1,36 @@
function murmurHash3(string: string) {
let i = 0, hash: number;
for (hash = 1779033703 ^ string.length; i < string.length; i++) {
const bitwise_xor_from_character = hash ^ string.charCodeAt(i);
hash = Math.imul(bitwise_xor_from_character, 3432918353);
hash = hash << 13 | hash >>> 19;
}
return () => {
// Return the hash that you can use as a seed
hash = Math.imul(hash ^ (hash >>> 16), 2246822507);
hash = Math.imul(hash ^ (hash >>> 13), 3266489909);
return (hash ^= hash >>> 16) >>> 0;
};
}
function simpleFastCounter32(seed_1: number, seed_2: number, seed_3: number, seed_4: number) {
return () => {
seed_1 >>>= 0;
seed_2 >>>= 0;
seed_3 >>>= 0;
seed_4 >>>= 0;
let cast32 = (seed_1 + seed_2) | 0;
seed_1 = seed_2 ^ seed_2 >>> 9;
seed_2 = seed_3 + (seed_3 << 3) | 0;
seed_3 = (seed_3 << 21 | seed_3 >>> 11);
seed_4 = seed_4 + 1 | 0;
cast32 = cast32 + seed_4 | 0;
seed_3 = seed_3 + cast32 | 0;
return (cast32 >>> 0) / 4294967296;
};
}
export function createRandomGenerator(seed: string) {
const seedGenerator = murmurHash3(seed);
return simpleFastCounter32(seedGenerator(), seedGenerator(), seedGenerator(), seedGenerator());
}