this repo has no description
0
fork

Configure Feed

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

Reorganize code

uwx e0c2b0a8 3d0d42c6

+144 -136
+144 -136
public/main.tsx
··· 87 87 /** 88 88 * Maps kink name -> participant -> choice (id string) 89 89 * Entries may be undefined! 90 - * @type {Map<Kink, Map<string, Choice>>} 91 90 */ 92 91 const kinkSelections: Map<Kink, Map<string, Signal<Choice>>> = new Map(); 93 92 94 93 /** 95 94 * Maps kink -> participant -> choice option -> button element 96 95 * Entries may be undefined! 97 - * @type {Map<Kink, Map<string, Map<string, (action: 'select' | 'deselect') => void>>>} 98 96 */ 99 97 const kinkButtons: Map<Kink, Map<string, Map<string, (action: "select" | "deselect") => void>>> = new Map(); 100 98 ··· 1210 1208 ) 1211 1209 } 1212 1210 1213 - function RealRoot() { 1211 + async function uploadKinks() { 1212 + if (!user.value) { 1213 + return false; 1214 + } 1215 + 1216 + await user.value.client.createOrUpdateProfile({ 1217 + kinks: getKinksArray(), 1218 + kinkDefinitions: kinkData.value.kinkCategories 1219 + }); 1220 + 1221 + return true; 1222 + } 1223 + 1224 + function Navbar({ 1225 + hasInitialSession 1226 + }: { 1227 + hasInitialSession: boolean; 1228 + }) { 1214 1229 const [changelogOpen, setChangelogOpen] = useState(false); 1215 1230 const [exportImageOpen, setExportImageOpen] = useState(false); 1216 1231 const [exportModalContent, setExportModalContent] = useState<HTMLElement | null>(null); ··· 1267 1282 } 1268 1283 } 1269 1284 1270 - const [hasInitialSession, setHasInitialSession] = useState(false); 1271 - 1272 1285 async function signIn(action: 'upload' | 'sign-in') { 1273 1286 localStorage.setItem("oauth-redirect-kinks", serializeChoices()); 1274 1287 localStorage.setItem("oauth-redirect-action", action); ··· 1301 1314 } 1302 1315 } 1303 1316 1304 - async function uploadKinks() { 1305 - if (!user.value) { 1306 - return false; 1307 - } 1317 + const [darkThemeChecked, setDarkThemeChecked] = useState(document.documentElement.classList.contains("theme-dark")); 1318 + 1319 + return ( 1320 + <nav class="navbar px-5 mt-5 mb-2" role="navigation" aria-label="main navigation"> 1321 + <div class="navbar-brand"> 1322 + <div class="navbar-item"> 1323 + <h1 class="title">Kink list</h1> 1324 + </div> 1325 + 1326 + <div role="button" class={`navbar-burger ${navbarMenuActive ? "is-active" : ""}`} onClick={() => setNavbarMenuActive(!navbarMenuActive)} aria-label="menu" aria-expanded={navbarMenuActive} data-target="navMenu"> 1327 + <span aria-hidden="true"></span> 1328 + <span aria-hidden="true"></span> 1329 + <span aria-hidden="true"></span> 1330 + <span aria-hidden="true"></span> 1331 + </div> 1332 + </div> 1333 + 1334 + <div class={`navbar-menu ${navbarMenuActive ? "is-active" : ""}`}> 1335 + <div class="navbar-start"> 1336 + <div class={`navbar-item has-dropdown ${exportDropdownActive ? "is-active" : ""}`} onClick={() => setExportDropdownActive(!exportDropdownActive)}> 1337 + <a class="navbar-link"> 1338 + Export 1339 + </a> 1340 + 1341 + <div class="navbar-dropdown"> 1342 + <a class="navbar-item" onClick={exportImageCallback}> 1343 + to Clipboard 1344 + </a> 1345 + 1346 + <Modal open={exportImageOpen} onClose={() => setExportImageOpen(false)} container={document.body}> 1347 + <div class="box"> 1348 + <h1 class="title">Exported! Copy the image to your clipboard or save it now.</h1> 1349 + <div id="export-modal-content">{exportModalContent}</div> 1350 + </div> 1351 + </Modal> 1352 + 1353 + <a class="navbar-item" onClick={exportAtprotoCallback}> 1354 + to ATProto 1355 + </a> 1356 + </div> 1357 + </div> 1358 + <a class="navbar-item" onClick={() => setChangelogOpen(true)}> 1359 + Changelog 1360 + </a> 1361 + 1362 + <Modal open={changelogOpen} onClose={() => setChangelogOpen(false)} container={document.body}> 1363 + <div class="box content"> 1364 + <h1>Changelog</h1> 1365 + {changelog.map((entry) => ( 1366 + <div> 1367 + <h2>{entry.version}</h2> 1368 + <ul> 1369 + {entry.changes.map((change) => ( 1370 + <li>{change}</li> 1371 + ))} 1372 + </ul> 1373 + </div> 1374 + ))} 1375 + </div> 1376 + </Modal> 1377 + 1378 + <a class="navbar-item" onClick={() => setQuizModeOpen(true)}> 1379 + Quiz Mode 1380 + </a> 1381 + 1382 + <Modal open={quizModeOpen} onClose={() => setQuizModeOpen(false)} container={document.body}> 1383 + <QuizMode /> 1384 + </Modal> 1385 + 1386 + <a class="navbar-item" id="customize-list" onClick={() => setCustomizeListOpen(true)}> 1387 + Customize List 1388 + </a> 1389 + 1390 + <Modal open={customizeListOpen} onClose={() => setCustomizeListOpen(false)} container={document.body}> 1391 + <CustomizeList onClose={() => setCustomizeListOpen(false)} /> 1392 + </Modal> 1393 + </div> 1394 + 1395 + {hasInitialSession && <div class="navbar-end"> 1396 + {user.value 1397 + ? <> 1398 + <a class="navbar-item" onClick={() => setFriendsOpen(true)}> 1399 + Friends 1400 + </a> 1401 + <div class="navbar-item"> 1402 + @{user.value.handle} 1403 + </div> 1404 + <a class="navbar-item" onClick={() => oauthClient.revokeSessions()}> 1405 + Sign out 1406 + </a> 1407 + </> 1408 + : ( 1409 + <a class="navbar-item" onClick={() => signIn('sign-in')}> 1410 + Sign in with ATProto 1411 + </a> 1412 + )} 1413 + </div>} 1308 1414 1309 - await user.value.client.createOrUpdateProfile({ 1310 - kinks: getKinksArray(), 1311 - kinkDefinitions: kinkData.value.kinkCategories 1312 - }); 1415 + <Modal open={friendsOpen} onClose={() => setFriendsOpen(false)} container={document.body}> 1416 + {friendsOpen && <Friends />} 1417 + </Modal> 1418 + 1313 1419 1314 - return true; 1315 - } 1420 + <a class="navbar-item" onClick={e => { 1421 + e.preventDefault(); 1422 + e.stopPropagation(); 1423 + 1424 + if (!darkThemeChecked) { 1425 + localStorage.setItem("theme", "dark"); 1426 + document.documentElement.classList.add("theme-dark"); 1427 + setDarkThemeChecked(true); 1428 + } else { 1429 + localStorage.setItem("theme", "light"); 1430 + document.documentElement.classList.remove("theme-dark"); 1431 + setDarkThemeChecked(false); 1432 + } 1433 + }}> 1434 + {darkThemeChecked ? <FontAwesomeIcon icon={faSun} /> : <FontAwesomeIcon icon={faMoon} />} 1435 + </a> 1436 + </div> 1437 + </nav> 1438 + ) 1439 + } 1440 + 1441 + function Root() { 1442 + const [hasInitialSession, setHasInitialSession] = useState(false); 1316 1443 1317 1444 useEffect(() => { 1318 1445 const hash = location.hash.slice(1); ··· 1391 1518 } 1392 1519 }, []); 1393 1520 1394 - const [darkThemeChecked, setDarkThemeChecked] = useState(document.documentElement.classList.contains("theme-dark")); 1395 - 1396 1521 return ( 1397 1522 <div id="root"> 1398 - <nav class="navbar px-5 mt-5 mb-2" role="navigation" aria-label="main navigation"> 1399 - <div class="navbar-brand"> 1400 - <div class="navbar-item"> 1401 - <h1 class="title">Kink list</h1> 1402 - </div> 1403 - 1404 - <div role="button" class={`navbar-burger ${navbarMenuActive ? "is-active" : ""}`} onClick={() => setNavbarMenuActive(!navbarMenuActive)} aria-label="menu" aria-expanded={navbarMenuActive} data-target="navMenu"> 1405 - <span aria-hidden="true"></span> 1406 - <span aria-hidden="true"></span> 1407 - <span aria-hidden="true"></span> 1408 - <span aria-hidden="true"></span> 1409 - </div> 1410 - </div> 1411 - 1412 - <div class={`navbar-menu ${navbarMenuActive ? "is-active" : ""}`}> 1413 - <div class="navbar-start"> 1414 - <div class={`navbar-item has-dropdown ${exportDropdownActive ? "is-active" : ""}`} onClick={() => setExportDropdownActive(!exportDropdownActive)}> 1415 - <a class="navbar-link"> 1416 - Export 1417 - </a> 1418 - 1419 - <div class="navbar-dropdown"> 1420 - <a class="navbar-item" onClick={exportImageCallback}> 1421 - to Clipboard 1422 - </a> 1423 - 1424 - <Modal open={exportImageOpen} onClose={() => setExportImageOpen(false)} container={document.body}> 1425 - <div class="box"> 1426 - <h1 class="title">Exported! Copy the image to your clipboard or save it now.</h1> 1427 - <div id="export-modal-content">{exportModalContent}</div> 1428 - </div> 1429 - </Modal> 1430 - 1431 - <a class="navbar-item" onClick={exportAtprotoCallback}> 1432 - to ATProto 1433 - </a> 1434 - </div> 1435 - </div> 1436 - <a class="navbar-item" onClick={() => setChangelogOpen(true)}> 1437 - Changelog 1438 - </a> 1439 - 1440 - <Modal open={changelogOpen} onClose={() => setChangelogOpen(false)} container={document.body}> 1441 - <div class="box content"> 1442 - <h1>Changelog</h1> 1443 - {changelog.map((entry) => ( 1444 - <div> 1445 - <h2>{entry.version}</h2> 1446 - <ul> 1447 - {entry.changes.map((change) => ( 1448 - <li>{change}</li> 1449 - ))} 1450 - </ul> 1451 - </div> 1452 - ))} 1453 - </div> 1454 - </Modal> 1455 - 1456 - <a class="navbar-item" onClick={() => setQuizModeOpen(true)}> 1457 - Quiz Mode 1458 - </a> 1459 - 1460 - <Modal open={quizModeOpen} onClose={() => setQuizModeOpen(false)} container={document.body}> 1461 - <QuizMode /> 1462 - </Modal> 1463 - 1464 - <a class="navbar-item" id="customize-list" onClick={() => setCustomizeListOpen(true)}> 1465 - Customize List 1466 - </a> 1467 - 1468 - <Modal open={customizeListOpen} onClose={() => setCustomizeListOpen(false)} container={document.body}> 1469 - <CustomizeList onClose={() => setCustomizeListOpen(false)} /> 1470 - </Modal> 1471 - </div> 1472 - 1473 - {hasInitialSession && <div class="navbar-end"> 1474 - {user.value 1475 - ? <> 1476 - <a class="navbar-item" onClick={() => setFriendsOpen(true)}> 1477 - Friends 1478 - </a> 1479 - <div class="navbar-item"> 1480 - @{user.value.handle} 1481 - </div> 1482 - <a class="navbar-item" onClick={() => oauthClient.revokeSessions()}> 1483 - Sign out 1484 - </a> 1485 - </> 1486 - : ( 1487 - <a class="navbar-item" onClick={() => signIn('sign-in')}> 1488 - Sign in with ATProto 1489 - </a> 1490 - )} 1491 - </div>} 1492 - 1493 - <Modal open={friendsOpen} onClose={() => setFriendsOpen(false)} container={document.body}> 1494 - {friendsOpen && <Friends />} 1495 - </Modal> 1496 - 1497 - 1498 - <a class="navbar-item" onClick={e => { 1499 - e.preventDefault(); 1500 - e.stopPropagation(); 1501 - 1502 - if (!darkThemeChecked) { 1503 - localStorage.setItem("theme", "dark"); 1504 - document.documentElement.classList.add("theme-dark"); 1505 - setDarkThemeChecked(true); 1506 - } else { 1507 - localStorage.setItem("theme", "light"); 1508 - document.documentElement.classList.remove("theme-dark"); 1509 - setDarkThemeChecked(false); 1510 - } 1511 - }}> 1512 - {darkThemeChecked ? <FontAwesomeIcon icon={faSun} /> : <FontAwesomeIcon icon={faMoon} />} 1513 - </a> 1514 - </div> 1515 - </nav> 1523 + <Navbar hasInitialSession={hasInitialSession} /> 1516 1524 1517 1525 <nav class="level px-5"> 1518 1526 <div id="legend" class="kinks-legend level-left"> ··· 1527 1535 ); 1528 1536 } 1529 1537 1530 - render(<RealRoot />, root!); 1538 + render(<Root />, root!); 1531 1539 function getKinksArray(): KinksArray { 1532 1540 return kinkData.value.kinkCategories.flatMap((category) => 1533 1541 category.kinks.flatMap((kink) =>