aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Layout/Dropdown.svelte
blob: fb270dfebf3ac05dd7b644c2f2afec202a4d3696 (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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<script lang="ts">
  interface Item {
    name: string;
    url: string;
    onClick?: () => void;
    preventDefault?: boolean;
  }

  export let items: Item[] = [];
  export let title: string | undefined = undefined;
  export let header = true;
  export let center = false;

  let open = false;

  const handleClickOutside = (event: any) => {
    if (!event.target.closest('.dropdown')) open = false;
  };
</script>

<svelte:window on:click={handleClickOutside} />

<div
  class="dropdown"
  id="dropdown"
  style={`--dropdown-left: ${center ? '50%' : 'unset'}; --dropdown-transform: ${
    center ? 'translateX(-50%)' : 'unset'
  };`}
>
  <span
    class={`${header ? 'header-item' : ''} dropdown-toggle`}
    id="dropdown-toggle"
    on:click|preventDefault={() => (open = !open)}
    on:keydown={() => {}}
    role="button"
    tabindex="0"
  >
    {#if title}
      {title}
    {:else}
      <slot name="title" />
    {/if}
  </span>

  <div class={`dropdown-content card card-small ${open ? 'dropdown-open' : ''}`}>
    {#each items as item}
      <a
        href={item.url}
        class="header-item"
        on:click={(e) => {
          if (item.preventDefault) e.preventDefault();
          if (item.onClick) item.onClick();
        }}
      >
        {item.name}
      </a>
    {/each}
  </div>
</div>

<style lang="scss">
  a {
    color: var(--base06);
  }

  .header-item {
    margin: 0 0.5rem;
  }

  .header-item:hover {
    text-decoration: none;
  }

  .header-item:active {
    outline: none;
  }

  .dropdown {
    position: relative;
    display: inline-block;
  }

  .dropdown-content {
    display: block;
    position: absolute;
    min-width: max-content;
    padding: 0.5em 0;
    opacity: 0;
    transform: translateY(-20px);
    visibility: hidden;
    $delay: 0.25s;
    transition: opacity $delay ease, transform $delay ease, visibility 0s linear $delay;
    left: var(--dropdown-left);
    transform: var(--dropdown-transform);
    z-index: 1;
  }

  .dropdown-open {
    opacity: 1;
    transform: translateY(0);
    visibility: visible;
    transition-delay: 0s, 0s, 0s;
    left: var(--dropdown-left);
    transform: var(--dropdown-transform);
  }

  .dropdown:hover .dropdown-content {
    opacity: 1;
    transform: translateY(0);
    visibility: visible;
    transition-delay: 0s, 0s, 0s;
    left: var(--dropdown-left);
    transform: var(--dropdown-transform);
  }

  .dropdown-content a {
    padding: 0.5em 0.75em;
    text-decoration: none;
    display: block;
  }

  .dropdown-content a:hover {
    border-radius: 8px;
    backdrop-filter: blur(160px);
    background-color: var(--base01);
  }
</style>