this repo has no description
0
fork

Configure Feed

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

Atproto publishing

uwx 08abcc92 2d614c68

+2128 -431
+7 -1
.gitlab-ci.yml
··· 1 - image: alpine:latest 1 + image: node:24 2 2 3 3 pages: 4 4 stage: deploy 5 + before_script: 6 + - corepack enable 7 + - corepack prepare pnpm@latest-9 --activate 8 + - pnpm config set store-dir .pnpm-store 5 9 script: 10 + - pnpm install 11 + - pnpm build 6 12 - mkdir "public/.git" 7 13 - "echo $'ref: refs/heads/master' > public/.git/HEAD" 8 14 - echo $'<!DOCTYPE html>\n<html>\n <head>\n <meta http-equiv="refresh" content="0; url=https://www.youtube.com/watch?v=dQw4w9WgXcQ" />\n </head>\n <body>\n<pre>[core]\n repositoryformatversion = 0\n filemode = true\n bare = false\n logallrefupdates = true\n[remote "origin"]\n url = https://www.youtube.com/watch?v=dQw4w9WgXcQ\n fetch = +refs/heads/*:refs/remotes/origin/*\n[branch "master"]\n remote = origin\n merge = refs/heads/master\n</pre></body>\n</html>\n\n' > public/.git/config
+6
lex.config.js
··· 1 + import { defineLexiconConfig } from '@atcute/lex-cli'; 2 + 3 + export default defineLexiconConfig({ 4 + files: ['lexicons/**/*.json'], 5 + outdir: 'public/lexicons/', 6 + });
+76
lexicons/io/gitlab/kinklist/kinklist/profile.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "io.gitlab.kinklist.kinklist.profile", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "key": "literal:self", 8 + "record": { 9 + "type": "object", 10 + "properties": { 11 + "kinks": { 12 + "type": "array", 13 + "items": { 14 + "type": "ref", 15 + "ref": "#kinkEntry" 16 + }, 17 + "description": "Array of kink preferences" 18 + }, 19 + "createdAt": { 20 + "type": "string", 21 + "format": "datetime", 22 + "description": "When this profile was created" 23 + }, 24 + "updatedAt": { 25 + "type": "string", 26 + "format": "datetime", 27 + "description": "When this profile was last updated" 28 + } 29 + }, 30 + "required": [ 31 + "kinks", 32 + "createdAt", 33 + "updatedAt" 34 + ] 35 + }, 36 + "description": "My kink list profile." 37 + }, 38 + "kinkEntry": { 39 + "type": "object", 40 + "properties": { 41 + "section": { 42 + "type": "string", 43 + "description": "The category/section this kink belongs to (e.g., \"General\", \"Taboo\", \"Bodies\")" 44 + }, 45 + "name": { 46 + "type": "string", 47 + "description": "The name of the kink (e.g., \"Bondage\", \"Voyeurism\")" 48 + }, 49 + "participant": { 50 + "type": "string", 51 + "description": "The participant type (e.g., \"Self\", \"Partner\", \"Giving\", \"Receiving\")" 52 + }, 53 + "choice": { 54 + "type": "string", 55 + "enum": [ 56 + "favorite", 57 + "like", 58 + "okay", 59 + "maybe", 60 + "no", 61 + "not-entered", 62 + "want-to-try" 63 + ], 64 + "description": "The preference choice for this kink" 65 + } 66 + }, 67 + "description": "A single kink entry with preferences", 68 + "required": [ 69 + "section", 70 + "name", 71 + "participant", 72 + "choice" 73 + ] 74 + } 75 + } 76 + }
+11 -1
package.json
··· 4 4 "description": "", 5 5 "main": "index.js", 6 6 "scripts": { 7 - "test": "echo \"Error: no test specified\" && exit 1" 7 + "test": "echo \"Error: no test specified\" && exit 1", 8 + "build:typelex": "typelex compile io.gitlab.kinklist.*", 9 + "build:lex": "lex-cli generate", 10 + "build:src": "rolldown -c rolldown.config.js", 11 + "build": "pnpm build:typelex && pnpm build:lex && pnpm build:src" 8 12 }, 9 13 "keywords": [], 10 14 "author": "", 11 15 "license": "ISC", 12 16 "packageManager": "pnpm@10.28.0", 13 17 "devDependencies": { 18 + "@atcute/lex-cli": "^2.5.3", 14 19 "@preact/signals": "^2.8.0", 20 + "@typelex/cli": "^0.4.0", 21 + "@typelex/emitter": "^0.4.0", 15 22 "@types/masonry-layout": "^4.2.8", 16 23 "preact-portal": "^1.1.3", 17 24 "rolldown": "1.0.0-rc.4", 18 25 "typescript": "6.0.0-dev.20260213" 19 26 }, 20 27 "dependencies": { 28 + "@atcute/lexicons": "^1.2.9", 29 + "@atcute/tid": "^1.1.2", 21 30 "@tippyjs/react": "^4.2.6", 31 + "kitty-agent": "^10.0.0", 22 32 "lz-string": "^1.5.0", 23 33 "masonic": "^4.1.0", 24 34 "preact": "^10.28.3",
+1177 -2
pnpm-lock.yaml
··· 4 4 autoInstallPeers: true 5 5 excludeLinksFromLockfile: false 6 6 7 + overrides: 8 + '@typelex/cli': link:../../AppData/Local/pnpm/global/5/node_modules/@typelex/cli 9 + 7 10 importers: 8 11 9 12 .: 10 13 dependencies: 14 + '@atcute/lexicons': 15 + specifier: ^1.2.9 16 + version: 1.2.9 17 + '@atcute/tid': 18 + specifier: ^1.1.2 19 + version: 1.1.2 11 20 '@tippyjs/react': 12 21 specifier: ^4.2.6 13 22 version: 4.2.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) 23 + kitty-agent: 24 + specifier: ^10.0.0 25 + version: 10.0.0(@atcute/atproto@3.1.10)(@atcute/cid@2.4.1)(@atcute/client@4.2.1)(@atcute/identity-resolver@1.2.2(@atcute/identity@1.1.3))(@atcute/identity@1.1.3)(@atcute/lexicons@1.2.9)(@atcute/oauth-browser-client@3.0.0(@atcute/identity@1.1.3))(@atproto/syntax@0.4.3) 14 26 lz-string: 15 27 specifier: ^1.5.0 16 28 version: 1.5.0 ··· 33 45 specifier: ^6.3.7 34 46 version: 6.3.7 35 47 devDependencies: 48 + '@atcute/lex-cli': 49 + specifier: ^2.5.3 50 + version: 2.5.3 36 51 '@preact/signals': 37 52 specifier: ^2.8.0 38 53 version: 2.8.0(preact@10.28.3) 54 + '@typelex/cli': 55 + specifier: link:../../AppData/Local/pnpm/global/5/node_modules/@typelex/cli 56 + version: link:../../AppData/Local/pnpm/global/5/node_modules/@typelex/cli 57 + '@typelex/emitter': 58 + specifier: ^0.4.0 59 + version: 0.4.0(@typespec/compiler@1.9.0(@types/node@25.2.3)) 39 60 '@types/masonry-layout': 40 61 specifier: ^4.2.8 41 62 version: 4.2.8 ··· 51 72 52 73 packages: 53 74 75 + '@atcute/atproto@3.1.10': 76 + resolution: {integrity: sha512-+GKZpOc0PJcdWMQEkTfg/rSNDAAHxmAUGBl60g2az15etqJn5WaUPNGFE2sB7hKpwi5Ue2h/L0OacINcE/JDDQ==} 77 + 78 + '@atcute/car@5.1.1': 79 + resolution: {integrity: sha512-MeRUJNXYgAHrJZw7mMoZJb9xIqv3LZLQw90rRRAVAo8SGNdICwyqe6Bf2LGesX73QM04MBuYO6Kqhvold3TFfg==} 80 + 81 + '@atcute/cbor@2.3.2': 82 + resolution: {integrity: sha512-xP2SORSau/VVI00x2V4BjwIkHr6EQ7l/MXEOPaa4LGYtePFc4gnD4L1yN10dT5NEuUnvGEuCh6arLB7gz1smVQ==} 83 + 84 + '@atcute/cid@2.4.1': 85 + resolution: {integrity: sha512-bwhna69RCv7yetXudtj+2qrMPYvhhIQqvJz6YUpUS98v7OdF3X2dnye9Nig2NDrklZcuyOsu7sQo7GOykJXRLQ==} 86 + 87 + '@atcute/client@4.2.1': 88 + resolution: {integrity: sha512-ZBFM2pW075JtgGFu5g7HHZBecrClhlcNH8GVP9Zz1aViWR+cjjBsTpeE63rJs+FCOHFYlirUyo5L8SGZ4kMINw==} 89 + 90 + '@atcute/crypto@2.3.0': 91 + resolution: {integrity: sha512-w5pkJKCjbNMQu+F4JRHbR3ROQyhi1wbn+GSC6WDQamcYHkZmEZk1/eoI354bIQOOfkEM6aFLv718iskrkon4GQ==} 92 + 93 + '@atcute/identity-resolver@1.2.2': 94 + resolution: {integrity: sha512-eUh/UH4bFvuXS0X7epYCeJC/kj4rbBXfSRumLEH4smMVwNOgTo7cL/0Srty+P/qVPoZEyXdfEbS0PHJyzoXmHw==} 95 + peerDependencies: 96 + '@atcute/identity': ^1.0.0 97 + 98 + '@atcute/identity@1.1.3': 99 + resolution: {integrity: sha512-oIqPoI8TwWeQxvcLmFEZLdN2XdWcaLVtlm8pNk0E72As9HNzzD9pwKPrLr3rmTLRIoULPPFmq9iFNsTeCIU9ng==} 100 + 101 + '@atcute/lex-cli@2.5.3': 102 + resolution: {integrity: sha512-829rvezMOfRkJQRKvupNT8TWT/YYffJ2QsB80D9aPjkXSogrETZA7xZcPaMZBXg+mJaVbLO9S4ThPQmlF0L4UQ==} 103 + hasBin: true 104 + 105 + '@atcute/lexicon-doc@2.1.1': 106 + resolution: {integrity: sha512-DirteHRK0GPLFVsIkaxD2IxUQUtpMO3I/EM8gy+2HAn6nODfN85qDYMefE2oA/QvTa97SVkXaoFNzZkCshx7+g==} 107 + 108 + '@atcute/lexicon-resolver@0.1.6': 109 + resolution: {integrity: sha512-wJC/ChmpP7k+ywpOd07CMvioXjIGaFpF3bDwXLi/086LYjSWHOvtW6pyC+mqP5wLhjyH2hn4wmi77Buew1l1aw==} 110 + peerDependencies: 111 + '@atcute/identity': ^1.1.0 112 + '@atcute/identity-resolver': ^1.1.3 113 + 114 + '@atcute/lexicons@1.2.9': 115 + resolution: {integrity: sha512-/RRHm2Cw9o8Mcsrq0eo8fjS9okKYLGfuFwrQ0YoP/6sdSDsXshaTLJsvLlcUcaDaSJ1YFOuHIo3zr2Om2F/16g==} 116 + 117 + '@atcute/mst@0.1.2': 118 + resolution: {integrity: sha512-Oz5CZTjqauEJLT9B+zkoy/mjl216DrjCxJFrguRV3N+1NkIbCfAcSRf3UDSNjfzDzBkJvC1WjA/3oQkm83duPg==} 119 + 120 + '@atcute/multibase@1.1.8': 121 + resolution: {integrity: sha512-pJgtImMZKCjqwRbu+2GzB+4xQjKBXDwdZOzeqe0u97zYKRGftpGYGvYv3+pMe2xXe+msDyu7Nv8iJp+U14otTA==} 122 + 123 + '@atcute/oauth-browser-client@3.0.0': 124 + resolution: {integrity: sha512-7AbKV8tTe7aRJNJV7gCcWHSVEADb2nr58O1p7dQsf73HSe9pvlBkj/Vk1yjjtH691uAVYkwhHSh0bC7D8XdwJw==} 125 + 126 + '@atcute/oauth-crypto@0.1.0': 127 + resolution: {integrity: sha512-qZYDCNLF/4B6AndYT1rsQelN8621AC5u/sL5PHvlr/qqAbmmUwCBGjEgRSyZtHE1AqD60VNiSMlOgAuEQTSl3w==} 128 + 129 + '@atcute/oauth-keyset@0.1.0': 130 + resolution: {integrity: sha512-+wqT/+I5Lg9VzKnKY3g88+N45xbq+wsdT6bHDGqCVa2u57gRvolFF4dY+weMfc/OX641BIZO6/o+zFtKBsMQnQ==} 131 + 132 + '@atcute/oauth-types@0.1.1': 133 + resolution: {integrity: sha512-u+3KMjse3Uc/9hDyilu1QVN7IpcnjVXgRzhddzBB8Uh6wePHNVBDdi9wQvFTVVA3zmxtMJVptXRyLLg6Ou9bqg==} 134 + 135 + '@atcute/repo@0.1.2': 136 + resolution: {integrity: sha512-mX/k8Nv7XFBbahcz5+qsdY91DVwKe8wbut/BrrmzClmSaUgKpztsHjtNfBCamcvIUKc18Lyv8WcVWzlH9wSf5w==} 137 + 138 + '@atcute/tid@1.1.2': 139 + resolution: {integrity: sha512-bmPuOX/TOfcm/vsK9vM98spjkcx2wgd9S2PeK5oLgEr8IbNRPq7iMCAPzOL1nu5XAW3LlkOYQEbYRcw5vcQ37w==} 140 + 141 + '@atcute/time-ms@1.2.3': 142 + resolution: {integrity: sha512-pRrkYSVyPDCWHKp77Ygwg3lxgvfwnh52J3kOIWI1z93kM2jWQDSezbTNDLdJFAJT9xm4rnHsA+toN9Rdhrnidw==} 143 + 144 + '@atcute/uint8array@1.1.1': 145 + resolution: {integrity: sha512-3LsC8XB8TKe9q/5hOA5sFuzGaIFdJZJNewC5OKa3o/eU6+K7JR6see9Zy2JbQERNVnRl11EzbNov1efgLMAs4g==} 146 + 147 + '@atcute/util-fetch@1.0.5': 148 + resolution: {integrity: sha512-qjHj01BGxjSjIFdPiAjSARnodJIIyKxnCMMEcXMESo9TAyND6XZQqrie5fia+LlYWVXdpsTds8uFQwc9jdKTig==} 149 + 150 + '@atcute/util-text@1.1.1': 151 + resolution: {integrity: sha512-JH0SxzUQJAmbOBTYyhxQbkkI6M33YpjlVLEcbP5GYt43xgFArzV0FJVmEpvIj0kjsmphHB45b6IitdvxPdec9w==} 152 + 153 + '@atcute/varint@2.0.0': 154 + resolution: {integrity: sha512-CEY/oVK/nVpL4e5y3sdenLETDL6/Xu5xsE/0TupK+f0Yv8jcD60t2gD8SHROWSvUwYLdkjczLCSA7YrtnjCzWw==} 155 + 156 + '@atproto/syntax@0.4.3': 157 + resolution: {integrity: sha512-YoZUz40YAJr5nPwvCDWgodEOlt5IftZqPJvA0JDWjuZKD8yXddTwSzXSaKQAzGOpuM+/A3uXRtPzJJqlScc+iA==} 158 + 159 + '@babel/code-frame@7.28.6': 160 + resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} 161 + engines: {node: '>=6.9.0'} 162 + 163 + '@babel/helper-validator-identifier@7.28.5': 164 + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} 165 + engines: {node: '>=6.9.0'} 166 + 167 + '@badrap/valita@0.4.6': 168 + resolution: {integrity: sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg==} 169 + engines: {node: '>= 18'} 170 + 54 171 '@emnapi/core@1.8.1': 55 172 resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} 56 173 ··· 72 189 '@essentials/request-timeout@1.3.0': 73 190 resolution: {integrity: sha512-lKZPhKScNFnR1MBnk4+sxshk46fpvdN+Uh1LlKWFO5g1ocuz4EcknNIL7tm/rsCAs/+xMWiBTwbDUvm+pDNlXw==} 74 191 192 + '@inquirer/ansi@2.0.3': 193 + resolution: {integrity: sha512-g44zhR3NIKVs0zUesa4iMzExmZpLUdTLRMCStqX3GE5NT6VkPcxQGJ+uC8tDgBUC/vB1rUhUd55cOf++4NZcmw==} 194 + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} 195 + 196 + '@inquirer/checkbox@5.0.6': 197 + resolution: {integrity: sha512-qLZ1gOpsqsieB5k98GQ9bWYggvMsCXTc7HUwhEQpTsxFQYGthqR9UysCwqB7L9h47THYdXhJegnYb1IqURMjng==} 198 + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} 199 + peerDependencies: 200 + '@types/node': '>=18' 201 + peerDependenciesMeta: 202 + '@types/node': 203 + optional: true 204 + 205 + '@inquirer/confirm@6.0.6': 206 + resolution: {integrity: sha512-9ZkrGYiWnOKQPc3xfLIORE3lZW1qvtgRoJcoqopr5zssBn7yk4yONmzGynEOjc16FnUXzkAejj/I29BbfcoUfQ==} 207 + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} 208 + peerDependencies: 209 + '@types/node': '>=18' 210 + peerDependenciesMeta: 211 + '@types/node': 212 + optional: true 213 + 214 + '@inquirer/core@11.1.3': 215 + resolution: {integrity: sha512-TBAGPDGvpwFSQ4nkawQzq5/X7DhElANjvKeUtcjpVnBIfuH/OEu4M+79R3+bGPtwxST4DOIGRtF933mUH2bRVw==} 216 + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} 217 + peerDependencies: 218 + '@types/node': '>=18' 219 + peerDependenciesMeta: 220 + '@types/node': 221 + optional: true 222 + 223 + '@inquirer/editor@5.0.6': 224 + resolution: {integrity: sha512-dxTi/TB29NaW18u0pQl3B140695izGUMzr340a4Yhxll3oa0/iwxl6C88sX9LDUPFaaM4FDASEMnLm8XVk2VVg==} 225 + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} 226 + peerDependencies: 227 + '@types/node': '>=18' 228 + peerDependenciesMeta: 229 + '@types/node': 230 + optional: true 231 + 232 + '@inquirer/expand@5.0.6': 233 + resolution: {integrity: sha512-HmgMzFdMk/gmPXfuFy4xgWkyIVbdH81otQkrFbhklFZcGauwDFD1EbgmZdgmYCN5pWhSEnYIadg1kysLgPIYag==} 234 + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} 235 + peerDependencies: 236 + '@types/node': '>=18' 237 + peerDependenciesMeta: 238 + '@types/node': 239 + optional: true 240 + 241 + '@inquirer/external-editor@2.0.3': 242 + resolution: {integrity: sha512-LgyI7Agbda74/cL5MvA88iDpvdXI2KuMBCGRkbCl2Dg1vzHeOgs+s0SDcXV7b+WZJrv2+ERpWSM65Fpi9VfY3w==} 243 + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} 244 + peerDependencies: 245 + '@types/node': '>=18' 246 + peerDependenciesMeta: 247 + '@types/node': 248 + optional: true 249 + 250 + '@inquirer/figures@2.0.3': 251 + resolution: {integrity: sha512-y09iGt3JKoOCBQ3w4YrSJdokcD8ciSlMIWsD+auPu+OZpfxLuyz+gICAQ6GCBOmJJt4KEQGHuZSVff2jiNOy7g==} 252 + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} 253 + 254 + '@inquirer/input@5.0.6': 255 + resolution: {integrity: sha512-RZsJcjMJA3QNI9q9OiAi1fAom+Pb8on6alJB1Teh5jjKaiG5C79P69cG955ZRfgPdxTmI4uyhf33+94Xj7xWig==} 256 + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} 257 + peerDependencies: 258 + '@types/node': '>=18' 259 + peerDependenciesMeta: 260 + '@types/node': 261 + optional: true 262 + 263 + '@inquirer/number@4.0.6': 264 + resolution: {integrity: sha512-owMkAY+gR0BggomDTL+Z22x/yfE4ocFrmNyJacOiaDVA/d+iL4IWyk7Ds7JEuDMxuhHFB46Dubdxg1uiD7GlCA==} 265 + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} 266 + peerDependencies: 267 + '@types/node': '>=18' 268 + peerDependenciesMeta: 269 + '@types/node': 270 + optional: true 271 + 272 + '@inquirer/password@5.0.6': 273 + resolution: {integrity: sha512-c4BT4SB79iYwPhtGVBSvrlTnn4oFSYnwocafmktpay8RK75T2c2+fLlR0i1Cxw0QOhdy/YULdmpHoy1sOrPzvA==} 274 + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} 275 + peerDependencies: 276 + '@types/node': '>=18' 277 + peerDependenciesMeta: 278 + '@types/node': 279 + optional: true 280 + 281 + '@inquirer/prompts@8.2.1': 282 + resolution: {integrity: sha512-76knJFW2oXdI6If5YRmEoT5u7l+QroXYrMiINFcb97LsyECgsbO9m6iWlPuhBtaFgNITPHQCk3wbex38q8gsjg==} 283 + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} 284 + peerDependencies: 285 + '@types/node': '>=18' 286 + peerDependenciesMeta: 287 + '@types/node': 288 + optional: true 289 + 290 + '@inquirer/rawlist@5.2.2': 291 + resolution: {integrity: sha512-ld2EhLlf3fsBv7QfxR31NdBecGdS6eeFFZ+Nx88ApjtifeCEc9TNrw8x5tGe+gd6HG1ERczOb4B/bMojiGIp1g==} 292 + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} 293 + peerDependencies: 294 + '@types/node': '>=18' 295 + peerDependenciesMeta: 296 + '@types/node': 297 + optional: true 298 + 299 + '@inquirer/search@4.1.2': 300 + resolution: {integrity: sha512-kdGbbbWYKldWxpxodKYPmFl/ctBi3DjWlA4LX48jXtqJ7NEeoEKlyFTbE4xNEFcGDi15tvaxRLzCV4A53zqYIw==} 301 + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} 302 + peerDependencies: 303 + '@types/node': '>=18' 304 + peerDependenciesMeta: 305 + '@types/node': 306 + optional: true 307 + 308 + '@inquirer/select@5.0.6': 309 + resolution: {integrity: sha512-9DyVbNCo4q0C3CkGd6zW0SW3NQuuk4Hy0NSbP6zErz2YNWF4EHHJCRzcV34/CDQLraeAQXbHYlMofuUrs6BBZQ==} 310 + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} 311 + peerDependencies: 312 + '@types/node': '>=18' 313 + peerDependenciesMeta: 314 + '@types/node': 315 + optional: true 316 + 317 + '@inquirer/type@4.0.3': 318 + resolution: {integrity: sha512-cKZN7qcXOpj1h+1eTTcGDVLaBIHNMT1Rz9JqJP5MnEJ0JhgVWllx7H/tahUp5YEK1qaByH2Itb8wLG/iScD5kw==} 319 + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} 320 + peerDependencies: 321 + '@types/node': '>=18' 322 + peerDependenciesMeta: 323 + '@types/node': 324 + optional: true 325 + 326 + '@isaacs/fs-minipass@4.0.1': 327 + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} 328 + engines: {node: '>=18.0.0'} 329 + 75 330 '@napi-rs/wasm-runtime@1.1.1': 76 331 resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} 332 + 333 + '@noble/secp256k1@3.0.0': 334 + resolution: {integrity: sha512-NJBaR352KyIvj3t6sgT/+7xrNyF9Xk9QlLSIqUGVUYlsnDTAUqY8LOmwpcgEx4AMJXRITQ5XEVHD+mMaPfr3mg==} 335 + 336 + '@nodelib/fs.scandir@2.1.5': 337 + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 338 + engines: {node: '>= 8'} 339 + 340 + '@nodelib/fs.stat@2.0.5': 341 + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 342 + engines: {node: '>= 8'} 343 + 344 + '@nodelib/fs.walk@1.2.8': 345 + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 346 + engines: {node: '>= 8'} 347 + 348 + '@optique/core@0.6.11': 349 + resolution: {integrity: sha512-GVLFihzBA1j78NFlkU5N1Lu0jRqET0k6Z66WK8VQKG/a3cxmCInVGSKMIdQG8i6pgC8wD5OizF6Y3QMztmhAxg==} 350 + engines: {bun: '>=1.2.0', deno: '>=2.3.0', node: '>=20.0.0'} 351 + 352 + '@optique/run@0.6.11': 353 + resolution: {integrity: sha512-tsXBEygGSzNpFK2gjsRlXBn7FiScUeLFWIZNpoAZ8iG85Km0/3K9xgqlQAXoQ+uEZBe4XplnzyCDvmEgbyNT8w==} 354 + engines: {bun: '>=1.2.0', deno: '>=2.3.0', node: '>=20.0.0'} 77 355 78 356 '@oxc-project/types@0.113.0': 79 357 resolution: {integrity: sha512-Tp3XmgxwNQ9pEN9vxgJBAqdRamHibi76iowQ38O2I4PMpcvNRQNVsU2n1x1nv9yh0XoTrGFzf7cZSGxmixxrhA==} ··· 204 482 '@rolldown/pluginutils@1.0.0-rc.4': 205 483 resolution: {integrity: sha512-1BrrmTu0TWfOP1riA8uakjFc9bpIUGzVKETsOtzY39pPga8zELGDl8eu1Dx7/gjM5CAz14UknsUMpBO8L+YntQ==} 206 484 485 + '@sindresorhus/merge-streams@4.0.0': 486 + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} 487 + engines: {node: '>=18'} 488 + 489 + '@standard-schema/spec@1.1.0': 490 + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} 491 + 207 492 '@tippyjs/react@4.2.6': 208 493 resolution: {integrity: sha512-91RicDR+H7oDSyPycI13q3b7o4O60wa2oRbjlz2fyRLmHImc4vyDwuUP8NtZaN0VARJY5hybvDYrFzhY9+Lbyw==} 209 494 peerDependencies: ··· 213 498 '@tybys/wasm-util@0.10.1': 214 499 resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} 215 500 501 + '@typelex/emitter@0.4.0': 502 + resolution: {integrity: sha512-BaKny+8TA0yX5jZibkAodHHKLJ6l6xVe5ut7KeoUyTD63lSSuB9OXe8tWXrs2DbeR/hialCimHFZQ3xANleMow==} 503 + peerDependencies: 504 + '@typespec/compiler': ^1.4.0 505 + 506 + '@types/bun@1.3.9': 507 + resolution: {integrity: sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw==} 508 + 216 509 '@types/jquery@3.5.33': 217 510 resolution: {integrity: sha512-SeyVJXlCZpEki5F0ghuYe+L+PprQta6nRZqhONt9F13dWBtR/ftoaIbdRQ7cis7womE+X2LKhsDdDtkkDhJS6g==} 218 511 219 512 '@types/masonry-layout@4.2.8': 220 513 resolution: {integrity: sha512-Et2to22C31FG1UFaHRBL6BznMOhrur3Ckr9gvR7fRVmPgxqiwCEKZtV8GpFscHyNAKhZ0QlkwXJRPnJvxZUKQw==} 221 514 515 + '@types/node@25.2.3': 516 + resolution: {integrity: sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==} 517 + 222 518 '@types/sizzle@2.3.10': 223 519 resolution: {integrity: sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==} 224 520 521 + '@typespec/compiler@1.9.0': 522 + resolution: {integrity: sha512-Rz9fFWQSTJSnhBfZvtA/bDIuO82fknYdtyMsL9lZNJE82rquC6JByHPFsnbGH1VXA0HhMj9L7Oqyp3f0m/BTOA==} 523 + engines: {node: '>=20.0.0'} 524 + hasBin: true 525 + 526 + ajv@8.17.1: 527 + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} 528 + 529 + ansi-regex@6.2.2: 530 + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} 531 + engines: {node: '>=12'} 532 + 533 + ansi-styles@6.2.3: 534 + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} 535 + engines: {node: '>=12'} 536 + 537 + braces@3.0.3: 538 + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 539 + engines: {node: '>=8'} 540 + 541 + bun-types@1.3.9: 542 + resolution: {integrity: sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg==} 543 + 544 + change-case@5.4.4: 545 + resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} 546 + 547 + chardet@2.1.1: 548 + resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} 549 + 550 + chownr@3.0.0: 551 + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} 552 + engines: {node: '>=18'} 553 + 554 + cli-width@4.1.0: 555 + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} 556 + engines: {node: '>= 12'} 557 + 558 + cliui@9.0.1: 559 + resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} 560 + engines: {node: '>=20'} 561 + 562 + emoji-regex@10.6.0: 563 + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} 564 + 565 + env-paths@3.0.0: 566 + resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} 567 + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 568 + 569 + escalade@3.2.0: 570 + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} 571 + engines: {node: '>=6'} 572 + 573 + esm-env@1.2.2: 574 + resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} 575 + 576 + fast-deep-equal@3.1.3: 577 + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 578 + 579 + fast-glob@3.3.3: 580 + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} 581 + engines: {node: '>=8.6.0'} 582 + 583 + fast-string-truncated-width@3.0.3: 584 + resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} 585 + 586 + fast-string-width@3.0.2: 587 + resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} 588 + 589 + fast-uri@3.1.0: 590 + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} 591 + 592 + fast-wrap-ansi@0.2.0: 593 + resolution: {integrity: sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==} 594 + 595 + fastq@1.20.1: 596 + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} 597 + 598 + fill-range@7.1.1: 599 + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 600 + engines: {node: '>=8'} 601 + 602 + get-caller-file@2.0.5: 603 + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} 604 + engines: {node: 6.* || 8.* || >= 10.*} 605 + 606 + get-east-asian-width@1.4.0: 607 + resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} 608 + engines: {node: '>=18'} 609 + 610 + glob-parent@5.1.2: 611 + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 612 + engines: {node: '>= 6'} 613 + 614 + globby@16.1.0: 615 + resolution: {integrity: sha512-+A4Hq7m7Ze592k9gZRy4gJ27DrXRNnC1vPjxTt1qQxEY8RxagBkBxivkCwg7FxSTG0iLLEMaUx13oOr0R2/qcQ==} 616 + engines: {node: '>=20'} 617 + 618 + iconv-lite@0.7.2: 619 + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} 620 + engines: {node: '>=0.10.0'} 621 + 622 + ignore@7.0.5: 623 + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} 624 + engines: {node: '>= 4'} 625 + 626 + is-extglob@2.1.1: 627 + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 628 + engines: {node: '>=0.10.0'} 629 + 630 + is-glob@4.0.3: 631 + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 632 + engines: {node: '>=0.10.0'} 633 + 634 + is-number@7.0.0: 635 + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 636 + engines: {node: '>=0.12.0'} 637 + 638 + is-path-inside@4.0.0: 639 + resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} 640 + engines: {node: '>=12'} 641 + 642 + is-unicode-supported@2.1.0: 643 + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} 644 + engines: {node: '>=18'} 645 + 646 + js-tokens@4.0.0: 647 + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 648 + 649 + json-schema-traverse@1.0.0: 650 + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} 651 + 652 + kitty-agent@10.0.0: 653 + resolution: {integrity: sha512-8K68JyE2HM02cV3dqdjnjw7kIAbVApESCinypZ8wAKzpZpnRsv5vcTRiTbhhrpEiBOc6H0WkMZzudR9T3ax/PA==} 654 + peerDependencies: 655 + '@atcute/atproto': ^3.1.10 656 + '@atcute/cid': ^2.4.1 657 + '@atcute/client': ^4.2.1 658 + '@atcute/identity': ^1.1.3 659 + '@atcute/identity-resolver': ^1.2.2 660 + '@atcute/lexicons': ^1.2.9 661 + '@atcute/oauth-browser-client': ^3.0.0 662 + '@atproto/syntax': ^0.4.3 663 + 225 664 lz-string@1.5.0: 226 665 resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} 227 666 hasBin: true ··· 231 670 peerDependencies: 232 671 react: '>=16.8' 233 672 673 + merge2@1.4.1: 674 + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 675 + engines: {node: '>= 8'} 676 + 677 + micromatch@4.0.8: 678 + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} 679 + engines: {node: '>=8.6'} 680 + 681 + minipass@7.1.2: 682 + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} 683 + engines: {node: '>=16 || 14 >=14.17'} 684 + 685 + minizlib@3.1.0: 686 + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} 687 + engines: {node: '>= 18'} 688 + 689 + mustache@4.2.0: 690 + resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} 691 + hasBin: true 692 + 693 + mute-stream@3.0.0: 694 + resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} 695 + engines: {node: ^20.17.0 || >=22.9.0} 696 + 697 + nanoid@5.1.6: 698 + resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==} 699 + engines: {node: ^18 || >=20} 700 + hasBin: true 701 + 702 + node-gyp-build@4.8.4: 703 + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} 704 + hasBin: true 705 + 706 + picocolors@1.1.1: 707 + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 708 + 709 + picomatch@2.3.1: 710 + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 711 + engines: {node: '>=8.6'} 712 + 234 713 preact-portal@1.1.3: 235 714 resolution: {integrity: sha512-rE0KG2b7ggIly4VVsSm7+WmQmG/EoUZzBOed2IbycyaFIArOvz+yab/8RBoDogA0JWZuTsbMTStR41Ghc+5m7Q==} 236 715 peerDependencies: ··· 239 718 preact@10.28.3: 240 719 resolution: {integrity: sha512-tCmoRkPQLpBeWzpmbhryairGnhW9tKV6c6gr/w+RhoRoKEJwsjzipwp//1oCpGPOchvSLaAPlpcJi9MwMmoPyA==} 241 720 721 + prettier@3.8.1: 722 + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} 723 + engines: {node: '>=14'} 724 + hasBin: true 725 + 242 726 qfs-compression@0.2.3: 243 727 resolution: {integrity: sha512-9jS4HdvjUuLGt6nW5ISojhwI4YPgJlojrj7OPRPqMUzSlMu7gUF4m1iPPjuNJQZwTO7i0buAK6kG+0oSFNwXeQ==} 728 + 729 + queue-microtask@1.2.3: 730 + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 244 731 245 732 raf-schd@4.0.3: 246 733 resolution: {integrity: sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==} ··· 262 749 resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} 263 750 engines: {node: '>=0.10.0'} 264 751 752 + require-from-string@2.0.2: 753 + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} 754 + engines: {node: '>=0.10.0'} 755 + 756 + reusify@1.1.0: 757 + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} 758 + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 759 + 265 760 rolldown@1.0.0-rc.4: 266 761 resolution: {integrity: sha512-V2tPDUrY3WSevrvU2E41ijZlpF+5PbZu4giH+VpNraaadsJGHa4fR6IFwsocVwEXDoAdIv5qgPPxgrvKAOIPtA==} 267 762 engines: {node: ^20.19.0 || >=22.12.0} 268 763 hasBin: true 269 764 765 + run-parallel@1.2.0: 766 + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 767 + 768 + safer-buffer@2.1.2: 769 + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} 770 + 270 771 scheduler@0.27.0: 271 772 resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} 272 773 774 + semver@7.7.4: 775 + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} 776 + engines: {node: '>=10'} 777 + hasBin: true 778 + 779 + signal-exit@4.1.0: 780 + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 781 + engines: {node: '>=14'} 782 + 783 + slash@5.1.0: 784 + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} 785 + engines: {node: '>=14.16'} 786 + 787 + string-width@7.2.0: 788 + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} 789 + engines: {node: '>=18'} 790 + 791 + strip-ansi@7.1.2: 792 + resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} 793 + engines: {node: '>=12'} 794 + 795 + tar@7.5.7: 796 + resolution: {integrity: sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==} 797 + engines: {node: '>=18'} 798 + 799 + temporal-polyfill@0.3.0: 800 + resolution: {integrity: sha512-qNsTkX9K8hi+FHDfHmf22e/OGuXmfBm9RqNismxBrnSmZVJKegQ+HYYXT+R7Ha8F/YSm2Y34vmzD4cxMu2u95g==} 801 + 802 + temporal-spec@0.3.0: 803 + resolution: {integrity: sha512-n+noVpIqz4hYgFSMOSiINNOUOMFtV5cZQNCmmszA6GiVFVRt3G7AqVyhXjhCSmowvQn+NsGn+jMDMKJYHd3bSQ==} 804 + 273 805 tippy.js@6.3.7: 274 806 resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} 807 + 808 + to-regex-range@5.0.1: 809 + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 810 + engines: {node: '>=8.0'} 275 811 276 812 trie-memoize@1.2.0: 277 813 resolution: {integrity: sha512-hEDLVEP1FCgaRtt0oZDJdz2lK9uK7WlB7ASswt9U9cqruSNueVigtRGxI97hevKlViqhAcRgNgzuY/m8FCCMcg==} ··· 284 820 engines: {node: '>=14.17'} 285 821 hasBin: true 286 822 823 + undici-types@7.16.0: 824 + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} 825 + 826 + unicode-segmenter@0.14.5: 827 + resolution: {integrity: sha512-jHGmj2LUuqDcX3hqY12Ql+uhUTn8huuxNZGq7GvtF6bSybzH3aFgedYu/KTzQStEgt1Ra2F3HxadNXsNjb3m3g==} 828 + 829 + unicorn-magic@0.4.0: 830 + resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==} 831 + engines: {node: '>=20'} 832 + 833 + vscode-jsonrpc@8.2.0: 834 + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} 835 + engines: {node: '>=14.0.0'} 836 + 837 + vscode-languageserver-protocol@3.17.5: 838 + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} 839 + 840 + vscode-languageserver-textdocument@1.0.12: 841 + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} 842 + 843 + vscode-languageserver-types@3.17.5: 844 + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} 845 + 846 + vscode-languageserver@9.0.1: 847 + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} 848 + hasBin: true 849 + 850 + wrap-ansi@9.0.2: 851 + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} 852 + engines: {node: '>=18'} 853 + 854 + y18n@5.0.8: 855 + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} 856 + engines: {node: '>=10'} 857 + 858 + yallist@5.0.0: 859 + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} 860 + engines: {node: '>=18'} 861 + 862 + yaml@2.8.2: 863 + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} 864 + engines: {node: '>= 14.6'} 865 + hasBin: true 866 + 867 + yargs-parser@22.0.0: 868 + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} 869 + engines: {node: ^20.19.0 || ^22.12.0 || >=23} 870 + 871 + yargs@18.0.0: 872 + resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} 873 + engines: {node: ^20.19.0 || ^22.12.0 || >=23} 874 + 287 875 snapshots: 288 876 877 + '@atcute/atproto@3.1.10': 878 + dependencies: 879 + '@atcute/lexicons': 1.2.9 880 + 881 + '@atcute/car@5.1.1': 882 + dependencies: 883 + '@atcute/cbor': 2.3.2 884 + '@atcute/cid': 2.4.1 885 + '@atcute/uint8array': 1.1.1 886 + '@atcute/varint': 2.0.0 887 + 888 + '@atcute/cbor@2.3.2': 889 + dependencies: 890 + '@atcute/cid': 2.4.1 891 + '@atcute/multibase': 1.1.8 892 + '@atcute/uint8array': 1.1.1 893 + 894 + '@atcute/cid@2.4.1': 895 + dependencies: 896 + '@atcute/multibase': 1.1.8 897 + '@atcute/uint8array': 1.1.1 898 + 899 + '@atcute/client@4.2.1': 900 + dependencies: 901 + '@atcute/identity': 1.1.3 902 + '@atcute/lexicons': 1.2.9 903 + 904 + '@atcute/crypto@2.3.0': 905 + dependencies: 906 + '@atcute/multibase': 1.1.8 907 + '@atcute/uint8array': 1.1.1 908 + '@noble/secp256k1': 3.0.0 909 + 910 + '@atcute/identity-resolver@1.2.2(@atcute/identity@1.1.3)': 911 + dependencies: 912 + '@atcute/identity': 1.1.3 913 + '@atcute/lexicons': 1.2.9 914 + '@atcute/util-fetch': 1.0.5 915 + '@badrap/valita': 0.4.6 916 + 917 + '@atcute/identity@1.1.3': 918 + dependencies: 919 + '@atcute/lexicons': 1.2.9 920 + '@badrap/valita': 0.4.6 921 + 922 + '@atcute/lex-cli@2.5.3': 923 + dependencies: 924 + '@atcute/identity': 1.1.3 925 + '@atcute/identity-resolver': 1.2.2(@atcute/identity@1.1.3) 926 + '@atcute/lexicon-doc': 2.1.1 927 + '@atcute/lexicon-resolver': 0.1.6(@atcute/identity-resolver@1.2.2(@atcute/identity@1.1.3))(@atcute/identity@1.1.3) 928 + '@atcute/lexicons': 1.2.9 929 + '@badrap/valita': 0.4.6 930 + '@optique/core': 0.6.11 931 + '@optique/run': 0.6.11 932 + picocolors: 1.1.1 933 + prettier: 3.8.1 934 + 935 + '@atcute/lexicon-doc@2.1.1': 936 + dependencies: 937 + '@atcute/identity': 1.1.3 938 + '@atcute/lexicons': 1.2.9 939 + '@atcute/uint8array': 1.1.1 940 + '@atcute/util-text': 1.1.1 941 + '@badrap/valita': 0.4.6 942 + 943 + '@atcute/lexicon-resolver@0.1.6(@atcute/identity-resolver@1.2.2(@atcute/identity@1.1.3))(@atcute/identity@1.1.3)': 944 + dependencies: 945 + '@atcute/crypto': 2.3.0 946 + '@atcute/identity': 1.1.3 947 + '@atcute/identity-resolver': 1.2.2(@atcute/identity@1.1.3) 948 + '@atcute/lexicon-doc': 2.1.1 949 + '@atcute/lexicons': 1.2.9 950 + '@atcute/repo': 0.1.2 951 + '@atcute/util-fetch': 1.0.5 952 + '@badrap/valita': 0.4.6 953 + 954 + '@atcute/lexicons@1.2.9': 955 + dependencies: 956 + '@atcute/uint8array': 1.1.1 957 + '@atcute/util-text': 1.1.1 958 + '@standard-schema/spec': 1.1.0 959 + esm-env: 1.2.2 960 + 961 + '@atcute/mst@0.1.2': 962 + dependencies: 963 + '@atcute/cbor': 2.3.2 964 + '@atcute/cid': 2.4.1 965 + '@atcute/uint8array': 1.1.1 966 + 967 + '@atcute/multibase@1.1.8': 968 + dependencies: 969 + '@atcute/uint8array': 1.1.1 970 + 971 + '@atcute/oauth-browser-client@3.0.0(@atcute/identity@1.1.3)': 972 + dependencies: 973 + '@atcute/client': 4.2.1 974 + '@atcute/identity-resolver': 1.2.2(@atcute/identity@1.1.3) 975 + '@atcute/lexicons': 1.2.9 976 + '@atcute/multibase': 1.1.8 977 + '@atcute/oauth-crypto': 0.1.0 978 + '@atcute/oauth-types': 0.1.1 979 + nanoid: 5.1.6 980 + transitivePeerDependencies: 981 + - '@atcute/identity' 982 + 983 + '@atcute/oauth-crypto@0.1.0': 984 + dependencies: 985 + '@atcute/multibase': 1.1.8 986 + '@atcute/uint8array': 1.1.1 987 + '@badrap/valita': 0.4.6 988 + nanoid: 5.1.6 989 + 990 + '@atcute/oauth-keyset@0.1.0': 991 + dependencies: 992 + '@atcute/oauth-crypto': 0.1.0 993 + 994 + '@atcute/oauth-types@0.1.1': 995 + dependencies: 996 + '@atcute/identity': 1.1.3 997 + '@atcute/lexicons': 1.2.9 998 + '@atcute/oauth-keyset': 0.1.0 999 + '@badrap/valita': 0.4.6 1000 + 1001 + '@atcute/repo@0.1.2': 1002 + dependencies: 1003 + '@atcute/car': 5.1.1 1004 + '@atcute/cbor': 2.3.2 1005 + '@atcute/cid': 2.4.1 1006 + '@atcute/crypto': 2.3.0 1007 + '@atcute/lexicons': 1.2.9 1008 + '@atcute/mst': 0.1.2 1009 + '@atcute/uint8array': 1.1.1 1010 + 1011 + '@atcute/tid@1.1.2': 1012 + dependencies: 1013 + '@atcute/time-ms': 1.2.3 1014 + 1015 + '@atcute/time-ms@1.2.3': 1016 + dependencies: 1017 + '@types/bun': 1.3.9 1018 + node-gyp-build: 4.8.4 1019 + 1020 + '@atcute/uint8array@1.1.1': {} 1021 + 1022 + '@atcute/util-fetch@1.0.5': 1023 + dependencies: 1024 + '@badrap/valita': 0.4.6 1025 + 1026 + '@atcute/util-text@1.1.1': 1027 + dependencies: 1028 + unicode-segmenter: 0.14.5 1029 + 1030 + '@atcute/varint@2.0.0': {} 1031 + 1032 + '@atproto/syntax@0.4.3': 1033 + dependencies: 1034 + tslib: 2.8.1 1035 + 1036 + '@babel/code-frame@7.28.6': 1037 + dependencies: 1038 + '@babel/helper-validator-identifier': 7.28.5 1039 + js-tokens: 4.0.0 1040 + picocolors: 1.1.1 1041 + 1042 + '@babel/helper-validator-identifier@7.28.5': {} 1043 + 1044 + '@badrap/valita@0.4.6': {} 1045 + 289 1046 '@emnapi/core@1.8.1': 290 1047 dependencies: 291 1048 '@emnapi/wasi-threads': 1.1.0 ··· 312 1069 dependencies: 313 1070 '@essentials/raf': 1.2.0 314 1071 1072 + '@inquirer/ansi@2.0.3': {} 1073 + 1074 + '@inquirer/checkbox@5.0.6(@types/node@25.2.3)': 1075 + dependencies: 1076 + '@inquirer/ansi': 2.0.3 1077 + '@inquirer/core': 11.1.3(@types/node@25.2.3) 1078 + '@inquirer/figures': 2.0.3 1079 + '@inquirer/type': 4.0.3(@types/node@25.2.3) 1080 + optionalDependencies: 1081 + '@types/node': 25.2.3 1082 + 1083 + '@inquirer/confirm@6.0.6(@types/node@25.2.3)': 1084 + dependencies: 1085 + '@inquirer/core': 11.1.3(@types/node@25.2.3) 1086 + '@inquirer/type': 4.0.3(@types/node@25.2.3) 1087 + optionalDependencies: 1088 + '@types/node': 25.2.3 1089 + 1090 + '@inquirer/core@11.1.3(@types/node@25.2.3)': 1091 + dependencies: 1092 + '@inquirer/ansi': 2.0.3 1093 + '@inquirer/figures': 2.0.3 1094 + '@inquirer/type': 4.0.3(@types/node@25.2.3) 1095 + cli-width: 4.1.0 1096 + fast-wrap-ansi: 0.2.0 1097 + mute-stream: 3.0.0 1098 + signal-exit: 4.1.0 1099 + optionalDependencies: 1100 + '@types/node': 25.2.3 1101 + 1102 + '@inquirer/editor@5.0.6(@types/node@25.2.3)': 1103 + dependencies: 1104 + '@inquirer/core': 11.1.3(@types/node@25.2.3) 1105 + '@inquirer/external-editor': 2.0.3(@types/node@25.2.3) 1106 + '@inquirer/type': 4.0.3(@types/node@25.2.3) 1107 + optionalDependencies: 1108 + '@types/node': 25.2.3 1109 + 1110 + '@inquirer/expand@5.0.6(@types/node@25.2.3)': 1111 + dependencies: 1112 + '@inquirer/core': 11.1.3(@types/node@25.2.3) 1113 + '@inquirer/type': 4.0.3(@types/node@25.2.3) 1114 + optionalDependencies: 1115 + '@types/node': 25.2.3 1116 + 1117 + '@inquirer/external-editor@2.0.3(@types/node@25.2.3)': 1118 + dependencies: 1119 + chardet: 2.1.1 1120 + iconv-lite: 0.7.2 1121 + optionalDependencies: 1122 + '@types/node': 25.2.3 1123 + 1124 + '@inquirer/figures@2.0.3': {} 1125 + 1126 + '@inquirer/input@5.0.6(@types/node@25.2.3)': 1127 + dependencies: 1128 + '@inquirer/core': 11.1.3(@types/node@25.2.3) 1129 + '@inquirer/type': 4.0.3(@types/node@25.2.3) 1130 + optionalDependencies: 1131 + '@types/node': 25.2.3 1132 + 1133 + '@inquirer/number@4.0.6(@types/node@25.2.3)': 1134 + dependencies: 1135 + '@inquirer/core': 11.1.3(@types/node@25.2.3) 1136 + '@inquirer/type': 4.0.3(@types/node@25.2.3) 1137 + optionalDependencies: 1138 + '@types/node': 25.2.3 1139 + 1140 + '@inquirer/password@5.0.6(@types/node@25.2.3)': 1141 + dependencies: 1142 + '@inquirer/ansi': 2.0.3 1143 + '@inquirer/core': 11.1.3(@types/node@25.2.3) 1144 + '@inquirer/type': 4.0.3(@types/node@25.2.3) 1145 + optionalDependencies: 1146 + '@types/node': 25.2.3 1147 + 1148 + '@inquirer/prompts@8.2.1(@types/node@25.2.3)': 1149 + dependencies: 1150 + '@inquirer/checkbox': 5.0.6(@types/node@25.2.3) 1151 + '@inquirer/confirm': 6.0.6(@types/node@25.2.3) 1152 + '@inquirer/editor': 5.0.6(@types/node@25.2.3) 1153 + '@inquirer/expand': 5.0.6(@types/node@25.2.3) 1154 + '@inquirer/input': 5.0.6(@types/node@25.2.3) 1155 + '@inquirer/number': 4.0.6(@types/node@25.2.3) 1156 + '@inquirer/password': 5.0.6(@types/node@25.2.3) 1157 + '@inquirer/rawlist': 5.2.2(@types/node@25.2.3) 1158 + '@inquirer/search': 4.1.2(@types/node@25.2.3) 1159 + '@inquirer/select': 5.0.6(@types/node@25.2.3) 1160 + optionalDependencies: 1161 + '@types/node': 25.2.3 1162 + 1163 + '@inquirer/rawlist@5.2.2(@types/node@25.2.3)': 1164 + dependencies: 1165 + '@inquirer/core': 11.1.3(@types/node@25.2.3) 1166 + '@inquirer/type': 4.0.3(@types/node@25.2.3) 1167 + optionalDependencies: 1168 + '@types/node': 25.2.3 1169 + 1170 + '@inquirer/search@4.1.2(@types/node@25.2.3)': 1171 + dependencies: 1172 + '@inquirer/core': 11.1.3(@types/node@25.2.3) 1173 + '@inquirer/figures': 2.0.3 1174 + '@inquirer/type': 4.0.3(@types/node@25.2.3) 1175 + optionalDependencies: 1176 + '@types/node': 25.2.3 1177 + 1178 + '@inquirer/select@5.0.6(@types/node@25.2.3)': 1179 + dependencies: 1180 + '@inquirer/ansi': 2.0.3 1181 + '@inquirer/core': 11.1.3(@types/node@25.2.3) 1182 + '@inquirer/figures': 2.0.3 1183 + '@inquirer/type': 4.0.3(@types/node@25.2.3) 1184 + optionalDependencies: 1185 + '@types/node': 25.2.3 1186 + 1187 + '@inquirer/type@4.0.3(@types/node@25.2.3)': 1188 + optionalDependencies: 1189 + '@types/node': 25.2.3 1190 + 1191 + '@isaacs/fs-minipass@4.0.1': 1192 + dependencies: 1193 + minipass: 7.1.2 1194 + 315 1195 '@napi-rs/wasm-runtime@1.1.1': 316 1196 dependencies: 317 1197 '@emnapi/core': 1.8.1 ··· 319 1199 '@tybys/wasm-util': 0.10.1 320 1200 optional: true 321 1201 1202 + '@noble/secp256k1@3.0.0': {} 1203 + 1204 + '@nodelib/fs.scandir@2.1.5': 1205 + dependencies: 1206 + '@nodelib/fs.stat': 2.0.5 1207 + run-parallel: 1.2.0 1208 + 1209 + '@nodelib/fs.stat@2.0.5': {} 1210 + 1211 + '@nodelib/fs.walk@1.2.8': 1212 + dependencies: 1213 + '@nodelib/fs.scandir': 2.1.5 1214 + fastq: 1.20.1 1215 + 1216 + '@optique/core@0.6.11': {} 1217 + 1218 + '@optique/run@0.6.11': 1219 + dependencies: 1220 + '@optique/core': 0.6.11 1221 + 322 1222 '@oxc-project/types@0.113.0': {} 323 1223 324 1224 '@popperjs/core@2.11.8': {} ··· 408 1308 409 1309 '@rolldown/pluginutils@1.0.0-rc.4': {} 410 1310 1311 + '@sindresorhus/merge-streams@4.0.0': {} 1312 + 1313 + '@standard-schema/spec@1.1.0': {} 1314 + 411 1315 '@tippyjs/react@4.2.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': 412 1316 dependencies: 413 1317 react: 19.2.4 ··· 419 1323 tslib: 2.8.1 420 1324 optional: true 421 1325 1326 + '@typelex/emitter@0.4.0(@typespec/compiler@1.9.0(@types/node@25.2.3))': 1327 + dependencies: 1328 + '@typespec/compiler': 1.9.0(@types/node@25.2.3) 1329 + 1330 + '@types/bun@1.3.9': 1331 + dependencies: 1332 + bun-types: 1.3.9 1333 + 422 1334 '@types/jquery@3.5.33': 423 1335 dependencies: 424 1336 '@types/sizzle': 2.3.10 ··· 427 1339 dependencies: 428 1340 '@types/jquery': 3.5.33 429 1341 1342 + '@types/node@25.2.3': 1343 + dependencies: 1344 + undici-types: 7.16.0 1345 + 430 1346 '@types/sizzle@2.3.10': {} 431 1347 1348 + '@typespec/compiler@1.9.0(@types/node@25.2.3)': 1349 + dependencies: 1350 + '@babel/code-frame': 7.28.6 1351 + '@inquirer/prompts': 8.2.1(@types/node@25.2.3) 1352 + ajv: 8.17.1 1353 + change-case: 5.4.4 1354 + env-paths: 3.0.0 1355 + globby: 16.1.0 1356 + is-unicode-supported: 2.1.0 1357 + mustache: 4.2.0 1358 + picocolors: 1.1.1 1359 + prettier: 3.8.1 1360 + semver: 7.7.4 1361 + tar: 7.5.7 1362 + temporal-polyfill: 0.3.0 1363 + vscode-languageserver: 9.0.1 1364 + vscode-languageserver-textdocument: 1.0.12 1365 + yaml: 2.8.2 1366 + yargs: 18.0.0 1367 + transitivePeerDependencies: 1368 + - '@types/node' 1369 + 1370 + ajv@8.17.1: 1371 + dependencies: 1372 + fast-deep-equal: 3.1.3 1373 + fast-uri: 3.1.0 1374 + json-schema-traverse: 1.0.0 1375 + require-from-string: 2.0.2 1376 + 1377 + ansi-regex@6.2.2: {} 1378 + 1379 + ansi-styles@6.2.3: {} 1380 + 1381 + braces@3.0.3: 1382 + dependencies: 1383 + fill-range: 7.1.1 1384 + 1385 + bun-types@1.3.9: 1386 + dependencies: 1387 + '@types/node': 25.2.3 1388 + 1389 + change-case@5.4.4: {} 1390 + 1391 + chardet@2.1.1: {} 1392 + 1393 + chownr@3.0.0: {} 1394 + 1395 + cli-width@4.1.0: {} 1396 + 1397 + cliui@9.0.1: 1398 + dependencies: 1399 + string-width: 7.2.0 1400 + strip-ansi: 7.1.2 1401 + wrap-ansi: 9.0.2 1402 + 1403 + emoji-regex@10.6.0: {} 1404 + 1405 + env-paths@3.0.0: {} 1406 + 1407 + escalade@3.2.0: {} 1408 + 1409 + esm-env@1.2.2: {} 1410 + 1411 + fast-deep-equal@3.1.3: {} 1412 + 1413 + fast-glob@3.3.3: 1414 + dependencies: 1415 + '@nodelib/fs.stat': 2.0.5 1416 + '@nodelib/fs.walk': 1.2.8 1417 + glob-parent: 5.1.2 1418 + merge2: 1.4.1 1419 + micromatch: 4.0.8 1420 + 1421 + fast-string-truncated-width@3.0.3: {} 1422 + 1423 + fast-string-width@3.0.2: 1424 + dependencies: 1425 + fast-string-truncated-width: 3.0.3 1426 + 1427 + fast-uri@3.1.0: {} 1428 + 1429 + fast-wrap-ansi@0.2.0: 1430 + dependencies: 1431 + fast-string-width: 3.0.2 1432 + 1433 + fastq@1.20.1: 1434 + dependencies: 1435 + reusify: 1.1.0 1436 + 1437 + fill-range@7.1.1: 1438 + dependencies: 1439 + to-regex-range: 5.0.1 1440 + 1441 + get-caller-file@2.0.5: {} 1442 + 1443 + get-east-asian-width@1.4.0: {} 1444 + 1445 + glob-parent@5.1.2: 1446 + dependencies: 1447 + is-glob: 4.0.3 1448 + 1449 + globby@16.1.0: 1450 + dependencies: 1451 + '@sindresorhus/merge-streams': 4.0.0 1452 + fast-glob: 3.3.3 1453 + ignore: 7.0.5 1454 + is-path-inside: 4.0.0 1455 + slash: 5.1.0 1456 + unicorn-magic: 0.4.0 1457 + 1458 + iconv-lite@0.7.2: 1459 + dependencies: 1460 + safer-buffer: 2.1.2 1461 + 1462 + ignore@7.0.5: {} 1463 + 1464 + is-extglob@2.1.1: {} 1465 + 1466 + is-glob@4.0.3: 1467 + dependencies: 1468 + is-extglob: 2.1.1 1469 + 1470 + is-number@7.0.0: {} 1471 + 1472 + is-path-inside@4.0.0: {} 1473 + 1474 + is-unicode-supported@2.1.0: {} 1475 + 1476 + js-tokens@4.0.0: {} 1477 + 1478 + json-schema-traverse@1.0.0: {} 1479 + 1480 + kitty-agent@10.0.0(@atcute/atproto@3.1.10)(@atcute/cid@2.4.1)(@atcute/client@4.2.1)(@atcute/identity-resolver@1.2.2(@atcute/identity@1.1.3))(@atcute/identity@1.1.3)(@atcute/lexicons@1.2.9)(@atcute/oauth-browser-client@3.0.0(@atcute/identity@1.1.3))(@atproto/syntax@0.4.3): 1481 + dependencies: 1482 + '@atcute/atproto': 3.1.10 1483 + '@atcute/cid': 2.4.1 1484 + '@atcute/client': 4.2.1 1485 + '@atcute/identity': 1.1.3 1486 + '@atcute/identity-resolver': 1.2.2(@atcute/identity@1.1.3) 1487 + '@atcute/lexicons': 1.2.9 1488 + '@atcute/oauth-browser-client': 3.0.0(@atcute/identity@1.1.3) 1489 + '@atproto/syntax': 0.4.3 1490 + 432 1491 lz-string@1.5.0: {} 433 1492 434 1493 masonic@4.1.0(react@19.2.4): ··· 446 1505 react: 19.2.4 447 1506 trie-memoize: 1.2.0 448 1507 1508 + merge2@1.4.1: {} 1509 + 1510 + micromatch@4.0.8: 1511 + dependencies: 1512 + braces: 3.0.3 1513 + picomatch: 2.3.1 1514 + 1515 + minipass@7.1.2: {} 1516 + 1517 + minizlib@3.1.0: 1518 + dependencies: 1519 + minipass: 7.1.2 1520 + 1521 + mustache@4.2.0: {} 1522 + 1523 + mute-stream@3.0.0: {} 1524 + 1525 + nanoid@5.1.6: {} 1526 + 1527 + node-gyp-build@4.8.4: {} 1528 + 1529 + picocolors@1.1.1: {} 1530 + 1531 + picomatch@2.3.1: {} 1532 + 449 1533 preact-portal@1.1.3(preact@10.28.3): 450 1534 dependencies: 451 1535 preact: 10.28.3 452 1536 453 1537 preact@10.28.3: {} 454 1538 1539 + prettier@3.8.1: {} 1540 + 455 1541 qfs-compression@0.2.3: {} 1542 + 1543 + queue-microtask@1.2.3: {} 456 1544 457 1545 raf-schd@4.0.3: {} 458 1546 ··· 469 1557 470 1558 react@19.2.4: {} 471 1559 1560 + require-from-string@2.0.2: {} 1561 + 1562 + reusify@1.1.0: {} 1563 + 472 1564 rolldown@1.0.0-rc.4: 473 1565 dependencies: 474 1566 '@oxc-project/types': 0.113.0 ··· 488 1580 '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.4 489 1581 '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.4 490 1582 1583 + run-parallel@1.2.0: 1584 + dependencies: 1585 + queue-microtask: 1.2.3 1586 + 1587 + safer-buffer@2.1.2: {} 1588 + 491 1589 scheduler@0.27.0: {} 492 1590 1591 + semver@7.7.4: {} 1592 + 1593 + signal-exit@4.1.0: {} 1594 + 1595 + slash@5.1.0: {} 1596 + 1597 + string-width@7.2.0: 1598 + dependencies: 1599 + emoji-regex: 10.6.0 1600 + get-east-asian-width: 1.4.0 1601 + strip-ansi: 7.1.2 1602 + 1603 + strip-ansi@7.1.2: 1604 + dependencies: 1605 + ansi-regex: 6.2.2 1606 + 1607 + tar@7.5.7: 1608 + dependencies: 1609 + '@isaacs/fs-minipass': 4.0.1 1610 + chownr: 3.0.0 1611 + minipass: 7.1.2 1612 + minizlib: 3.1.0 1613 + yallist: 5.0.0 1614 + 1615 + temporal-polyfill@0.3.0: 1616 + dependencies: 1617 + temporal-spec: 0.3.0 1618 + 1619 + temporal-spec@0.3.0: {} 1620 + 493 1621 tippy.js@6.3.7: 494 1622 dependencies: 495 1623 '@popperjs/core': 2.11.8 496 1624 1625 + to-regex-range@5.0.1: 1626 + dependencies: 1627 + is-number: 7.0.0 1628 + 497 1629 trie-memoize@1.2.0: {} 498 1630 499 - tslib@2.8.1: 500 - optional: true 1631 + tslib@2.8.1: {} 501 1632 502 1633 typescript@6.0.0-dev.20260213: {} 1634 + 1635 + undici-types@7.16.0: {} 1636 + 1637 + unicode-segmenter@0.14.5: {} 1638 + 1639 + unicorn-magic@0.4.0: {} 1640 + 1641 + vscode-jsonrpc@8.2.0: {} 1642 + 1643 + vscode-languageserver-protocol@3.17.5: 1644 + dependencies: 1645 + vscode-jsonrpc: 8.2.0 1646 + vscode-languageserver-types: 3.17.5 1647 + 1648 + vscode-languageserver-textdocument@1.0.12: {} 1649 + 1650 + vscode-languageserver-types@3.17.5: {} 1651 + 1652 + vscode-languageserver@9.0.1: 1653 + dependencies: 1654 + vscode-languageserver-protocol: 3.17.5 1655 + 1656 + wrap-ansi@9.0.2: 1657 + dependencies: 1658 + ansi-styles: 6.2.3 1659 + string-width: 7.2.0 1660 + strip-ansi: 7.1.2 1661 + 1662 + y18n@5.0.8: {} 1663 + 1664 + yallist@5.0.0: {} 1665 + 1666 + yaml@2.8.2: {} 1667 + 1668 + yargs-parser@22.0.0: {} 1669 + 1670 + yargs@18.0.0: 1671 + dependencies: 1672 + cliui: 9.0.1 1673 + escalade: 3.2.0 1674 + get-caller-file: 2.0.5 1675 + string-width: 7.2.0 1676 + y18n: 5.0.8 1677 + yargs-parser: 22.0.0
+2
pnpm-workspace.yaml
··· 1 + overrides: 2 + '@typelex/cli': link:../../AppData/Local/pnpm/global/5/node_modules/@typelex/cli
+2 -1
public/.wispignore
··· 1 - *.ts 1 + *.ts 2 + *.tsx
+41
public/atproto/client.ts
··· 1 + import type { KittyAgent } from "kitty-agent"; 2 + import { IoGitlabKinklistKinklistProfile } from "../lexicons"; 3 + import { Did } from "@atcute/lexicons"; 4 + 5 + export class KinklistClient { 6 + constructor(private readonly loginState: { 7 + readonly handle: string; 8 + readonly did: Did; 9 + readonly pds: string; 10 + readonly agent: KittyAgent; 11 + }) {} 12 + 13 + get agent(): KittyAgent { 14 + return this.loginState.agent; 15 + } 16 + 17 + get user() { 18 + return this.loginState; 19 + } 20 + 21 + async createOrUpdateProfile(profile: Omit<IoGitlabKinklistKinklistProfile.Main, "createdAt" | "updatedAt" | "$type">) { 22 + const { cid, value } = await this.agent.tryGetRecord({ 23 + collection: 'io.gitlab.kinklist.kinklist.profile', 24 + repo: this.user.did, 25 + rkey: 'self' 26 + }); 27 + 28 + await this.agent.put({ 29 + collection: 'io.gitlab.kinklist.kinklist.profile', 30 + repo: this.user.did, 31 + rkey: 'self', 32 + record: { 33 + $type: 'io.gitlab.kinklist.kinklist.profile', 34 + ...profile, 35 + createdAt: value?.createdAt ?? new Date().toISOString(), 36 + updatedAt: new Date().toISOString(), 37 + }, 38 + swapRecord: cid ?? undefined, 39 + }); 40 + } 41 + }
+21
public/atproto/signed-in-user.ts
··· 1 + import { StatefulPreactOAuthClient } from "kitty-agent/oauth-preact"; 2 + import { KinklistClient } from "./client"; 3 + import { computed, signal } from "@preact/signals"; 4 + 5 + import metadata from '../client-metadata.json' with { type: 'json' }; 6 + 7 + export const oauthClient = new StatefulPreactOAuthClient<KinklistClient>( 8 + { 9 + clientId: metadata.client_id, 10 + redirectUri: metadata.redirect_uris[0], 11 + scope: metadata.scope, 12 + }, 13 + { 14 + computed, 15 + signal, 16 + }, 17 + (loginState) => new KinklistClient(loginState), 18 + ); 19 + 20 + export const user = oauthClient.user; 21 + export const savedHandle = oauthClient.handle;
+18 -9
public/base.ts
··· 1 + export const enum Choice { 2 + Favorite = "favorite", 3 + Like = "like", 4 + Maybe = "maybe", 5 + No = "no", 6 + NotEntered = "not-entered", 7 + Okay = "okay", 8 + WantToTry = "want-to-try" 9 + } 1 10 2 - /** @type {[id: string, name: string, color: string][]} */ 3 - export const choiceOptions: [id: string, name: string, color: string][] = [ 4 - ['not-entered', 'Not Entered', '#FFFFFF'], 5 - ['favorite', 'Favorite', '#6DB5FE'], 6 - ['like', 'Like', '#23FD22'], 7 - ['okay', 'Okay', '#FDFD6B'], 8 - ['maybe', 'Maybe', '#DB6C00'], 9 - ['no', 'No', '#920000'], 10 - ['try', 'Want To Try', 'pattern'], 11 + /** @type {[id: Choice, name: string, color: string][]} */ 12 + export const choiceOptions: [id: Choice, name: string, color: string][] = [ 13 + [Choice.NotEntered, 'Not Entered', '#FFFFFF'], 14 + [Choice.Favorite, 'Favorite', '#6DB5FE'], 15 + [Choice.Like, 'Like', '#23FD22'], 16 + [Choice.Okay, 'Okay', '#FDFD6B'], 17 + [Choice.Maybe, 'Maybe', '#DB6C00'], 18 + [Choice.No, 'No', '#920000'], 19 + [Choice.WantToTry, 'Want To Try', 'pattern'], 11 20 ]; 12 21 export const choiceOptionIndices = Object.fromEntries(choiceOptions.map(([id], i) => [id, i]));
+12
public/client-metadata.json
··· 1 + { 2 + "client_id": "https://kinklist.wisp.place/client-metadata.json", 3 + "client_name": "atpaste", 4 + "client_uri": "https://kinklist.wisp.place/", 5 + "redirect_uris": ["https://kinklist.wisp.place/oauth-redirect.html", "https://kinklist.github.io/oauth-redirect.html", "https://sites.wisp.place/did:plc:nmc77zslrwafxn75j66mep6o/kinklist/oauth-redirect.html"], 6 + "scope": "atproto repo:io.gitlab.kinklist.kinklist.profile", 7 + "grant_types": ["authorization_code", "refresh_token"], 8 + "response_types": ["code"], 9 + "token_endpoint_auth_method": "none", 10 + "application_type": "web", 11 + "dpop_bound_access_tokens": true 12 + }
+3 -3
public/exporter.ts
··· 28 28 // Circles 29 29 for (let i = 0; i < drawCall.data.choices.length; i++) { 30 30 const choice = drawCall.data.choices[i]; 31 - const color = choiceOptions.find(e => e[0] == choice)[2]; 31 + const color = choiceOptions.find(e => e[0] == choice)![2]; 32 32 33 33 x = 10 + drawCall.x + (i * 20); 34 34 y = drawCall.y - 10; ··· 67 67 canvas.width = width; 68 68 canvas.height = height; 69 69 70 - const context = canvas.getContext('2d'); 70 + const context = canvas.getContext('2d')!; 71 71 context.fillStyle = '#FFFFFF'; 72 72 context.fillRect(0, 0, canvas.width, canvas.height); 73 73 ··· 75 75 context.fillStyle = '#000000'; 76 76 context.fillText('Kinklist', 5, 25); 77 77 78 - const pattern = context.createPattern(patternImg, 'repeat'); 78 + const pattern = context.createPattern(patternImg, 'repeat')!; 79 79 80 80 drawLegend(context, pattern); 81 81 return { context, canvas, pattern };
+1 -400
public/index.html
··· 45 45 detectColorScheme(); 46 46 </script> 47 47 48 - <style> 49 - /* Fix bulma-prefers-dark table cells not fitting vanilla bulma layout */ 50 - /* @media (prefers-color-scheme: dark) { */ 51 - /* .table td, .table th { */ 52 - /* border-width: 0 0 1px; */ 53 - /* } */ 54 - /* } */ 55 - html.theme-dark .table td, html.theme-dark .table th { 56 - border-width: 0 0 1px; 57 - } 58 - 59 - /* Display table vertically. Matches Bulma's threshold for stacking columns vertically. */ 60 - @media screen and (max-width: 1023px) { 61 - .kinks-table tr { display: flex; float: left; width: 100%; flex-flow: column; } 62 - .kinks-table td { display: block; } /* Had th, see below for what we actually do */ 63 - 64 - /* Size choice button as a square that takes up the whole space */ 65 - .choice { 66 - width: 100%; 67 - } 68 - .choice:after { 69 - content: ""; 70 - display: block; 71 - padding-bottom: 100%; 72 - } 73 - 74 - .kinks-legend .choice { 75 - width: 32px; 76 - height: 32px; 77 - } 78 - 79 - .kinks-table td:last-child { 80 - /* Place the kink label before the options */ 81 - order: -1; 82 - /* Hide the border for the kink label */ 83 - border-bottom: none !important; 84 - } 85 - 86 - /* Due to the display:block above the table headers will not match the vertical layout. So we put them side-by-side (and then make them look pretty) */ 87 - .kinks-table th { 88 - display: inline-block; 89 - } 90 - 91 - /* They're side-by-side, but we still need to remove the padding to make it seem as one single element */ 92 - .kinks-table th:not(:first-child) { 93 - padding-left: 0; 94 - } 95 - .kinks-table th:not(:last-child) { 96 - padding-right: 0; 97 - } 98 - /* Then, we add a comma separating them. */ 99 - .kinks-table th:not(:last-child)::after { 100 - content: ', '; 101 - white-space: pre; 102 - } 103 - 104 - /* Now we have to add the Self/Partner text to each set of choices so the reader doesn't get confused. */ 105 - /* This is only applied when there is more than one choice. */ 106 - /* https://stackoverflow.com/a/12198561 */ 107 - .kinks-table:not([data-num-participants="1"]) td::before { /* We have to set this manually for every table. */ 108 - color: #363636; 109 - font-style: italic; 110 - content: attr(data-choice-type); /* We have to set this manually for every td. */ 111 - } 112 - } 113 - @media screen and (min-width: 1024px) { 114 - .choice { 115 - width: 16px; 116 - height: 16px; 117 - } 118 - 119 - /* Make the table stretch out to the entire available width for the outer masonry element. This may be a hack. */ 120 - .kinks-table td:last-child { 121 - width: 100%; /* Stretches out the last column as far as possible, which the browser limits to the masonry's width */ 122 - } 123 - .kinks-table { 124 - margin-right: 1rem; /* Adds a small margin to the table so they don't all touch each other */ 125 - } 126 - } 127 - 128 - .column { 129 - margin-right: 1% !important; 130 - } 131 - 132 - kinks { 133 - display: none !important; 134 - } 135 - 136 - /* Margin in between choices */ 137 - .choices .columns.is-gapless .column:not(:last-child) { 138 - margin-right: 3px !important; 139 - } 140 - 141 - .choice { 142 - padding: 0; 143 - font-size: 0; 144 - outline: none; 145 - border: 1px solid black; 146 - border-radius: 50%; 147 - transition: opacity 0.3s ease-in-out; 148 - vertical-align: middle; 149 - opacity: 0.35; 150 - cursor: pointer; 151 - } 152 - 153 - .choice:not([disabled]):hover { 154 - opacity: 0.7; 155 - } 156 - 157 - .choice[disabled] { 158 - cursor: inherit; 159 - } 160 - 161 - .choice.selected { 162 - opacity: 1; 163 - border-width: 2px; 164 - } 165 - 166 - .choice.not-entered { background-color: #FFFFFF; } 167 - .choice.favorite { background-color: #6DB5FE; } 168 - .choice.like { background-color: #23FD22; } 169 - .choice.okay { background-color: #FDFD6B; } 170 - .choice.maybe { background-color: #DB6C00; } 171 - .choice.no { background-color: #920000; } 172 - .choice.try { 173 - background-color: white; 174 - background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxNScgaGVpZ2h0PScxNSc+CiAgPHJlY3Qgd2lkdGg9JzE1JyBoZWlnaHQ9JzE1JyBmaWxsPSd3aGl0ZScvPgogIDxwYXRoIGQ9J00tMSwxIGwyLC0yCiAgICAgICAgICAgTTAsNSBsMTUsLTE1CiAgICAgICAgICAgTTAsMTAgbDE1LC0xNQogICAgICAgICAgIE0wLDE1IGwxNSwtMTUKICAgICAgICAgICBNMCwyMCBsMTUsLTE1CiAgICAgICAgICAgTTAsMjUgbDE1LC0xNQogICAgICAgICAgIE0xNCwxNiBsMiwtMicgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxJy8+Cjwvc3ZnPgo=); 175 - background-repeat: repeat; 176 - } 177 - 178 - .kinks-subtitle { 179 - margin-top: 1.5rem; 180 - margin-bottom: 0 !important; 181 - } 182 - 183 - .kinks-section { 184 - padding-top: 0; 185 - } 186 - 187 - /* Legend: Bulma's Level does not come with margins by default. We pad the inner element instead. */ 188 - .kinks-legend { 189 - padding-left: 12px; 190 - } 191 - 192 - /* Margin between the choice button reference and the text that describes it */ 193 - .kinks-legend .choice { 194 - margin-right: 4px; 195 - } 196 - 197 - /* Increases margin between elements, matching Bulma's behavior to only do anything when not displaying vertically */ 198 - @media screen and (min-width: 769px) { 199 - .kinks-legend > .level-item { 200 - margin-right: 1rem !important; 201 - } 202 - } 203 - 204 - .has-description { 205 - text-decoration: underline; 206 - text-decoration-style: dotted; 207 - } 208 - 209 - .has-subtitle-description { 210 - font-size: 70%; 211 - 212 - 213 - background-image: linear-gradient(to right, black 33%, rgba(255,255,255,0) 0%); 214 - background-position: bottom; 215 - background-size: 3px 1px; 216 - background-repeat: repeat-x; 217 - } 218 - 219 - /* Use white-colored border for choice buttons when dark theme is enabled */ 220 - html.theme-dark .choice { 221 - border-color: white; 222 - } 223 - </style> 224 - 225 - <kinks> 226 - #Bodies 227 - (Self, Partner) 228 - * Skinny 229 - * Chubby 230 - * Hyper ? Unrealistically gigantic proportions, either in body size or muscle. 231 - * Twink ? Slim to average-looking masculine participants, generally younger. 232 - * Bear ? Larger, generally hairier masculine participants. 233 - * Breasts (in general) ? Individuals that have breasts. 234 - * Penis (in general) ? Individuals that have a penis. 235 - * Vagina (in general) ? Individuals that have a vagina. 236 - * Both genitals ? Both a penis and a vagina, at the same time. 237 - * Small breasts ? Specifically small breasts. 238 - * Large breasts ? Specifically large (but humanly possible) breasts. 239 - * Hyper breasts ? Unrealistically large breasts. 240 - * Small cocks ? Specifically small cocks. 241 - * Large cocks ? Specifically large (but humanly possible) cocks. 242 - * Hyper cocks ? Unrealistically large cocks. 243 - * Beard ? Presence of noticeable facial hair. 244 - * Hairy body ? Presence of noticeable body hair. 245 - * Shaven body ? Lack of noticeable body hair. 246 - 247 - #Clothing 248 - (Self, Partner) 249 - * Clothed sex 250 - * Skirts 251 - * Lingerie 252 - * Stockings 253 - * Heels 254 - * Leather 255 - * Latex 256 - * Uniform / costume 257 - * Zettai ryoiki ? Miniskirt or shorts, with overknee socks, showing a gap of skin between the skirt and socks. 258 - * Gothic ? Dark, mysterious fashion style, sometimes referring to Victorian clothing style. 259 - * Bodysuits 260 - * Cross-dressing ? Participants dressing with clothing typical of a gender opposite to that which they identify as. 261 - * Animal ears ? Can refer to wearing a headband with animal ears or the presence of characters with animal ears in roleplay. 262 - * Piercings ? Presence of piercings, such as facial, or genital. 263 - * Nipple piercings ? Presence of piercings specifically on the nipples. 264 - 265 - #Interactions & Groupings ? What kind of participants you are interested in having sexual interactions with, in addition to yourself, and what kind of sexual encounters you are interested in. 266 - (General) 267 - * You and 1 male 268 - * You and 1 female 269 - * You and 1 enby 270 - * You and MtF trans 271 - * You and FtM trans 272 - * You and 1 male, 1 female 273 - * You and 2 males 274 - * You and 2 females 275 - * You and 2 enby 276 - * Group sex ? Sexual interactions with more partners than listed here. 277 - * ERPing ? Your interest in taking part in erotic role-play. 278 - 279 - #General 280 - (Giving, Receiving) 281 - * Romance / Affection ? Affectionate interactions typically within a sexual context, such as cuddling. 282 - * Handjob / Fingering ? Stimulation of the genitals using the hands. 283 - * Blowjob / Cunnilingus ? Stimulation of the genitals using the tongue or lips. 284 - * Deepthroat ? A type of blowjob where the receiving participant has most of the penis in their mouth. 285 - * Swallowing ? Swallowing semen. 286 - * Facials ? The act of ejaculating on a participant's face. 287 - * Face-sitting 288 - * Edging 289 - * Teasing 290 - * JOI, SI ? "Jack-off instruction" or "Squirt instruction", Involves a participant "instructing" the audience how and when to stroke and how/when to ejaculate while often teasing or performing other sexual acts. 291 - 292 - #Butt play 293 - (Giving, Receiving) 294 - * Anal sex 295 - * Rimming ? A participant using their tongue on the anal rim of another person in order to gain and/or give sexual pleasure. 296 - * Double penetration 297 - * Anal fisting 298 - 299 - #Restrictive 300 - (Self, Partner) 301 - * Gag 302 - * Collar 303 - * Leash 304 - * Blindfold 305 - * Gas mask 306 - * Chastity ? Bondage toys with the intention of making a participant unable to receive physical sexual pleasure. 307 - * Rope bondage / Kinbaku ? Tying a participant with ropes with the intention of restricting movement, sometimes using patterns which are simple yet visually intricate. 308 - * Suspension bondage ? A form of sexual bondage where a bound person is hung from one or more overhead suspension points, typically with rope. 309 - * Bondage (Light) ? Bondage involving softer and more comfortable materials and less restrictive ties. 310 - * Bondage (Heavy) ? Bondage involving very restrictive materials or materials that cover most of the body, giving the participant very little wiggle room. 311 - * Cages ? Refers to a participant being in a cage, such as a steel cage, wooden box, or other type of container intended to be restrictive. This differs from encasement in that the participant is still able to move inside the cage. 312 - * Encasement ? Refers to part of a participant's body being encased in a very restrictive material, giving them no room to move. This can include sensory deprivation play. 313 - 314 - #Toys 315 - (Self, Partner) 316 - * Dildos 317 - * Dragon dildo ? A dildo resembling a dragon, or other fictional creature's penis. 318 - * Horse dildo ? A dildo resembling an equine penis. 319 - * Gaping ? Inserting a large object in the participant's anus (such as a dildo), and then removing it quickly leaving the anus temporarily stretched open. 320 - * Butt plug 321 - * Tail plug ? A kind of butt plug with an animal-styled tail at the end. 322 - * Anal beads 323 - * Vibrators 324 - * Sounding ? The act of sticking toys into the urethra. 325 - 326 - #Domination ? In this section, "dominant" refers to the participant performing the actions to the submissive participant. 327 - (Dominant, Submissive) 328 - * Dominant / Submissive ? Involves roleplay where parties takes pleasure or erotic enjoyment from either dominating or being dominated. 329 - * Domestic servitude ? Can refer to maid/master roleplay, but also the act of the dominant party making the submissive participant perform a household act such as cleaning or washing dishes. 330 - * Slavery ? Sex slavery roleplay, an extension of domestic servitude to sex acts. Can involve degradation and non-con play elements, but not always. 331 - * Pet play ? Roleplay where one participant pretends to be a pet, and the other participant is their owner. Can be oriented to degradation or affection, as some participants may enjoy the thought of being cared for like a pet. 332 - * Daddy/Mommy ? Calling your partner daddy/mommy or having your partner call you daddy/mommy. This is not inherently related to incest or ageplay. 333 - * Discipline ? When a dominant party sets rules for the submissive party to follow, and punishes them if they don't. The submissive party may purposefully choose to break the rules in order to receive sexual gratification through punishment. 334 - * Begging ? When a submissive party begs the dominant party for sex or punishment. The dominant party may receive pleasure from the thought of being begged for. 335 - * Forced orgasm ? When the dominant party takes the submissive party to orgasm by force, typically meaning resistance leading to a very intense orgasm. 336 - * Orgasm control ? When the dominant party controls when the submissive party is allowed to orgasm, regardless of the sexual intercourse they're partaking in. This can involve edging, suddenly stopping sex, or the submissive party begging for orgasm, or punishing the submissive party for orgasming. 337 - * Orgasm denial ? A subset of orgasm control, when the dominant party prevents the submissive party from orgasming, by way of edging, or punishing them if they orgasm. 338 - * Power exchange ? When the dominant party allows the submissive party to do normally dominant acts, while still remaining submissive. 339 - * Neglect play ? Can refer to the dominant party purposefully refusing to have sex with the submissive party for the purposes of dominance, or leaving the submissive party tied up/with a vibrator on, while not interacting with them. 340 - * Fear play ? When the submissive party intentionally disorients themselves, often including wearing a blindfold, in order to reduce spatial awareness and induce anxiety, raising adrenaline levels, which can lead to more intense sexual enjoyment. 341 - * Breathplay ? Refers to any kind of play where the submissive party has their ability to breathe controlled by the dominant party, such as by covering the submissive party's mouth and nose, or using a towel on their face. 342 - * Choking ? Refers to specifically breathplay through choking. 343 - * Water bondage (w/o breath control) ? A form of sexual restraint common in BDSM where water is used for play in addition to other restraints. Water bondage involves restraining the submissive and either spraying them or dunking them into a body of water. This entry refers to water play where the participant's head is not under water. 344 - * Water bondage (breath control) ? A combination of water play and breathplay where the submissive party is held underwater, having to hold their breath until the dominant party lets them breathe again. 345 - * Hypnoplay / Erotic Hypnosis ? A type of roleplay where a party is hypnotized into a state of trance, where they can then be induced to temporarily feel different, or feel like they are someone or something else. 346 - * Droneplay ? Droneplay or dronification is a kind of hypnoplay where a submissive party (referred to as a drone) wears latex and a gas mask, and a dominant party (referred to as a programmer) hypnotizes ("reprograms") the drone into feeling like an obedient, mindless drone. Droneplay can involve aspects of degradation and dehumanization. 347 - 348 - #Fantasy / Characters ? Entries here can refer to having a sexual attraction to characters fitting the descriptions, or wanting to roleplay as them/with them. 349 - (Self, Partner) 350 - * Nekomimi / Cat features ? Human character with cat features, such as ears and a tail. 351 - * Kitsunemimi / Fox features ? Human character with fox features, such as ears and a tail. Fox ears are larger and pointier than cat ears, and fox tails are wider and fluffier. 352 - * Kemonomimi / Animal features ? Human character with features of any animal, such as wolf, cows etc. 353 - * Furry ? Anthropomorphic animal characters, which may include fursuits. 354 - * Cows ? A subset of furry specifically for anthropomorphic bovine characters. 355 - * Rodents ? A subset of furry specifically for anthropomorphic rodent characters (rats, etc.). 356 - * Animal Crossing characters ? A subset of furry specifically for Animal Crossing characters, or characters based on them 357 - * Clowns 358 - 359 - #Fantasy / Interactions 360 - (Self, Partner) 361 - * Vore ? Short for "voraphilia" or "vorarephilia", the fantasy of being eaten alive whole, or eating another creature alive whole. 362 - * Digestion ? A subset of vore where a creature, after being eaten, is digested in the other creature's stomach, or relevant body part. This can later involve the creature that was eaten being brought back. 363 - * Transformation ? Sexual attraction to the fantasy of being transformed into an object, or a different creature. 364 - * Bimbofication ? The fantasy of being turned into an airheaded, skimpy slut who adores sex. 365 - * Inflation ? A fantasy involving the belly of a participant being inflated like a balloon, by being pumped with air or fluid. 366 - * Growth ? A fantasy involving a participant growing without being related to inflation. This can be a result of eating or some other fictional elixir. 367 - * Macrophilia ? The sexual fetish of being an unrealistically large giant/giantess or being around a giant/giantess. 368 - * Microphilia ? The sexual fetish of being an unrealistically tiny person or being around one. 369 - * Tentacles ? Sexual interactions with fantasy creatures that possess phallic-shaped tentacles intended for sex. The tentacles can also be used to restrain the person being fucked. Sometimes the tentacles can have suction cups or other accessory parts, and can include oviposition. 370 - * Consentacles ? A subtype of tentacle fetish where the character being fucked by the tentacles is willing and welcoming. This can involve the tentacle creature and the character being friends. 371 - * Oviposition ? A kink that involves laying eggs into someone, usually involving aliens, bugs, tentacles, etc. Can be related to inflation. 372 - * Monster or alien ? Any character that is some kind of non-earthly monster or alien creature. 373 - * Living clothes ? Refers to when a person is wearing a creature on them, like clothes, but with a living creature. The creature can then be implied to sexually please the person wearing them. 374 - * Force-feeding ? The fantasy of a dominant participant repeatedly feeding the submissive participant, often for the purposes of weight gain. 375 - * Dullahan / Detachable head ? The fantasy of having a detachable head that can be removed and put back on without hurting the character. 376 - * Detachable body parts (not head) ? The fantasy of having detachable body parts that can function despite being detached, and can be removed without dismemberment. 377 - * Clone / selfcest ? Having sex with a clone of someone or yourself; not the same as masturbation. 378 - 379 - #Fantasy / Con-non-con ? Consensual non-con, sometimes known as rapeplay, is a type of sexual roleplay where an aggressor pretends to "forcibly" have sex with the other participant. This interaction is fully consensual and both parties are willing and aware of what's going on. 380 - (Aggressor, Target) 381 - * Non-con / rape 382 - * Mindbreak ? A furthering of non-con where a target participant no longer exhibits thought or logical thinking after being induced to repeated or intense sex. 383 - * Blackmail / coercion 384 - * Kidnapping 385 - * Drugs / alcohol ? Interactions involving the target being drugged, under the influence or intoxicated. The target participant doesn't have to actually be under the influence for this to apply. 386 - * Sleep play ? Roleplay involving sex where one party pretends to be asleep. 387 - * Slavery play ? Sex slavery roleplay, but with an implied aspect of non-con to the interactions. Unlike the entry for Slavery in the Domination section, this always implies non-con and the person may wish not to appear to be enjoying the context. 388 - 389 - #Fantasy / Taboo 390 - (General) 391 - * Incest ? The fantasy that the participant you're having a sexual interaction with is part of your immediate family. 392 - * Exhibitionism ? The act of having sexual interactions in public or out in the open, even if nobody's around. 393 - * Voyeurism ? The fantasy of peeping on your partner while they don't know you're looking. 394 - 395 - #Fluids 396 - (General) 397 - * Blood ? Sexual arousal derived from the sight of blood. 398 - * Watersports ? Sexual interactions involving urine and urination. 399 - * Lactation ? Sexual interactions involving lactation and breast milk. 400 - * Cum play ? Sexual interactions such as licking someone clean after ejaculation, holding or smearing cum. 401 - * Excessive cum ? Sexual arousal from the presence of unrealistically large amounts of cum, such as a tank full of it. 402 - * Gas (farts etc) ? Sexual arousal derived from the sight of farts. In fantasy situations the farts can have different colors and smell. 403 - * Scat ? Sexual arousal derived from the sight of feces, as well as the act of holding or eating feces. 404 - * Diapers ? Sexual arousal derived from adults wearing diapers, which may or may not be related to watersports/scat. 405 - 406 - #Degradation 407 - (Giving, Receiving) 408 - * Glory hole ? A receiving participant giving a blowjob to someone standing behind a wall, with only their penis visible through a hole. 409 - * Name calling ? Consensual insults/verbal assault. 410 - * Humiliation ? Consensual psychological humiliation performed in order to produce erotic excitement or arousal, involving the receiving partner being demeaned or put into humiliating situations, such as being naked. 411 - * Cleaning up ? The act of being told to clean something by a dominant party after sex, such as bodily fluids (cum, etc.) 412 - 413 - #Touch & Stimulation 414 - (Actor, Subject) 415 - * Cock/Pussy worship ? The sex act of worshipping a partner's genitals, which can be used in foreplay, as an affectionate gesture, or for degradation. 416 - * Ass worship ? The sex act of worshipping a partner's ass, which can be used in foreplay, as an affectionate gesture, or for degradation. 417 - * Foot play 418 - * Tickling 419 - * Sensation play ? Sexual gratification from touching erogenous parts of the body, without penetration. 420 - * Electro stimulation ? Bondage sex play using toys that shock you. 421 - 422 - #Misc. Fetish 423 - (Giving, Receiving) 424 - * Fisting 425 - * Gangbang ? Many people having sex with one person. 426 - * Impregnation ? Sex for the purpose of impregnation, can refer to creampies. 427 - * Pregnancy sex ? Sex during pregnancy. 428 - * Feminization ? Similar to bimbofication, a fantasy of taking a masculine individual and "feminizing" them by making them take on feminine traits or clothing. 429 - * Cuckold / Cuckquean ? The fantasy where someone else cheats on your partner or you cheat on your partner, while all parties are aware of the situation. 430 - 431 - #Pain 432 - (Giving, Receiving) 433 - * Light pain ? Pain play where the pain is not the focus of the interaction, such as lighter slapping and whipping. 434 - * Heavy pain ? Pain play where the pain is heavily the focus of the interaction, and can border on the limit of the receiving party's pain tolerance. 435 - * Nipple clamps 436 - * Clothespins ? Clothespins used on the body or nipples. These can be pulled off for an intense pain feeling. 437 - * Spanking ? Open hand spanking, typically on the butt or face. 438 - * Beating ? Closed fist beating, typically on the belly, face, or butt. 439 - * Flogging ? Whips, or similar instruments used on the body of the receiving party for a pleasuresome pain response. Typically whipping is aimed at the butt, which can be more tolerable for some people. 440 - * Caning ? Hitting or being hit with a cane, which can be very painful, but enjoyable for a masochist partner. 441 - * Cock/Pussy slapping ? Slapping a participant's genitals, not involving other genital torture interactions. 442 - * Cock/Pussy torture ? Genital torture is a sexual activity involving the application of pain or constriction to the genitals, for pleasure by a masochist participant. 443 - * Hot wax ? Holding a burning candle over a participant's body and letting hot wax drip onto their bare skin, leading to a sensation of burning which can be sexually pleasing. 444 - * Scratching ? Love scratches, or any kind of sexually-oriented skin scratching that doesn't draw blood. 445 - * Biting ? Bites, typically on the neck, that don't draw blood. 446 - * Cutting ? Purposefully cutting the skin to draw blood, can refer to knife play but also applies to physical interactions that draw blood in general. 447 - </kinks> 48 + <link rel="stylesheet" href="style.css"> 448 49 </head> 449 50 450 51 <body>
+223
public/kinks.ts
··· 1 + export const kinkText = ` 2 + #Bodies 3 + (Self, Partner) 4 + * Skinny 5 + * Chubby 6 + * Hyper ::: Unrealistically gigantic proportions, either in body size or muscle. 7 + * Twink ::: Slim to average-looking masculine participants, generally younger. 8 + * Bear ::: Larger, generally hairier masculine participants. 9 + * Breasts (in general) ::: Individuals that have breasts. 10 + * Penis (in general) ::: Individuals that have a penis. 11 + * Vagina (in general) ::: Individuals that have a vagina. 12 + * Both genitals ::: Both a penis and a vagina, at the same time. 13 + * Small breasts ::: Specifically small breasts. 14 + * Large breasts ::: Specifically large (but humanly possible) breasts. 15 + * Hyper breasts ::: Unrealistically large breasts. 16 + * Small cocks ::: Specifically small cocks. 17 + * Large cocks ::: Specifically large (but humanly possible) cocks. 18 + * Hyper cocks ::: Unrealistically large cocks. 19 + * Beard ::: Presence of noticeable facial hair. 20 + * Hairy body ::: Presence of noticeable body hair. 21 + * Shaven body ::: Lack of noticeable body hair. 22 + 23 + #Clothing 24 + (Self, Partner) 25 + * Clothed sex 26 + * Skirts 27 + * Lingerie 28 + * Stockings 29 + * Heels 30 + * Leather 31 + * Latex 32 + * Uniform / costume 33 + * Zettai ryoiki ::: Miniskirt or shorts, with overknee socks, showing a gap of skin between the skirt and socks. 34 + * Gothic ::: Dark, mysterious fashion style, sometimes referring to Victorian clothing style. 35 + * Bodysuits 36 + * Cross-dressing ::: Participants dressing with clothing typical of a gender opposite to that which they identify as. 37 + * Animal ears ::: Can refer to wearing a headband with animal ears or the presence of characters with animal ears in roleplay. 38 + * Piercings ::: Presence of piercings, such as facial, or genital. 39 + * Nipple piercings ::: Presence of piercings specifically on the nipples. 40 + 41 + #Interactions & Groupings ::: What kind of participants you are interested in having sexual interactions with, in addition to yourself, and what kind of sexual encounters you are interested in. 42 + (General) 43 + * You and 1 male 44 + * You and 1 female 45 + * You and 1 enby 46 + * You and MtF trans 47 + * You and FtM trans 48 + * You and 1 male, 1 female 49 + * You and 2 males 50 + * You and 2 females 51 + * You and 2 enby 52 + * Group sex ::: Sexual interactions with more partners than listed here. 53 + * ERPing ::: Your interest in taking part in erotic role-play. 54 + 55 + #General 56 + (Giving, Receiving) 57 + * Romance / Affection ::: Affectionate interactions typically within a sexual context, such as cuddling. 58 + * Handjob / Fingering ::: Stimulation of the genitals using the hands. 59 + * Blowjob / Cunnilingus ::: Stimulation of the genitals using the tongue or lips. 60 + * Deepthroat ::: A type of blowjob where the receiving participant has most of the penis in their mouth. 61 + * Swallowing ::: Swallowing semen. 62 + * Facials ::: The act of ejaculating on a participant's face. 63 + * Face-sitting 64 + * Edging 65 + * Teasing 66 + * JOI, SI ::: "Jack-off instruction" or "Squirt instruction", Involves a participant "instructing" the audience how and when to stroke and how/when to ejaculate while often teasing or performing other sexual acts. 67 + 68 + #Butt play 69 + (Giving, Receiving) 70 + * Anal sex 71 + * Rimming ::: A participant using their tongue on the anal rim of another person in order to gain and/or give sexual pleasure. 72 + * Double penetration 73 + * Anal fisting 74 + 75 + #Restrictive 76 + (Self, Partner) 77 + * Gag 78 + * Collar 79 + * Leash 80 + * Blindfold 81 + * Gas mask 82 + * Chastity ::: Bondage toys with the intention of making a participant unable to receive physical sexual pleasure. 83 + * Rope bondage / Kinbaku ::: Tying a participant with ropes with the intention of restricting movement, sometimes using patterns which are simple yet visually intricate. 84 + * Suspension bondage ::: A form of sexual bondage where a bound person is hung from one or more overhead suspension points, typically with rope. 85 + * Bondage (Light) ::: Bondage involving softer and more comfortable materials and less restrictive ties. 86 + * Bondage (Heavy) ::: Bondage involving very restrictive materials or materials that cover most of the body, giving the participant very little wiggle room. 87 + * Cages ::: Refers to a participant being in a cage, such as a steel cage, wooden box, or other type of container intended to be restrictive. This differs from encasement in that the participant is still able to move inside the cage. 88 + * Encasement ::: Refers to part of a participant's body being encased in a very restrictive material, giving them no room to move. This can include sensory deprivation play. 89 + 90 + #Toys 91 + (Self, Partner) 92 + * Dildos 93 + * Dragon dildo ::: A dildo resembling a dragon, or other fictional creature's penis. 94 + * Horse dildo ::: A dildo resembling an equine penis. 95 + * Gaping ::: Inserting a large object in the participant's anus (such as a dildo), and then removing it quickly leaving the anus temporarily stretched open. 96 + * Butt plug 97 + * Tail plug ::: A kind of butt plug with an animal-styled tail at the end. 98 + * Anal beads 99 + * Vibrators 100 + * Sounding ::: The act of sticking toys into the urethra. 101 + 102 + #Domination ::: In this section, "dominant" refers to the participant performing the actions to the submissive participant. 103 + (Dominant, Submissive) 104 + * Dominant / Submissive ::: Involves roleplay where parties takes pleasure or erotic enjoyment from either dominating or being dominated. 105 + * Domestic servitude ::: Can refer to maid/master roleplay, but also the act of the dominant party making the submissive participant perform a household act such as cleaning or washing dishes. 106 + * Slavery ::: Sex slavery roleplay, an extension of domestic servitude to sex acts. Can involve degradation and non-con play elements, but not always. 107 + * Pet play ::: Roleplay where one participant pretends to be a pet, and the other participant is their owner. Can be oriented to degradation or affection, as some participants may enjoy the thought of being cared for like a pet. 108 + * Daddy/Mommy ::: Calling your partner daddy/mommy or having your partner call you daddy/mommy. This is not inherently related to incest or ageplay. 109 + * Discipline ::: When a dominant party sets rules for the submissive party to follow, and punishes them if they don't. The submissive party may purposefully choose to break the rules in order to receive sexual gratification through punishment. 110 + * Begging ::: When a submissive party begs the dominant party for sex or punishment. The dominant party may receive pleasure from the thought of being begged for. 111 + * Forced orgasm ::: When the dominant party takes the submissive party to orgasm by force, typically meaning resistance leading to a very intense orgasm. 112 + * Orgasm control ::: When the dominant party controls when the submissive party is allowed to orgasm, regardless of the sexual intercourse they're partaking in. This can involve edging, suddenly stopping sex, or the submissive party begging for orgasm, or punishing the submissive party for orgasming. 113 + * Orgasm denial ::: A subset of orgasm control, when the dominant party prevents the submissive party from orgasming, by way of edging, or punishing them if they orgasm. 114 + * Power exchange ::: When the dominant party allows the submissive party to do normally dominant acts, while still remaining submissive. 115 + * Neglect play ::: Can refer to the dominant party purposefully refusing to have sex with the submissive party for the purposes of dominance, or leaving the submissive party tied up/with a vibrator on, while not interacting with them. 116 + * Fear play ::: When the submissive party intentionally disorients themselves, often including wearing a blindfold, in order to reduce spatial awareness and induce anxiety, raising adrenaline levels, which can lead to more intense sexual enjoyment. 117 + * Breathplay ::: Refers to any kind of play where the submissive party has their ability to breathe controlled by the dominant party, such as by covering the submissive party's mouth and nose, or using a towel on their face. 118 + * Choking ::: Refers to specifically breathplay through choking. 119 + * Water bondage (w/o breath control) ::: A form of sexual restraint common in BDSM where water is used for play in addition to other restraints. Water bondage involves restraining the submissive and either spraying them or dunking them into a body of water. This entry refers to water play where the participant's head is not under water. 120 + * Water bondage (breath control) ::: A combination of water play and breathplay where the submissive party is held underwater, having to hold their breath until the dominant party lets them breathe again. 121 + * Hypnoplay / Erotic Hypnosis ::: A type of roleplay where a party is hypnotized into a state of trance, where they can then be induced to temporarily feel different, or feel like they are someone or something else. 122 + * Droneplay ::: Droneplay or dronification is a kind of hypnoplay where a submissive party (referred to as a drone) wears latex and a gas mask, and a dominant party (referred to as a programmer) hypnotizes ("reprograms") the drone into feeling like an obedient, mindless drone. Droneplay can involve aspects of degradation and dehumanization. 123 + 124 + #Fantasy / Characters ::: Entries here can refer to having a sexual attraction to characters fitting the descriptions, or wanting to roleplay as them/with them. 125 + (Self, Partner) 126 + * Nekomimi / Cat features ::: Human character with cat features, such as ears and a tail. 127 + * Kitsunemimi / Fox features ::: Human character with fox features, such as ears and a tail. Fox ears are larger and pointier than cat ears, and fox tails are wider and fluffier. 128 + * Kemonomimi / Animal features ::: Human character with features of any animal, such as wolf, cows etc. 129 + * Furry ::: Anthropomorphic animal characters, which may include fursuits. 130 + * Cows ::: A subset of furry specifically for anthropomorphic bovine characters. 131 + * Rodents ::: A subset of furry specifically for anthropomorphic rodent characters (rats, etc.). 132 + * Animal Crossing characters ::: A subset of furry specifically for Animal Crossing characters, or characters based on them 133 + * Clowns 134 + 135 + #Fantasy / Interactions 136 + (Self, Partner) 137 + * Vore ::: Short for "voraphilia" or "vorarephilia", the fantasy of being eaten alive whole, or eating another creature alive whole. 138 + * Digestion ::: A subset of vore where a creature, after being eaten, is digested in the other creature's stomach, or relevant body part. This can later involve the creature that was eaten being brought back. 139 + * Transformation ::: Sexual attraction to the fantasy of being transformed into an object, or a different creature. 140 + * Bimbofication ::: The fantasy of being turned into an airheaded, skimpy slut who adores sex. 141 + * Inflation ::: A fantasy involving the belly of a participant being inflated like a balloon, by being pumped with air or fluid. 142 + * Growth ::: A fantasy involving a participant growing without being related to inflation. This can be a result of eating or some other fictional elixir. 143 + * Macrophilia ::: The sexual fetish of being an unrealistically large giant/giantess or being around a giant/giantess. 144 + * Microphilia ::: The sexual fetish of being an unrealistically tiny person or being around one. 145 + * Tentacles ::: Sexual interactions with fantasy creatures that possess phallic-shaped tentacles intended for sex. The tentacles can also be used to restrain the person being fucked. Sometimes the tentacles can have suction cups or other accessory parts, and can include oviposition. 146 + * Consentacles ::: A subtype of tentacle fetish where the character being fucked by the tentacles is willing and welcoming. This can involve the tentacle creature and the character being friends. 147 + * Oviposition ::: A kink that involves laying eggs into someone, usually involving aliens, bugs, tentacles, etc. Can be related to inflation. 148 + * Monster or alien ::: Any character that is some kind of non-earthly monster or alien creature. 149 + * Living clothes ::: Refers to when a person is wearing a creature on them, like clothes, but with a living creature. The creature can then be implied to sexually please the person wearing them. 150 + * Force-feeding ::: The fantasy of a dominant participant repeatedly feeding the submissive participant, often for the purposes of weight gain. 151 + * Dullahan / Detachable head ::: The fantasy of having a detachable head that can be removed and put back on without hurting the character. 152 + * Detachable body parts (not head) ::: The fantasy of having detachable body parts that can function despite being detached, and can be removed without dismemberment. 153 + * Clone / selfcest ::: Having sex with a clone of someone or yourself; not the same as masturbation. 154 + 155 + #Fantasy / Con-non-con ::: Consensual non-con, sometimes known as rapeplay, is a type of sexual roleplay where an aggressor pretends to "forcibly" have sex with the other participant. This interaction is fully consensual and both parties are willing and aware of what's going on. 156 + (Aggressor, Target) 157 + * Non-con / rape 158 + * Mindbreak ::: A furthering of non-con where a target participant no longer exhibits thought or logical thinking after being induced to repeated or intense sex. 159 + * Blackmail / coercion 160 + * Kidnapping 161 + * Drugs / alcohol ::: Interactions involving the target being drugged, under the influence or intoxicated. The target participant doesn't have to actually be under the influence for this to apply. 162 + * Sleep play ::: Roleplay involving sex where one party pretends to be asleep. 163 + * Slavery play ::: Sex slavery roleplay, but with an implied aspect of non-con to the interactions. Unlike the entry for Slavery in the Domination section, this always implies non-con and the person may wish not to appear to be enjoying the context. 164 + 165 + #Fantasy / Taboo 166 + (General) 167 + * Incest ::: The fantasy that the participant you're having a sexual interaction with is part of your immediate family. 168 + * Exhibitionism ::: The act of having sexual interactions in public or out in the open, even if nobody's around. 169 + * Voyeurism ::: The fantasy of peeping on your partner while they don't know you're looking. 170 + 171 + #Fluids 172 + (General) 173 + * Blood ::: Sexual arousal derived from the sight of blood. 174 + * Watersports ::: Sexual interactions involving urine and urination. 175 + * Lactation ::: Sexual interactions involving lactation and breast milk. 176 + * Cum play ::: Sexual interactions such as licking someone clean after ejaculation, holding or smearing cum. 177 + * Excessive cum ::: Sexual arousal from the presence of unrealistically large amounts of cum, such as a tank full of it. 178 + * Gas (farts etc) ::: Sexual arousal derived from the sight of farts. In fantasy situations the farts can have different colors and smell. 179 + * Scat ::: Sexual arousal derived from the sight of feces, as well as the act of holding or eating feces. 180 + * Diapers ::: Sexual arousal derived from adults wearing diapers, which may or may not be related to watersports/scat. 181 + 182 + #Degradation 183 + (Giving, Receiving) 184 + * Glory hole ::: A receiving participant giving a blowjob to someone standing behind a wall, with only their penis visible through a hole. 185 + * Name calling ::: Consensual insults/verbal assault. 186 + * Humiliation ::: Consensual psychological humiliation performed in order to produce erotic excitement or arousal, involving the receiving partner being demeaned or put into humiliating situations, such as being naked. 187 + * Cleaning up ::: The act of being told to clean something by a dominant party after sex, such as bodily fluids (cum, etc.) 188 + 189 + #Touch & Stimulation 190 + (Actor, Subject) 191 + * Cock/Pussy worship ::: The sex act of worshipping a partner's genitals, which can be used in foreplay, as an affectionate gesture, or for degradation. 192 + * Ass worship ::: The sex act of worshipping a partner's ass, which can be used in foreplay, as an affectionate gesture, or for degradation. 193 + * Foot play 194 + * Tickling 195 + * Sensation play ::: Sexual gratification from touching erogenous parts of the body, without penetration. 196 + * Electro stimulation ::: Bondage sex play using toys that shock you. 197 + 198 + #Misc. Fetish 199 + (Giving, Receiving) 200 + * Fisting 201 + * Gangbang ::: Many people having sex with one person. 202 + * Impregnation ::: Sex for the purpose of impregnation, can refer to creampies. 203 + * Pregnancy sex ::: Sex during pregnancy. 204 + * Feminization ::: Similar to bimbofication, a fantasy of taking a masculine individual and "feminizing" them by making them take on feminine traits or clothing. 205 + * Cuckold / Cuckquean ::: The fantasy where someone else cheats on your partner or you cheat on your partner, while all parties are aware of the situation. 206 + 207 + #Pain 208 + (Giving, Receiving) 209 + * Light pain ::: Pain play where the pain is not the focus of the interaction, such as lighter slapping and whipping. 210 + * Heavy pain ::: Pain play where the pain is heavily the focus of the interaction, and can border on the limit of the receiving party's pain tolerance. 211 + * Nipple clamps 212 + * Clothespins ::: Clothespins used on the body or nipples. These can be pulled off for an intense pain feeling. 213 + * Spanking ::: Open hand spanking, typically on the butt or face. 214 + * Beating ::: Closed fist beating, typically on the belly, face, or butt. 215 + * Flogging ::: Whips, or similar instruments used on the body of the receiving party for a pleasuresome pain response. Typically whipping is aimed at the butt, which can be more tolerable for some people. 216 + * Caning ::: Hitting or being hit with a cane, which can be very painful, but enjoyable for a masochist partner. 217 + * Cock/Pussy slapping ::: Slapping a participant's genitals, not involving other genital torture interactions. 218 + * Cock/Pussy torture ::: Genital torture is a sexual activity involving the application of pain or constriction to the genitals, for pleasure by a masochist participant. 219 + * Hot wax ::: Holding a burning candle over a participant's body and letting hot wax drip onto their bare skin, leading to a sensation of burning which can be sexually pleasing. 220 + * Scratching ::: Love scratches, or any kind of sexually-oriented skin scratching that doesn't draw blood. 221 + * Biting ::: Bites, typically on the neck, that don't draw blood. 222 + * Cutting ::: Purposefully cutting the skin to draw blood, can refer to knife play but also applies to physical interactions that draw blood in general. 223 + `.trim();
+1
public/lexicons/index.ts
··· 1 + export * as IoGitlabKinklistKinklistProfile from "./types/io/gitlab/kinklist/kinklist/profile.js";
+71
public/lexicons/types/io/gitlab/kinklist/kinklist/profile.ts
··· 1 + import type {} from "@atcute/lexicons"; 2 + import * as v from "@atcute/lexicons/validations"; 3 + import type {} from "@atcute/lexicons/ambient"; 4 + 5 + const _kinkEntrySchema = /*#__PURE__*/ v.object({ 6 + $type: /*#__PURE__*/ v.optional( 7 + /*#__PURE__*/ v.literal("io.gitlab.kinklist.kinklist.profile#kinkEntry"), 8 + ), 9 + /** 10 + * The preference choice for this kink 11 + */ 12 + choice: /*#__PURE__*/ v.literalEnum([ 13 + "favorite", 14 + "like", 15 + "maybe", 16 + "no", 17 + "not-entered", 18 + "okay", 19 + "want-to-try", 20 + ]), 21 + /** 22 + * The name of the kink (e.g., "Bondage", "Voyeurism") 23 + */ 24 + name: /*#__PURE__*/ v.string(), 25 + /** 26 + * The participant type (e.g., "Self", "Partner", "Giving", "Receiving") 27 + */ 28 + participant: /*#__PURE__*/ v.string(), 29 + /** 30 + * The category/section this kink belongs to (e.g., "General", "Taboo", "Bodies") 31 + */ 32 + section: /*#__PURE__*/ v.string(), 33 + }); 34 + const _mainSchema = /*#__PURE__*/ v.record( 35 + /*#__PURE__*/ v.literal("self"), 36 + /*#__PURE__*/ v.object({ 37 + $type: /*#__PURE__*/ v.literal("io.gitlab.kinklist.kinklist.profile"), 38 + /** 39 + * When this profile was created 40 + */ 41 + createdAt: /*#__PURE__*/ v.datetimeString(), 42 + /** 43 + * Array of kink preferences 44 + */ 45 + get kinks() { 46 + return /*#__PURE__*/ v.array(kinkEntrySchema); 47 + }, 48 + /** 49 + * When this profile was last updated 50 + */ 51 + updatedAt: /*#__PURE__*/ v.datetimeString(), 52 + }), 53 + ); 54 + 55 + type kinkEntry$schematype = typeof _kinkEntrySchema; 56 + type main$schematype = typeof _mainSchema; 57 + 58 + export interface kinkEntrySchema extends kinkEntry$schematype {} 59 + export interface mainSchema extends main$schematype {} 60 + 61 + export const kinkEntrySchema = _kinkEntrySchema as kinkEntrySchema; 62 + export const mainSchema = _mainSchema as mainSchema; 63 + 64 + export interface KinkEntry extends v.InferInput<typeof kinkEntrySchema> {} 65 + export interface Main extends v.InferInput<typeof mainSchema> {} 66 + 67 + declare module "@atcute/lexicons/ambient" { 68 + interface Records { 69 + "io.gitlab.kinklist.kinklist.profile": mainSchema; 70 + } 71 + }
+114 -13
public/main.tsx
··· 4 4 import Portal from 'preact-portal'; 5 5 import { Masonry } from 'masonic'; 6 6 import Tippy from '@tippyjs/react'; 7 - import { choiceOptions, choiceOptionIndices } from './base'; 7 + import { choiceOptions, choiceOptionIndices, Choice } from './base'; 8 8 import { exportImage } from './exporter'; 9 9 import { compress, decompress } from 'qfs-compression'; 10 10 import { createPortal } from 'preact/compat'; 11 + import { kinkText as kinkTextContent } from './kinks'; 12 + import { oauthClient, user } from './atproto/signed-in-user'; 11 13 12 14 const root = document.querySelector('#root'); 13 15 ··· 41 43 let curKinkId = 0; 42 44 for (const line of kinkCode) { 43 45 if (line.startsWith('#')) { 44 - const [categoryName, categoryDesc] = sliceOnce(removeSymbols(line, '#'), '?'); 46 + const [categoryName, categoryDesc] = sliceOnce(removeSymbols(line, '#'), ':::'); 45 47 46 48 curKinkCategory = { 47 49 name: categoryName, ··· 71 73 return { kinkCategories, kinksById }; 72 74 } 73 75 74 - const kinkText = signal([...document.querySelectorAll('kinks')].map(e => e.textContent).join('\n')); 76 + const kinkText = signal(kinkTextContent); 75 77 const kinkData = computed(() => parseKinks(kinkText.value)); 76 78 77 79 /** 78 80 * Maps kink name -> participant -> choice (id string) 79 81 * Entries may be undefined! 80 - * @type {Map<Kink, Map<string, string>>} 82 + * @type {Map<Kink, Map<string, Choice>>} 81 83 */ 82 - const kinkSelections: Map<Kink, Map<string, string>> = new Map(); 84 + const kinkSelections: Map<Kink, Map<string, Choice>> = new Map(); 83 85 84 86 /** 85 87 * Maps kink -> participant -> choice option -> button element ··· 216 218 * @param {string} participant 217 219 * @returns {string} 218 220 */ 219 - function getSelectedKinkOrDefault(kink: Kink, participant: string): string { 220 - return kinkSelections.has(kink) && kinkSelections.get(kink)?.get(participant) || 'not-entered'; 221 + function getSelectedKinkOrDefault(kink: Kink, participant: string): Choice { 222 + return kinkSelections.has(kink) && kinkSelections.get(kink)?.get(participant) || Choice.NotEntered; 221 223 } 222 224 223 225 /** ··· 225 227 * @param {string} participant 226 228 * @param {string} toChoiceId 227 229 */ 228 - function setKinkSelection(kink: Kink, participant: string, toChoiceId: string) { 230 + function setKinkSelection(kink: Kink, participant: string, toChoiceId: Choice) { 229 231 if (!kinkSelections.has(kink)) kinkSelections.set(kink, new Map()); 230 232 231 233 kinkSelections.get(kink)!.set(participant, toChoiceId); ··· 321 323 interface KinkChoiceButtonProps { 322 324 kink: Kink; 323 325 participant: string; 324 - choiceId: string; 326 + choiceId: Choice; 325 327 choiceDescription: string; 326 328 } 327 329 ··· 594 596 } 595 597 } 596 598 599 + const [hasInitialSession, setHasInitialSession] = useState(false); 600 + 601 + async function exportAtprotoCallback() { 602 + localStorage.setItem('oauth-redirect-kinks', serializeChoices()); 603 + 604 + if (!hasInitialSession) { 605 + await oauthClient.waitForInitialSession(); 606 + } 607 + 608 + if (!user.value) { 609 + const handle = prompt('Enter your ATProto handle:'); 610 + 611 + if (!handle) { 612 + return; 613 + } 614 + 615 + await oauthClient.authenticateIfNecessary(handle, false); 616 + // This may not return if OAuth redirect, in which case the second part is handled below 617 + // in the useEffect that checks for the OAuth redirect page. 618 + // If it does return, then we can proceed to upload the kinks immediately. 619 + } 620 + 621 + const success = await uploadKinks(); 622 + 623 + if (success) { 624 + alert('Successfully uploaded kinks!'); 625 + } 626 + } 627 + 628 + async function uploadKinks() { 629 + if (!user.value) { 630 + return false; 631 + } 632 + 633 + await user.value.client.createOrUpdateProfile({ 634 + kinks: kinkData.value.kinkCategories.flatMap( 635 + category => category.kinks.flatMap( 636 + kink => category.participants.map( 637 + participant => ({ 638 + section: category.name, 639 + name: kink.name, 640 + participant: participant, 641 + choice: getSelectedKinkOrDefault(kink, participant), 642 + }) 643 + ) 644 + ) 645 + ), 646 + }); 647 + 648 + return true; 649 + } 650 + 597 651 useEffect(() => { 598 - if (window.location.hash) { 652 + const hash = location.hash.slice(1); 653 + oauthClient.waitForInitialSession() 654 + .then(() => setHasInitialSession(true)) 655 + .finally(async () => { 656 + if (document.location.pathname.endsWith('/oauth-redirect.html')) { 657 + console.log('On OAuth redirect page, finalizing authorization...'); 658 + 659 + // Retrieve kinks from local storage as OAuth metadata is in the hash 660 + const storedKinks = localStorage.getItem('oauth-redirect-kinks'); 661 + 662 + if (storedKinks) { 663 + console.log('Deserializing kinks from local storage'); 664 + deserializeChoices(storedKinks); 665 + 666 + console.log('Finalizing authorization'); 667 + if (!user.value) { 668 + await oauthClient.finalizeAuthorization(new URLSearchParams(hash)); 669 + } 670 + 671 + console.log('Uploading kinks'); 672 + const success = await uploadKinks(); 673 + 674 + // Return to index page without redirecting 675 + history.replaceState( 676 + null, 677 + '', 678 + location.origin + 679 + location.pathname.replace('/oauth-redirect.html', '') + 680 + location.search + '#' + 681 + serializeChoices() 682 + ); 683 + 684 + // Remove local storage 685 + localStorage.removeItem('oauth-redirect-kinks'); 686 + 687 + if (success) { 688 + alert('Successfully uploaded kinks!'); 689 + } else { 690 + alert('Failed to upload kinks!'); 691 + } 692 + } 693 + } 694 + }); 695 + 696 + if (hash && !document.location.pathname.endsWith('/oauth-redirect.html')) { 599 697 try { 600 - deserializeChoices(window.location.hash.slice(1)); 698 + deserializeChoices(hash); 601 699 } catch (err) { 602 700 console.error('Failed to load saved kinks:', err); 603 701 } 604 702 } 605 - }); 703 + }, []); 606 704 607 705 return <div id="root"> 608 706 <nav class="navbar px-5 mt-5 mb-2" role="navigation" aria-label="main navigation"> ··· 611 709 <h1 class="title">Kink list</h1> 612 710 </div> 613 711 <div class="navbar-item"> 614 - <button id="export-image" class="button is-primary" onClick={exportImageCallback}>Export</button> 712 + <button id="export-image" class="button is-primary" onClick={exportImageCallback}>Export to Clipboard</button> 713 + </div> 714 + <div class="navbar-item"> 715 + <button id="export-atproto" class="button is-primary" onClick={exportAtprotoCallback}>Export to ATProto</button> 615 716 </div> 616 717 <div class="navbar-item"> 617 718 <button id="view-changelog" class="button is-primary" onClick={() => setChangelogOpen(true)}>Changelog</button>
+58
public/oauth-redirect.html
··· 1 + <!DOCTYPE html> 2 + <html> 3 + 4 + <head> 5 + <meta charset="utf-8"> 6 + <meta name="viewport" content="width=device-width, initial-scale=1"> 7 + <title>Kink list</title> 8 + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.4/css/bulma.css"> 9 + <meta property="og:title" content="Kink list" /> 10 + <meta property="og:type" content="website" /> 11 + <meta property="og:url" content="https://kinklist.gitlab.io/" /> 12 + <meta property="og:image" content="https://kinklist.gitlab.io/kinklistlogo.png" /> 13 + <meta property="og:image:type" content="image/png"> 14 + <meta property="og:image:width" content="512"> 15 + <meta property="og:image:height" content="512"> 16 + <meta property="og:image:alt" content="Kink list logo"> 17 + <meta property="og:description" content="Generate a list of your sexual preferences and kinks, then export and share your list!"> 18 + 19 + <!--<link rel="stylesheet" href="https://unpkg.com/bulma-prefers-dark@0.1.0-beta.0/css/bulma-prefers-dark.css">--> 20 + <link rel="stylesheet" href="https://unpkg.com/tippy.js@6/dist/tippy.css"> 21 + <script> 22 + // https://stackoverflow.com/a/56550819 23 + // determines if the user has a set theme 24 + function detectColorScheme() { 25 + let theme = 'light'; // default to light 26 + 27 + // local storage is used to override OS theme settings 28 + if (localStorage.getItem('theme')) { 29 + if (localStorage.getItem('theme') === 'dark') { 30 + theme = 'dark'; 31 + } 32 + } else if (!window.matchMedia) { 33 + // matchMedia method not supported 34 + theme = 'light'; 35 + } else if (window.matchMedia('(prefers-color-scheme: dark)').matches) { 36 + // OS theme setting detected as dark 37 + theme = 'dark'; 38 + } 39 + 40 + // dark theme preferred, set document with a `data-theme` attribute 41 + if (theme === 'dark') { 42 + document.documentElement.classList.add('theme-dark'); 43 + } 44 + } 45 + detectColorScheme(); 46 + </script> 47 + 48 + <link rel="stylesheet" href="style.css"> 49 + </head> 50 + 51 + <body> 52 + <div id="root"></div> 53 + 54 + <!-- defer is used here so that DOMTools is loaded in time as it's async --> 55 + <script src="kinklist.js"></script> 56 + </body> 57 + 58 + </html>
+221
public/style.css
··· 1 + /* Fix bulma-prefers-dark table cells not fitting vanilla bulma layout */ 2 + /* @media (prefers-color-scheme: dark) { */ 3 + /* .table td, .table th { */ 4 + /* border-width: 0 0 1px; */ 5 + /* } */ 6 + /* } */ 7 + html.theme-dark .table td, 8 + html.theme-dark .table th { 9 + border-width: 0 0 1px; 10 + } 11 + 12 + /* Display table vertically. Matches Bulma's threshold for stacking columns vertically. */ 13 + @media screen and (max-width: 1023px) { 14 + .kinks-table tr { 15 + display: flex; 16 + float: left; 17 + width: 100%; 18 + flex-flow: column; 19 + } 20 + 21 + .kinks-table td { 22 + display: block; 23 + } 24 + 25 + /* Had th, see below for what we actually do */ 26 + 27 + /* Size choice button as a square that takes up the whole space */ 28 + .choice { 29 + width: 100%; 30 + } 31 + 32 + .choice:after { 33 + content: ""; 34 + display: block; 35 + padding-bottom: 100%; 36 + } 37 + 38 + .kinks-legend .choice { 39 + width: 32px; 40 + height: 32px; 41 + } 42 + 43 + .kinks-table td:last-child { 44 + /* Place the kink label before the options */ 45 + order: -1; 46 + /* Hide the border for the kink label */ 47 + border-bottom: none !important; 48 + } 49 + 50 + /* Due to the display:block above the table headers will not match the vertical layout. So we put them side-by-side (and then make them look pretty) */ 51 + .kinks-table th { 52 + display: inline-block; 53 + } 54 + 55 + /* They're side-by-side, but we still need to remove the padding to make it seem as one single element */ 56 + .kinks-table th:not(:first-child) { 57 + padding-left: 0; 58 + } 59 + 60 + .kinks-table th:not(:last-child) { 61 + padding-right: 0; 62 + } 63 + 64 + /* Then, we add a comma separating them. */ 65 + .kinks-table th:not(:last-child)::after { 66 + content: ', '; 67 + white-space: pre; 68 + } 69 + 70 + /* Now we have to add the Self/Partner text to each set of choices so the reader doesn't get confused. */ 71 + /* This is only applied when there is more than one choice. */ 72 + /* https://stackoverflow.com/a/12198561 */ 73 + .kinks-table:not([data-num-participants="1"]) td::before { 74 + /* We have to set this manually for every table. */ 75 + color: #363636; 76 + font-style: italic; 77 + content: attr(data-choice-type); 78 + /* We have to set this manually for every td. */ 79 + } 80 + } 81 + 82 + @media screen and (min-width: 1024px) { 83 + .choice { 84 + width: 16px; 85 + height: 16px; 86 + } 87 + 88 + /* Make the table stretch out to the entire available width for the outer masonry element. This may be a hack. */ 89 + .kinks-table td:last-child { 90 + width: 100%; 91 + /* Stretches out the last column as far as possible, which the browser limits to the masonry's width */ 92 + } 93 + 94 + .kinks-table { 95 + margin-right: 1rem; 96 + /* Adds a small margin to the table so they don't all touch each other */ 97 + } 98 + } 99 + 100 + .column { 101 + margin-right: 1% !important; 102 + } 103 + 104 + kinks { 105 + display: none !important; 106 + } 107 + 108 + /* Margin in between choices */ 109 + .choices .columns.is-gapless .column:not(:last-child) { 110 + margin-right: 3px !important; 111 + } 112 + 113 + .choice { 114 + padding: 0; 115 + font-size: 0; 116 + outline: none; 117 + border: 1px solid black; 118 + border-radius: 50%; 119 + transition: opacity 0.3s ease-in-out; 120 + vertical-align: middle; 121 + opacity: 0.35; 122 + cursor: pointer; 123 + } 124 + 125 + .choice:not([disabled]):hover { 126 + opacity: 0.7; 127 + } 128 + 129 + .choice[disabled] { 130 + cursor: inherit; 131 + } 132 + 133 + .choice.selected { 134 + opacity: 1; 135 + border-width: 2px; 136 + } 137 + 138 + .choice.not-entered { 139 + background-color: #FFFFFF; 140 + } 141 + 142 + .choice.favorite { 143 + background-color: #6DB5FE; 144 + } 145 + 146 + .choice.like { 147 + background-color: #23FD22; 148 + } 149 + 150 + .choice.okay { 151 + background-color: #FDFD6B; 152 + } 153 + 154 + .choice.maybe { 155 + background-color: #DB6C00; 156 + } 157 + 158 + .choice.no { 159 + background-color: #920000; 160 + } 161 + 162 + .choice.want-to-try { 163 + background-color: white; 164 + background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxNScgaGVpZ2h0PScxNSc+CiAgPHJlY3Qgd2lkdGg9JzE1JyBoZWlnaHQ9JzE1JyBmaWxsPSd3aGl0ZScvPgogIDxwYXRoIGQ9J00tMSwxIGwyLC0yCiAgICAgICAgICAgTTAsNSBsMTUsLTE1CiAgICAgICAgICAgTTAsMTAgbDE1LC0xNQogICAgICAgICAgIE0wLDE1IGwxNSwtMTUKICAgICAgICAgICBNMCwyMCBsMTUsLTE1CiAgICAgICAgICAgTTAsMjUgbDE1LC0xNQogICAgICAgICAgIE0xNCwxNiBsMiwtMicgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxJy8+Cjwvc3ZnPgo=); 165 + background-repeat: repeat; 166 + } 167 + 168 + .kinks-subtitle { 169 + margin-top: 1.5rem; 170 + margin-bottom: 0 !important; 171 + } 172 + 173 + .kinks-section { 174 + padding-top: 0; 175 + } 176 + 177 + /* Legend: Bulma's Level does not come with margins by default. We pad the inner element instead. */ 178 + .kinks-legend { 179 + padding-left: 12px; 180 + } 181 + 182 + /* Margin between the choice button reference and the text that describes it */ 183 + .kinks-legend .choice { 184 + margin-right: 4px; 185 + } 186 + 187 + /* Increases margin between elements, matching Bulma's behavior to only do anything when not displaying vertically */ 188 + @media screen and (min-width: 769px) { 189 + .kinks-legend>.level-item { 190 + margin-right: 1rem !important; 191 + } 192 + } 193 + 194 + .has-description { 195 + text-decoration: underline; 196 + text-decoration-style: dotted; 197 + } 198 + 199 + .has-subtitle-description { 200 + font-size: 70%; 201 + 202 + 203 + background-image: linear-gradient(to right, black 33%, rgba(255, 255, 255, 0) 0%); 204 + background-position: bottom; 205 + background-size: 3px 1px; 206 + background-repeat: repeat-x; 207 + } 208 + 209 + /* Use white-colored border for choice buttons when dark theme is enabled */ 210 + html.theme-dark .choice { 211 + border-color: white; 212 + } 213 + 214 + /* Stack navbar items vertically on mobile */ 215 + @media screen and (max-width: 1023px) { 216 + .navbar-brand { 217 + display: flex; 218 + flex-direction: column; 219 + justify-content: center; 220 + } 221 + }
+1 -1
public/tsconfig.json
··· 14 14 } 15 15 }, 16 16 "exclude": ["kinklist.js"], 17 - "include": ["*"] 17 + "include": ["*", "**/*.ts", "**/*.{ts,tsx}"] 18 18 }
+4
typelex/externals.tsp
··· 1 + import "@typelex/emitter"; 2 + 3 + // Generated by typelex from ./lexicons (excluding io.gitlab.kinklist.*) 4 + // No external lexicons found
+58
typelex/main.tsp
··· 1 + import "@typelex/emitter"; 2 + import "./externals.tsp"; 3 + 4 + namespace io.gitlab.kinklist.kinklist.profile { 5 + /** My kink list profile. */ 6 + @rec("literal:self") 7 + model Main { 8 + /** Array of kink preferences */ 9 + @required kinks: KinkEntry[]; 10 + 11 + /** When this profile was created */ 12 + @required createdAt: datetime; 13 + 14 + /** When this profile was last updated */ 15 + @required updatedAt: datetime; 16 + } 17 + 18 + /** A single kink entry with preferences */ 19 + model KinkEntry { 20 + /** The category/section this kink belongs to (e.g., "General", "Taboo", "Bodies") */ 21 + @required section: string; 22 + 23 + /** The name of the kink (e.g., "Bondage", "Voyeurism") */ 24 + @required name: string; 25 + 26 + /** The participant type (e.g., "Self", "Partner", "Giving", "Receiving") */ 27 + @required participant: string; 28 + 29 + /** The preference choice for this kink */ 30 + @required choice: Choice; 31 + } 32 + 33 + /** Closed enum of preference choices */ 34 + @closed 35 + @inline 36 + union Choice { 37 + /** Favorite - highly desired */ 38 + "favorite", 39 + 40 + /** Like - enjoyed */ 41 + "like", 42 + 43 + /** Okay - neutral/acceptable */ 44 + "okay", 45 + 46 + /** Maybe - uncertain/depends */ 47 + "maybe", 48 + 49 + /** No - not interested */ 50 + "no", 51 + 52 + /** Not entered - no preference given */ 53 + "not-entered", 54 + 55 + /** Want to try - interested but not yet experienced */ 56 + "want-to-try" 57 + } 58 + }