this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

replace masonry library with masonic, more defer

uwx 27192fb6 e9ba825a

+217 -45
+2
package.json
··· 17 17 "dependencies": { 18 18 "@tippyjs/react": "^4.2.6", 19 19 "lz-string": "^1.5.0", 20 + "masonic": "^4.1.0", 20 21 "preact": "^10.28.3", 21 22 "react-masonry-css": "^1.0.16", 23 + "react-responsive-masonry": "^2.7.1", 22 24 "tippy.js": "^6.3.7" 23 25 } 24 26 }
+133
pnpm-lock.yaml
··· 14 14 lz-string: 15 15 specifier: ^1.5.0 16 16 version: 1.5.0 17 + masonic: 18 + specifier: ^4.1.0 19 + version: 4.1.0(react@19.2.4) 17 20 preact: 18 21 specifier: ^10.28.3 19 22 version: 10.28.3 20 23 react-masonry-css: 21 24 specifier: ^1.0.16 22 25 version: 1.0.16(react@19.2.4) 26 + react-responsive-masonry: 27 + specifier: ^2.7.1 28 + version: 2.7.1 23 29 tippy.js: 24 30 specifier: ^6.3.7 25 31 version: 6.3.7 ··· 33 39 34 40 packages: 35 41 42 + '@essentials/memoize-one@1.1.0': 43 + resolution: {integrity: sha512-HMkuIkKNe0EWSUpZhlaq9+5Yp47YhrMhxLMnXTRnEyE5N4xKLspAvMGjUFdi794VnEF1EcOZFS8rdROeujrgag==} 44 + 45 + '@essentials/one-key-map@1.2.0': 46 + resolution: {integrity: sha512-C2H7zHVcsoipDv4VKY5uUcv5ilsK+uEgEj+WeOdN5oz/Qj1/OZIzCdle90gDzj0xnGQrmZ9qDujwD7AkBb5k9A==} 47 + 48 + '@essentials/raf@1.2.0': 49 + resolution: {integrity: sha512-AWJvpprE2o7ATMb7HBYMVUVmPJBCt2wZp2rY7d+rAcNSMvzLbDepy9KFeqqrPZh+s9aIpbw1LgmuAW7kuRFgrQ==} 50 + 51 + '@essentials/request-timeout@1.3.0': 52 + resolution: {integrity: sha512-lKZPhKScNFnR1MBnk4+sxshk46fpvdN+Uh1LlKWFO5g1ocuz4EcknNIL7tm/rsCAs/+xMWiBTwbDUvm+pDNlXw==} 53 + 36 54 '@popperjs/core@2.11.8': 37 55 resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} 38 56 57 + '@react-hook/debounce@3.0.0': 58 + resolution: {integrity: sha512-ir/kPrSfAzY12Gre0sOHkZ2rkEmM4fS5M5zFxCi4BnCeXh2nvx9Ujd+U4IGpKCuPA+EQD0pg1eK2NGLvfWejag==} 59 + peerDependencies: 60 + react: '>=16.8' 61 + 62 + '@react-hook/event@1.2.6': 63 + resolution: {integrity: sha512-JUL5IluaOdn5w5Afpe/puPa1rj8X6udMlQ9dt4hvMuKmTrBS1Ya6sb4sVgvfe2eU4yDuOfAhik8xhbcCekbg9Q==} 64 + peerDependencies: 65 + react: '>=16.8' 66 + 67 + '@react-hook/latest@1.0.3': 68 + resolution: {integrity: sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg==} 69 + peerDependencies: 70 + react: '>=16.8' 71 + 72 + '@react-hook/passive-layout-effect@1.2.1': 73 + resolution: {integrity: sha512-IwEphTD75liO8g+6taS+4oqz+nnroocNfWVHWz7j+N+ZO2vYrc6PV1q7GQhuahL0IOR7JccFTsFKQ/mb6iZWAg==} 74 + peerDependencies: 75 + react: '>=16.8' 76 + 77 + '@react-hook/throttle@2.2.0': 78 + resolution: {integrity: sha512-LJ5eg+yMV8lXtqK3lR+OtOZ2WH/EfWvuiEEu0M3bhR7dZRfTyEJKxH1oK9uyBxiXPtWXiQggWbZirMCXam51tg==} 79 + peerDependencies: 80 + react: '>=16.8' 81 + 82 + '@react-hook/window-scroll@1.3.0': 83 + resolution: {integrity: sha512-LdYnCL22pFI+LTs85Fi2OQHSKWkzIuHFgv8lA+wwuaPxLOEhWR5bzJ21iygUH9X4meeLVRZKEbfpYi3OWWD4GQ==} 84 + peerDependencies: 85 + react: '>=16.8' 86 + 87 + '@react-hook/window-size@3.1.1': 88 + resolution: {integrity: sha512-yWnVS5LKnOUIrEsI44oz3bIIUYqflamPL27n+k/PC//PsX/YeWBky09oPeAoc9As6jSH16Wgo8plI+ECZaHk3g==} 89 + peerDependencies: 90 + react: '>=16.8' 91 + 39 92 '@tippyjs/react@4.2.6': 40 93 resolution: {integrity: sha512-91RicDR+H7oDSyPycI13q3b7o4O60wa2oRbjlz2fyRLmHImc4vyDwuUP8NtZaN0VARJY5hybvDYrFzhY9+Lbyw==} 41 94 peerDependencies: ··· 55 108 resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} 56 109 hasBin: true 57 110 111 + masonic@4.1.0: 112 + resolution: {integrity: sha512-3RNbAG5qLve7qNtGp1UM/u7vI39jO73ZFHDBAg3xl8AVh7A6Ikx7I7mBeC0NY0h1r1jJn2Wqeol1QMa09MQbyQ==} 113 + peerDependencies: 114 + react: '>=16.8' 115 + 58 116 preact@10.28.3: 59 117 resolution: {integrity: sha512-tCmoRkPQLpBeWzpmbhryairGnhW9tKV6c6gr/w+RhoRoKEJwsjzipwp//1oCpGPOchvSLaAPlpcJi9MwMmoPyA==} 60 118 119 + raf-schd@4.0.3: 120 + resolution: {integrity: sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==} 121 + 61 122 react-dom@19.2.4: 62 123 resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} 63 124 peerDependencies: ··· 68 129 peerDependencies: 69 130 react: '>=16.0.0' 70 131 132 + react-responsive-masonry@2.7.1: 133 + resolution: {integrity: sha512-Q+u+nOH87PzjqGFd2PgTcmLpHPZnCmUPREHYoNBc8dwJv6fi51p9U6hqwG8g/T8MN86HrFjrU+uQU6yvETU7cA==} 134 + 71 135 react@19.2.4: 72 136 resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} 73 137 engines: {node: '>=0.10.0'} ··· 77 141 78 142 tippy.js@6.3.7: 79 143 resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} 144 + 145 + trie-memoize@1.2.0: 146 + resolution: {integrity: sha512-hEDLVEP1FCgaRtt0oZDJdz2lK9uK7WlB7ASswt9U9cqruSNueVigtRGxI97hevKlViqhAcRgNgzuY/m8FCCMcg==} 80 147 81 148 typescript@6.0.0-dev.20260213: 82 149 resolution: {integrity: sha512-zGIJwsX3OEsKIoEvXJzHRpt58fk370/T1N0GsSECAbcTlrsfUe2QQFbdKyKT3HyG2hFFyZg+Q0zYn6VLeahafg==} ··· 85 152 86 153 snapshots: 87 154 155 + '@essentials/memoize-one@1.1.0': {} 156 + 157 + '@essentials/one-key-map@1.2.0': {} 158 + 159 + '@essentials/raf@1.2.0': {} 160 + 161 + '@essentials/request-timeout@1.3.0': 162 + dependencies: 163 + '@essentials/raf': 1.2.0 164 + 88 165 '@popperjs/core@2.11.8': {} 89 166 167 + '@react-hook/debounce@3.0.0(react@19.2.4)': 168 + dependencies: 169 + '@react-hook/latest': 1.0.3(react@19.2.4) 170 + react: 19.2.4 171 + 172 + '@react-hook/event@1.2.6(react@19.2.4)': 173 + dependencies: 174 + react: 19.2.4 175 + 176 + '@react-hook/latest@1.0.3(react@19.2.4)': 177 + dependencies: 178 + react: 19.2.4 179 + 180 + '@react-hook/passive-layout-effect@1.2.1(react@19.2.4)': 181 + dependencies: 182 + react: 19.2.4 183 + 184 + '@react-hook/throttle@2.2.0(react@19.2.4)': 185 + dependencies: 186 + '@react-hook/latest': 1.0.3(react@19.2.4) 187 + react: 19.2.4 188 + 189 + '@react-hook/window-scroll@1.3.0(react@19.2.4)': 190 + dependencies: 191 + '@react-hook/event': 1.2.6(react@19.2.4) 192 + '@react-hook/throttle': 2.2.0(react@19.2.4) 193 + react: 19.2.4 194 + 195 + '@react-hook/window-size@3.1.1(react@19.2.4)': 196 + dependencies: 197 + '@react-hook/debounce': 3.0.0(react@19.2.4) 198 + '@react-hook/event': 1.2.6(react@19.2.4) 199 + '@react-hook/throttle': 2.2.0(react@19.2.4) 200 + react: 19.2.4 201 + 90 202 '@tippyjs/react@4.2.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': 91 203 dependencies: 92 204 react: 19.2.4 ··· 105 217 106 218 lz-string@1.5.0: {} 107 219 220 + masonic@4.1.0(react@19.2.4): 221 + dependencies: 222 + '@essentials/memoize-one': 1.1.0 223 + '@essentials/one-key-map': 1.2.0 224 + '@essentials/request-timeout': 1.3.0 225 + '@react-hook/event': 1.2.6(react@19.2.4) 226 + '@react-hook/latest': 1.0.3(react@19.2.4) 227 + '@react-hook/passive-layout-effect': 1.2.1(react@19.2.4) 228 + '@react-hook/throttle': 2.2.0(react@19.2.4) 229 + '@react-hook/window-scroll': 1.3.0(react@19.2.4) 230 + '@react-hook/window-size': 3.1.1(react@19.2.4) 231 + raf-schd: 4.0.3 232 + react: 19.2.4 233 + trie-memoize: 1.2.0 234 + 108 235 preact@10.28.3: {} 236 + 237 + raf-schd@4.0.3: {} 109 238 110 239 react-dom@19.2.4(react@19.2.4): 111 240 dependencies: ··· 116 245 dependencies: 117 246 react: 19.2.4 118 247 248 + react-responsive-masonry@2.7.1: {} 249 + 119 250 react@19.2.4: {} 120 251 121 252 scheduler@0.27.0: {} ··· 123 254 tippy.js@6.3.7: 124 255 dependencies: 125 256 '@popperjs/core': 2.11.8 257 + 258 + trie-memoize@1.2.0: {} 126 259 127 260 typescript@6.0.0-dev.20260213: {}
+46 -14
public/exporter.js
··· 1 + // @ts-check 2 + 1 3 /* eslint-disable indent */ 2 4 /* globals choiceOptions, kinkCategories, kinksById, getSelectedKinkOrDefault, ClipboardItem */ 3 - 4 - // @ts-check 5 5 6 6 const IMGUR_CLIENT_ID = '9db53e5936cd02f'; 7 7 ··· 9 9 /** 10 10 * @param {CanvasRenderingContext2D} context 11 11 * @param {CanvasPattern} pattern 12 - * @param {{ data: string; x: number; y: number; }} drawCall 12 + * @param {SimpleTitleDrawCall} drawCall 13 13 */ 14 14 simpleTitle(context, pattern, drawCall) { 15 15 context.fillStyle = '#000000'; ··· 19 19 /** 20 20 * @param {CanvasRenderingContext2D} context 21 21 * @param {CanvasPattern} pattern 22 - * @param {{ data: { category: any; fields: any[]; }; x: number; y: number; }} drawCall 22 + * @param {TitleSubtitleDrawCall} drawCall 23 23 */ 24 24 titleSubtitle(context, pattern, drawCall) { 25 25 context.fillStyle = '#000000'; ··· 33 33 /** 34 34 * @param {CanvasRenderingContext2D} context 35 35 * @param {CanvasPattern} pattern 36 - * @param {{ data: { choices: string[]; text: string; }; x: number; y: number; }} drawCall 36 + * @param {KinkRowDrawCall} drawCall 37 37 */ 38 38 kinkRow(context, pattern, drawCall) { 39 39 context.fillStyle = '#000000'; ··· 126 126 } 127 127 128 128 /** 129 + * @typedef {object} SimpleTitleDrawCall 130 + * @property {'simpleTitle'} type 131 + * @property {string} data 132 + * @property {number} [x] 133 + * @property {number} y 134 + */ 135 + 136 + /** 137 + * @typedef {object} TitleSubtitleDrawCall 138 + * @property {'titleSubtitle'} type 139 + * @property {object} data 140 + * @property {string} data.category 141 + * @property {string[]} data.fields 142 + * @property {number} [x] 143 + * @property {number} y 144 + */ 145 + 146 + /** 147 + * @typedef {object} KinkRowDrawCall 148 + * @property {'kinkRow'} type 149 + * @property {object} data 150 + * @property {string[]} data.choices 151 + * @property {string} data.text 152 + * @property {number} [x] 153 + * @property {number} y 154 + */ 155 + 156 + /** 157 + * @typedef {SimpleTitleDrawCall | TitleSubtitleDrawCall | KinkRowDrawCall} DrawCall 158 + */ 159 + 160 + /** 129 161 * @returns {HTMLCanvasElement} 130 162 */ 131 163 function exportImage() { ··· 156 188 ); 157 189 158 190 // Initialize columns and drawStacks 191 + /** @type {Array<{ height: number, drawStack: DrawCall[] }>} */ 159 192 const columns = []; 160 193 for (let i = 0; i < numberCols; i++) { 161 194 columns.push({ height: 0, drawStack: [] }); ··· 180 213 const column = columns[columnIndex]; 181 214 182 215 // Drawcall for title 183 - const drawCall = { y: column.height }; 184 - column.drawStack.push(drawCall); 185 216 if (fields.length < 2) { 186 217 column.height += simpleTitleHeight; 187 - drawCall.type = 'simpleTitle'; 188 - drawCall.data = catName; 218 + /** @type {SimpleTitleDrawCall} */ 219 + const drawCall = { y: column.height, type: 'simpleTitle', data: catName }; 220 + column.drawStack.push(drawCall); 189 221 } else { 190 222 column.height += titleSubtitleHeight; 191 - drawCall.type = 'titleSubtitle'; 192 - drawCall.data = { 193 - category: catName, 194 - fields: fields 195 - }; 223 + /** @type {TitleSubtitleDrawCall} */ 224 + const drawCall = { y: column.height, type: 'titleSubtitle', data: { category: catName, fields: fields } }; 225 + column.drawStack.push(drawCall); 196 226 } 197 227 198 228 // Drawcalls for kinks 199 229 for (const kink of category.kinks) { 230 + /** @type {KinkRowDrawCall} */ 200 231 const drawCall = { 201 232 y: column.height, 202 233 type: 'kinkRow', ··· 232 263 for (const drawCall of drawStack) { 233 264 drawCall.x = drawX; 234 265 drawCall.y += offsets.top; 266 + // @ts-expect-error - TS doesn't understand that the type of drawCall is determined by the type property 235 267 drawCallHandlers[drawCall.type](context, pattern, drawCall); 236 268 } 237 269 }
+1 -1
public/helpers.d.ts
··· 4 4 declare const preactHooks: typeof import('preact/hooks'); 5 5 declare const preactCompat: typeof import('preact/compat'); 6 6 // declare const Tippy: typeof import('@tippyjs/react'); 7 - declare const Masonry: typeof import('react-masonry-css')['default']; 7 + declare const Masonic: typeof import('masonic');
+10 -21
public/index.html
··· 220 220 html.dark-theme .choice { 221 221 border-color: white; 222 222 } 223 - .masonry { 224 - display: -webkit-box; /* Not needed if autoprefixing */ 225 - display: -ms-flexbox; /* Not needed if autoprefixing */ 226 - display: flex; 227 - width: auto; 228 - } 229 - .masonry-column { 230 - background-clip: padding-box; 231 - } 232 223 </style> 233 224 234 225 <kinks> ··· 509 500 <h2>Version 14 - February 13th 2026</h2> 510 501 <ul> 511 502 <li>Use Preact for rendering</li> 503 + <li>Upgrade to Bulma 1.0.4</li> 512 504 </ul> 513 505 514 506 <h2>Version 13 - November 14th 2022</h2> ··· 597 589 <button class="modal-close is-large" aria-label="close"></button> 598 590 </div> 599 591 600 - <script src="https://unpkg.com/@popperjs/core@2"></script> 601 - <script src="https://unpkg.com/tippy.js@6"></script> 602 - <script src="https://unpkg.com/preact@10.28.3/dist/preact.min.js"></script> 603 - <script src="https://unpkg.com/preact@10.28.3/hooks/dist/hooks.umd.js"></script> 604 - <script src="https://unpkg.com/preact@10.28.3/compat/dist/compat.umd.js"></script> 605 - <script> 606 - // Alias React UMD globals to Preact globals 607 - window.React = window.preactCompat; 608 - window.react = window.preactCompat; 609 - window.ReactDOM = window.preactCompat; 610 - </script> 611 - <script src="https://unpkg.com/react-masonry-css@1.0.16/dist/react-masonry-css.umd.js"></script> 592 + <script src="https://unpkg.com/@popperjs/core@2" defer></script> 593 + <script src="https://unpkg.com/tippy.js@6" defer></script> 594 + <script src="https://unpkg.com/preact@10.28.3/dist/preact.min.js" defer></script> 595 + <script src="https://unpkg.com/preact@10.28.3/hooks/dist/hooks.umd.js" defer></script> 596 + <script src="https://unpkg.com/preact@10.28.3/compat/dist/compat.umd.js" defer></script> 597 + <script src="https://unpkg.com/@preact/signals-core@1.13.0/dist/signals-core.min.js" defer></script> 598 + <script src="https://unpkg.com/@preact/signals@2.8.0/dist/signals.min.js" defer></script> 599 + <script src="./polyfill-react.js" defer></script> 600 + <script src="https://unpkg.com/masonic@4.1.0/dist/umd/masonic.js" defer></script> 612 601 613 602 <!-- defer is used here so that DOMTools is loaded in time as it's async --> 614 603 <script src="pageinfo.js" async></script>
+20 -8
public/kinklist.js
··· 552 552 ); 553 553 } 554 554 555 + /** 556 + * @typedef {object} MasonryItemProps 557 + * @property {number} index 558 + * @property {KinkCategory} data 559 + * @property {number} width 560 + */ 561 + 562 + /** 563 + * @param {MasonryItemProps} props 564 + */ 565 + function MasonryItem({ index, data: kinkCategory, width }) { 566 + return h(TheKinkCategory, { kinkCategory }, null); 567 + } 568 + 555 569 function Root() { 556 - return h(Masonry, { breakpointCols: { 557 - // breakpoints are the opposite to what you'd expect 558 - 1023: 1, 559 - 1530: 2, 560 - default: 3, 561 - }, className: 'masonry', columnClassName: 'masonry-column' }, [ 562 - kinkCategories.map(kinkCategory => h(TheKinkCategory, { kinkCategory }, null)) 563 - ]); 570 + return h(Masonic.Masonry, { 571 + items: kinkCategories, 572 + render: MasonryItem, 573 + columnWidth: 460, 574 + maxColumnCount: 8, 575 + }); 564 576 } 565 577 566 578 render(h(Root, null), root);
+4
public/polyfill-react.js
··· 1 + // Alias React UMD globals to Preact globals 2 + window.React = window.preactCompat; 3 + window.react = window.preactCompat; 4 + window.ReactDOM = window.preactCompat;
+1 -1
public/preact-tippy.js
··· 20 20 21 21 const instance = tippy(element, {content, ...config}); 22 22 return () => { 23 - instance[0].destroy(); 23 + instance.destroy(); 24 24 }; 25 25 }, []); 26 26