summaryrefslogtreecommitdiff
path: root/ui/routes/(app)/+layout.svelte
blob: 86bc3307e68efc862420b0690a80221407c61753 (plain)
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
<script>
  import { page } from '$app/stores';
  import { goto } from '$app/navigation';
  import { onMount, onDestroy, getContext } from 'svelte';

  import { boot, subscribeToEvents } from '$lib/apiServer';
  import { currentUser, logins, channelsList, messages } from '$lib/store';

  import ChannelList from '$lib/components/ChannelList.svelte';
  import CreateChannelForm from '$lib/components/CreateChannelForm.svelte';

  let events = null;

  let pageContext = getContext('page');
  let { children } = $props();
  let loading = $state(true);
  let channel = $derived($page.params.channel);

  function onBooted(boot) {
    currentUser.update(() => ({
      id: boot.login.id,
      username: boot.login.name
    }));
    logins.update((value) => value.setLogins(boot.logins));
    channelsList.update((value) => value.setChannels(boot.channels));
    messages.update((value) => value.setMessages(boot.messages));
  }

  onMount(async () => {
    let response = await boot();
    switch (response.status) {
      case 200:
        onBooted(response.data);
        events = subscribeToEvents(response.data.resume_point);
        break;
      case 401:
        currentUser.update(() => null);
        goto('/login');
        break;
      case 503:
        currentUser.update(() => null);
        goto('/setup');
        break;
      default:
        // TODO: display error.
        break;
    }
    loading = false;
  });

  onDestroy(async () => {
    if (events !== null) {
      events.close();
    }
  });
</script>

<svelte:head>
  <title>pilcrow</title>
</svelte:head>

{#if loading}
  <h2>Loading&hellip;</h2>
{:else}
  <div id="interface" class="p-2">
    <nav id="sidebar" data-expanded={pageContext.showMenu}>
      <div class="channel-list">
        <ChannelList active={channel} channels={$channelsList.channels} />
      </div>
      <div class="create-channel">
        <CreateChannelForm />
      </div>
    </nav>
    <main class="pl-4">
      {@render children?.()}
    </main>
  </div>
{/if}

<style>
  :root {
    --app-bar-height: 68px;
    --input-row-height: 2rem;
    --interface-padding: 16px;
  }

  #interface {
    margin: unset;
    display: grid;
    grid-template:
      'side main' 1fr
      / auto 1fr;
    height: calc(100vh - var(--app-bar-height));

    @media (width > 640px) {
      --overlay: static;
      --translate: 0;
    }
  }
  nav {
    grid-area: side;
    background-color: rgb(var(--color-surface-800));
    inset: auto auto 0 0;
    padding: 0.25rem;
    position: var(--overlay, absolute);
    transition: translate 300ms ease-out;
    width: 21rem;
    height: calc(100vh - var(--app-bar-height) - var(--interface-padding));
    z-index: 10;
  }
  main {
    grid-area: main;
    height: calc(100vh - var(--app-bar-height) - var(--interface-padding));
  }
  .channel-list {
    height: calc(
      100vh - var(--app-bar-height) - var(--interface-padding) - var(--input-row-height)
    );
    overflow: auto;
  }
  nav[data-expanded='false'] {
    translate: var(--translate, -100% 0);
  }
</style>