aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/Menu.svelte
blob: b1fae7a94f7c68cd6e907af8b9c9996f3cd3e204 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
<script lang="ts">
  import PhListBold from "virtual:icons/ph/list-bold";
  import PhFadersBold from "virtual:icons/ph/faders-bold";
  import PhLifebuoyBold from "virtual:icons/ph/lifebuoy-bold";
  import PhMapTrifoldBold from "virtual:icons/ph/map-trifold-bold";
  import PhChatBold from "virtual:icons/ph/chat-bold";
  import PhLightningFill from "virtual:icons/ph/lightning-fill";
  import PhMoonStarsBold from "virtual:icons/ph/moon-stars-bold";
  import PhSignOutBold from "virtual:icons/ph/sign-out-bold";
  import CoinosLogo from "virtual:icons/coinos/logo";
  import { theme, unreadDMs } from "$lib/store";
  import DarkToggle from "$comp/DarkToggle.svelte";
  let { t, user, w, opacity } = $props();

  let dark = () => ($theme = $theme === "dark" ? "light" : "dark");
  let showMenu = $state(false);

  let menuButtons = [
    { key: "nav.settings", icon: PhFadersBold, href: `/settings` },
    { key: "nav.support", icon: PhLifebuoyBold, href: `/support` },
    { key: "nav.map", icon: PhMapTrifoldBold, href: `/map` },
    { key: "nav.dm", icon: PhChatBold, href: `/messages` },
    { key: "nav.funds", icon: PhLightningFill, href: `/funds` },
    { key: "nav.dark", icon: PhMoonStarsBold, href: `/dark` },
    { key: "nav.signOut", icon: PhSignOutBold, href: `/logout` },
  ];

  let hideMenu = () => (showMenu = false);
  let toggleMenu = () => (showMenu = !showMenu);

  const clickOutside = (node, callback) => {
    const handler = (e) => { if (!node.contains(e.target)) callback(); };
    document.addEventListener("click", handler, true);
    return { destroy: () => document.removeEventListener("click", handler, true) };
  };
</script>

<div use:clickOutside={hideMenu}>
  <button class="relative flex justify-center items-center bg-base-100 p-2 rounded-full w-12 h-12 sm:w-16 sm:h-16 drop-shadow-xl {opacity('/support')}" onclick={toggleMenu} aria-label="Open menu">
    <PhListBold width={w > 640 ? 32 : 24} />
    {#if $unreadDMs > 0}
      <span class="badge-dot">{$unreadDMs > 99 ? "99+" : $unreadDMs}</span>
    {/if}
  </button>

  <div
    class="absolute top-14 right-0 bg-base-100 rounded-3xl p-8 shadow-xl z-50"
    class:hidden={!showMenu}
    class:block={showMenu}
  >
    <ul class="space-y-5 w-48">
      {#each menuButtons as { href, icon: Icon, key }}
        <li>
          {#if key.includes("dark")}
            <DarkToggle />
          {:else}
            <a
              {href}
              data-sveltekit-preload-data="tap"
              onclick={hideMenu}
            >
              <button
                class="relative flex justify-center items-center font-semibold hover:opacity-80 gap-2"
              >
                <Icon width="32" />
                {t(key)}
                {#if key === "nav.dm" && $unreadDMs > 0}
                  <span class="badge-dot">{$unreadDMs > 99 ? "99+" : $unreadDMs}</span>
                {/if}
              </button>
            </a>
          {/if}
        </li>
      {/each}
    </ul>
    <hr class="my-4" />
    <a href="/?stay=true" aria-label="Coinos home">
      <CoinosLogo width="160" />
    </a>
  </div>
</div>

<style>
  .badge-dot {
    position: absolute;
    top: -2px;
    right: -2px;
    min-width: 18px;
    height: 18px;
    padding: 0 4px;
    border-radius: 9px;
    background: #f97316;
    color: white;
    font-size: 11px;
    font-weight: 700;
    line-height: 18px;
    text-align: center;
  }
</style>