]> git.localhorst.tv Git - alttp.git/commitdiff
svg dungeon tracker
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 3 Apr 2024 13:07:26 +0000 (15:07 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 3 Apr 2024 13:07:26 +0000 (15:07 +0200)
resources/js/components/tracker/CountDisplay.js
resources/js/components/tracker/Dungeons.js
resources/js/components/tracker/ToggleIcon.js
resources/js/components/tracker/index.js
resources/sass/tracker.scss

index 8282422486c92059f574a70f7ea0715e2bf37f53..ba41b9fa50dd1dc81560f079c05868c6fa713121 100644 (file)
@@ -12,9 +12,9 @@ const CountDisplay = ({ className, count, full }) => {
        if (full && count >= full) {
                classNames.push('is-full');
        }
-       return <span className={classNames.join(' ')}>
+       return <text className={classNames.join(' ')}>
                {count}
-       </span>;
+       </text>;
 };
 
 CountDisplay.propTypes = {
index b997e754fb8c3b31b62c36b7c8e1ad40d5b33863..4890bbbc6afbb433a38c282c0bf33b63cdc2d571 100644 (file)
@@ -3,6 +3,7 @@ import React from 'react';
 import CountDisplay from './CountDisplay';
 import ToggleIcon from './ToggleIcon';
 import {
+       BOSSES,
        getDungeonAcquiredSKs,
        getDungeonRemainingItems,
        shouldShowDungeonItem,
@@ -12,67 +13,168 @@ import { useTracker } from '../../hooks/tracker';
 const Dungeons = () => {
        const { config, dungeons, state } = useTracker();
 
-       return <div className="dungeons">
+       const layout = React.useMemo(() => {
+               const mapX = 1;
+               const compassX = shouldShowDungeonItem(config, 'Map') ? mapX + 1 : mapX;
+               const smallX = shouldShowDungeonItem(config, 'Compass') ? compassX + 1 : compassX;
+               const bigX =  shouldShowDungeonItem(config, 'Small') ? smallX + 1 : smallX;
+               const countX = shouldShowDungeonItem(config, 'Big') ? bigX + 1 : bigX;
+               const bossX = countX + 1;
+               const prizeX = bossX + 1;
+               const dungeonWidth = prizeX + 1;
+               const width = (4 * dungeonWidth) + 2;
+               const height = 4;
+               const viewBox = `0 0 ${width} ${height}`;
+               return {
+                       width,
+                       height,
+                       viewBox,
+                       transform: {
+                               tag: '',
+                               map: `translate(${mapX} 0) scale(0.9)`,
+                               compass: `translate(${compassX} 0) scale(0.9)`,
+                               small: `translate(${smallX} 0) scale(0.9)`,
+                               big: `translate(${bigX} 0) scale(0.9)`,
+                               checks: `translate(${countX} 0) scale(0.9)`,
+                               boss: `translate(${bossX} 0)`,
+                               prize: `translate(${prizeX} 0)`,
+                               hc: 'translate(0.5, 0.5)',
+                               ct: 'translate(0.5, 1.5)',
+                               gt: 'translate(0.5, 2.5)',
+                               gtBoss1: `translate(${bossX - 2} 1)`,
+                               gtBoss2: `translate(${bossX - 1} 1)`,
+                               gtBoss3: `translate(${bossX} 1)`,
+                               ep: `translate(${dungeonWidth + 0.5}, 0.5)`,
+                               dp: `translate(${dungeonWidth + 0.5}, 1.5)`,
+                               th: `translate(${dungeonWidth + 0.5}, 2.5)`,
+                               pd: `translate(${(2 * dungeonWidth) + 1.5}, 0.5)`,
+                               sp: `translate(${(2 * dungeonWidth) + 1.5}, 1.5)`,
+                               sw: `translate(${(2 * dungeonWidth) + 1.5}, 2.5)`,
+                               tt: `translate(${(2 * dungeonWidth) + 1.5}, 3.5)`,
+                               ip: `translate(${(3 * dungeonWidth) + 2.5}, 0.5)`,
+                               mm: `translate(${(3 * dungeonWidth) + 2.5}, 1.5)`,
+                               tr: `translate(${(3 * dungeonWidth) + 2.5}, 2.5)`,
+                       },
+               };
+       }, [config, dungeons]);
+
+       return <svg
+               xmlns="http://www.w3.org/2000/svg"
+               className="dungeons"
+               width={layout.width}
+               height={layout.height}
+               viewBox={layout.viewBox}
+               onContextMenu={(e) => {
+                       e.preventDefault();
+                       e.stopPropagation();
+               }}
+       >
                {dungeons.map(dungeon =>
-                       <div className={`dungeon dungeon-${dungeon.id}`} key={dungeon.id}>
-                               <span className="dungeon-tag">{dungeon.id.toUpperCase()}</span>
+                       <g
+                               className={`dungeon dungeon-${dungeon.id}`}
+                               key={dungeon.id}
+                               transform={layout.transform[dungeon.id]}
+                       >
+                               <g transform={layout.transform.tag}>
+                                       <text className="dungeon-tag">{dungeon.id.toUpperCase()}</text>
+                               </g>
                                {shouldShowDungeonItem(config, 'Map') ?
-                                       <ToggleIcon
-                                               controller={ToggleIcon.dungeonController(dungeon)}
-                                               icons={['map']}
-                                       />
+                                       <g transform={layout.transform.map}>
+                                               <ToggleIcon
+                                                       controller={ToggleIcon.dungeonController(dungeon)}
+                                                       icons={['map']}
+                                                       svg
+                                               />
+                                       </g>
                                : null}
                                {shouldShowDungeonItem(config, 'Compass') ?
-                                       <ToggleIcon
-                                               controller={ToggleIcon.dungeonController(dungeon)}
-                                               icons={['compass']}
-                                       />
+                                       <g transform={layout.transform.compass}>
+                                               <ToggleIcon
+                                                       controller={ToggleIcon.dungeonController(dungeon)}
+                                                       icons={['compass']}
+                                                       svg
+                                               />
+                                       </g>
                                : null}
                                {shouldShowDungeonItem(config, 'Small') ?
-                                       <span className="dungeon-smalls">
+                                       <g transform={layout.transform.small}>
                                                <ToggleIcon
                                                        controller={ToggleIcon.dungeonCountController(dungeon, dungeon.sk)}
                                                        icons={['small-key']}
+                                                       svg
                                                />
                                                <CountDisplay
                                                        count={getDungeonAcquiredSKs(state, dungeon)}
                                                        full={dungeon.sk}
                                                />
-                                       </span>
+                                       </g>
                                : null}
                                {shouldShowDungeonItem(config, 'Big') ?
-                                       <ToggleIcon
-                                               controller={ToggleIcon.dungeonController(dungeon)}
-                                               icons={['big-key']}
-                                       />
+                                       <g transform={layout.transform.big}>
+                                               <ToggleIcon
+                                                       controller={ToggleIcon.dungeonController(dungeon)}
+                                                       icons={['big-key']}
+                                                       svg
+                                               />
+                                       </g>
                                : null}
-                               <span className="dungeon-checks">
+                               <g transform={layout.transform.checks}>
                                        <ToggleIcon
                                                controller={ToggleIcon.dungeonCheckController(dungeon)}
                                                icons={['open-chest', 'chest']}
+                                               svg
                                        />
                                        <CountDisplay count={getDungeonRemainingItems(state, dungeon)} />
-                               </span>
+                               </g>
                                {dungeon.boss ?
-                                       <ToggleIcon
-                                               controller={ToggleIcon.dungeonBossController(dungeon)}
-                                               icons={dungeon.bosses}
-                                       />
+                                       <g transform={layout.transform.boss}>
+                                               <ToggleIcon
+                                                       controller={ToggleIcon.dungeonBossController(dungeon)}
+                                                       icons={dungeon.bosses}
+                                                       svg
+                                               />
+                                       </g>
                                : null}
                                {dungeon.prize ?
-                                       <ToggleIcon
-                                               controller={ToggleIcon.dungeonPrizeController(dungeon)}
-                                               icons={[
-                                                       'crystal',
-                                                       'red-crystal',
-                                                       'green-pendant',
-                                                       'red-pendant',
-                                               ]}
-                                       />
+                                       <g transform={layout.transform.prize}>
+                                               <ToggleIcon
+                                                       controller={ToggleIcon.dungeonPrizeController(dungeon)}
+                                                       icons={[
+                                                               'crystal',
+                                                               'red-crystal',
+                                                               'green-pendant',
+                                                               'red-pendant',
+                                                       ]}
+                                                       svg
+                                               />
+                                       </g>
                                : null}
-                       </div>
+                               {dungeon.id === 'gt' && config.bossShuffle ? <>
+                                       <g transform={layout.transform.gtBoss1}>
+                                               <ToggleIcon
+                                                       controller={ToggleIcon.gtBossController('bot')}
+                                                       icons={BOSSES}
+                                                       svg
+                                               />
+                                       </g>
+                                       <g transform={layout.transform.gtBoss2}>
+                                               <ToggleIcon
+                                                       controller={ToggleIcon.gtBossController('mid')}
+                                                       icons={BOSSES}
+                                                       svg
+                                               />
+                                       </g>
+                                       <g transform={layout.transform.gtBoss3}>
+                                               <ToggleIcon
+                                                       controller={ToggleIcon.gtBossController('top')}
+                                                       icons={BOSSES}
+                                                       svg
+                                               />
+                                       </g>
+                               </> : null}
+                       </g>
                )}
-       </div>;
+       </svg>;
 };
 
 export default Dungeons;
index 6de9f63632652dea775d0eca42259e5f15d0425d..98ae93240d0656087f0dd17719c9af89a9b80da1 100644 (file)
@@ -8,6 +8,7 @@ import {
        getDungeonBoss,
        getDungeonRemainingItems,
        getDungeonPrize,
+       getGTBoss,
        hasDungeonBoss,
        hasDungeonPrize,
        highestActive,
@@ -201,6 +202,13 @@ ToggleIcon.dungeonPrizeController = (dungeon) => ({
        handleSecondary: previousString(`${dungeon.id}-prize`),
 });
 
+ToggleIcon.gtBossController = (which) => ({
+       getActive: (state) => getGTBoss(state, which),
+       getDefault: (state) => getGTBoss(state, which),
+       handlePrimary: nextString(`gt-${which}-boss`),
+       handleSecondary: previousString(`gt-${which}-boss`),
+});
+
 ToggleIcon.medallionController = {
        getActive: highestActive,
        getDefault: firstIcon,
index 31fb96423cc3a68680f02659acfba4764105e5b2..7b16b4014a97801c02b73cfdc7417073888ae80b 100644 (file)
@@ -13,12 +13,14 @@ const Tracker = () => {
                        <Row>
                                <Col sm={3}>
                                        <Items />
-                                       <Dungeons />
                                </Col>
                                <Col sm={9}>
                                        <Map />
                                </Col>
                        </Row>
+                       <div className="mt-2">
+                               <Dungeons />
+                       </div>
                </Container>
        </div>;
 };
index 01704b75f3f69e33ac4c696604798a349bc1a99c..ca20b6342d2893f47c77c694cf2a3ee7020c1df8 100644 (file)
@@ -4,61 +4,32 @@
                        vertical-align: middle;
                }
        }
-       .count-display,
-       .med-display {
-               background: black;
-               font-weight: bold;
-               text-align: center;
-       }
-       .dungeon {
-               display: flex;
-               flex-direction: row;
-               align-items: stretch;
-               justify-content: flex-start;
-               gap: 1ex;
-               > * {
-                       width: 2em;
-                       height: 2em;
-               }
-               .dungeon-smalls .count-display,
+       .dungeons {
+               width: 100%;
+               height: auto;
+               .count-display,
                .dungeon-tag {
-                       background: black;
-                       font-family: monospace;
-                       font-size: 115%;
+                       font-size: 0.5px;
                        font-weight: bold;
-                       text-align: center;
-               }
-               .dungeon-checks,
-               .dungeon-smalls {
-                       position: relative;
-                       .count-display {
-                               pointer-events: none;
-                               position: absolute;
-                               top: .3ex;
-                               left: .3ex;
-                               bottom: .3ex;
-                               right: .3ex;
-                               &.is-zero {
-                                       display: none;
-                               }
-                               &.is-full {
-                                       color: green;
-                               }
+                       fill: white;
+                       stroke: black;
+                       stroke-width: 0.25px;
+                       stroke-linejoin: round;
+                       paint-order: stroke fill;
+                       dominant-baseline: middle;
+                       text-anchor: middle;
+                       pointer-events: none;
+                       user-select: none;
+                       &.is-zero {
+                               display: none;
+                       }
+                       &.is-full {
+                               fill: green;
                        }
                }
-       }
-       .dungeons {
-               padding: 1ex;
-       }
-       .dungeon-ep,
-       .dungeon-pd {
-               margin-top: 1ex;
-       }
-       .equipment {
-               display: grid;
-               grid-template-columns: 3em 3em 3em 3em 3em;
-               gap: 1ex;
-               padding: 1ex;
+               .count-display {
+                       font-size: 0.65px;
+               }
        }
        .items {
                width: 100%;