@nymphjs/tilmeld-setup 1.0.0-beta.11 → 1.0.0-beta.111

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,12 @@
1
- <svelte:window on:resize={setMiniWindow} />
1
+ <svelte:window onresize={setMiniWindow} />
2
+
2
3
  <TopAppBar variant="static" class="tilmeld-top-app-bar">
3
4
  <Row>
4
5
  <Section>
5
6
  {#if miniWindow}
6
7
  <IconButton
7
8
  class="material-icons"
8
- on:click={() => (drawerOpen = !drawerOpen)}>menu</IconButton
9
+ onclick={() => (drawerOpen = !drawerOpen)}>menu</IconButton
9
10
  >
10
11
  {/if}
11
12
  <Title style={miniWindow ? 'padding-left: 0;' : ''}>
@@ -19,7 +20,7 @@
19
20
  rel="noreferrer"
20
21
  title="Nymph/Tilmeld on GitHub"
21
22
  >
22
- <Icon component={Svg} viewBox="0 0 24 24">
23
+ <Icon tag="svg" viewBox="0 0 24 24">
23
24
  <path fill="currentColor" d={mdiGithub} />
24
25
  </Icon>
25
26
  </IconButton>
@@ -29,34 +30,24 @@
29
30
  rel="noreferrer"
30
31
  title="SciActive on Mastodon"
31
32
  >
32
- <Icon component={Svg} viewBox="0 0 24 24">
33
+ <Icon tag="svg" viewBox="0 0 24 24">
33
34
  <path fill="currentColor" d={mdiMastodon} />
34
35
  </Icon>
35
36
  </IconButton>
36
- <IconButton
37
- href="https://twitter.com/SciActive"
38
- target="_blank"
39
- rel="noreferrer"
40
- title="SciActive on Twitter"
41
- >
42
- <Icon component={Svg} viewBox="0 0 24 24">
43
- <path fill="currentColor" d={mdiTwitter} />
44
- </Icon>
45
- </IconButton>
46
37
  <div>
47
38
  <IconButton
48
39
  title="Account"
49
- on:click={() => user != null && accountMenu.setOpen(true)}
40
+ onclick={() => $user != null && accountMenu.setOpen(true)}
50
41
  >
51
42
  <Icon tag="img" src={userAvatar} />
52
43
  </IconButton>
53
44
  <Menu bind:this={accountMenu} anchorCorner="BOTTOM_LEFT">
54
45
  <List>
55
- <Item on:SMUI:action={() => (accountOpen = true)}>
46
+ <Item onSMUIAction={() => (accountOpen = true)}>
56
47
  <Text>Account Details</Text>
57
48
  </Item>
58
49
  <Separator />
59
- <Item on:SMUI:action={() => user?.$logout()}>
50
+ <Item onSMUIAction={() => $user?.$logout()}>
60
51
  <Text>Logout</Text>
61
52
  </Item>
62
53
  </List>
@@ -74,7 +65,7 @@
74
65
  : 'hide-initial-small'}"
75
66
  >
76
67
  <Content>
77
- <List>
68
+ <List tag="div">
78
69
  {#if tilmeldAdmin}
79
70
  {#each sections as section (section.name)}
80
71
  {#if 'separator' in section}
@@ -82,13 +73,14 @@
82
73
  {:else}
83
74
  <Item
84
75
  bind:this={section.component}
85
- nonInteractive={!('route' in section)}
86
- on:click={() => {
87
- if ('route' in section) {
88
- active = section.route ?? Intro;
89
- }
90
- }}
91
- activated={active === section.route}
76
+ tag="a"
77
+ nonInteractive={!('href' in section)}
78
+ href={'href' in section ? `#${section.href}` : undefined}
79
+ activated={section.absolute
80
+ ? `${currentMatch.route.path}/` === section.href
81
+ : `${currentMatch.route.path}/`.startsWith(
82
+ section.href ?? '!',
83
+ )}
92
84
  style={section.indent
93
85
  ? 'margin-left: ' + section.indent * 25 + 'px;'
94
86
  : ''}
@@ -97,12 +89,12 @@
97
89
  </Item>
98
90
  {/if}
99
91
  {/each}
100
- {:else if user == null}
101
- <Item on:click={() => (drawerOpen = false)} activated>
92
+ {:else if $user == null}
93
+ <Item tag="span" onclick={() => (drawerOpen = false)} activated>
102
94
  <Text class="mdc-theme--on-secondary">Login</Text>
103
95
  </Item>
104
96
  {:else}
105
- <Item on:click={() => (drawerOpen = false)} activated>
97
+ <Item tag="span" onclick={() => (drawerOpen = false)} activated>
106
98
  <Text class="mdc-theme--on-secondary">Forbidden</Text>
107
99
  </Item>
108
100
  {/if}
@@ -116,83 +108,157 @@
116
108
  <AppContent class="tilmeld-app-content">
117
109
  <main class="tilmeld-main-content" bind:this={mainContent}>
118
110
  {#if tilmeldAdmin}
119
- {#if clientConfig}
120
- <svelte:component this={active} />
111
+ {#if $clientConfig}
112
+ <CurrentRoute {router} {params} {clientConfig} {user} />
121
113
  {:else}
122
114
  Loading...
123
115
  {/if}
124
- {:else if user == null}
116
+ {:else if $user === null}
125
117
  <section style="display: flex; justify-content: center;">
126
- <Login {User} {clientConfig} />
118
+ <Login
119
+ {User}
120
+ {clientConfig}
121
+ showExistingUserToggle={allowRegistration}
122
+ />
127
123
  </section>
124
+ {:else if $user === undefined}
125
+ Loading...
128
126
  {:else}
129
127
  <section>You don't have permission to access this app.</section>
130
128
  {/if}
131
- <Account bind:open={accountOpen} {User} {clientConfig} />
129
+ <Account bind:open={accountOpen} {User} {user} {clientConfig} />
132
130
  </main>
133
131
  </AppContent>
134
132
  </div>
135
133
 
136
134
  <script lang="ts">
137
- import { onMount, SvelteComponent } from 'svelte';
135
+ import type { Component } from 'svelte';
136
+ import { onMount } from 'svelte';
137
+ import type { Writable } from 'svelte/store';
138
+ import { writable } from 'svelte/store';
139
+ import Navigo from 'navigo';
138
140
  import type {
139
141
  User as UserClass,
140
142
  ClientConfig,
141
143
  CurrentUserData,
142
144
  } from '@nymphjs/tilmeld-client';
143
145
  import { Login, Account } from '@nymphjs/tilmeld-components';
144
- import { mdiGithub, mdiMastodon, mdiTwitter } from '@mdi/js';
146
+ import { mdiGithub, mdiMastodon } from '@mdi/js';
145
147
  import TopAppBar, { Row, Section, Title } from '@smui/top-app-bar';
146
148
  import Drawer, { Content, Scrim, AppContent } from '@smui/drawer';
147
149
  import IconButton from '@smui/icon-button';
148
150
  import List, { Item, Text, Separator } from '@smui/list';
149
151
  import Menu from '@smui/menu';
150
- import { Icon, Svg } from '@smui/common';
152
+ import { Icon } from '@smui/common';
151
153
 
152
154
  import { User } from './nymph';
153
- import Intro from './Intro.svelte';
154
- import Users from './Users.svelte';
155
- import Groups from './Groups.svelte';
156
- import type { SvelteComponentDev } from 'svelte/internal';
155
+ import Intro from './routes/Intro.svelte';
156
+ import Users from './routes/Users.svelte';
157
+ import UserEdit from './routes/UserEdit.svelte';
158
+ import Groups from './routes/Groups.svelte';
159
+ import GroupEdit from './routes/GroupEdit.svelte';
160
+ import NotFound from './routes/NotFound.svelte';
157
161
 
158
162
  const DEFAULT_AVATAR = 'https://secure.gravatar.com/avatar/?d=mm&s=40';
163
+ const allowRegistration = (window as any).allowRegistration;
159
164
 
160
165
  let mainContent: HTMLElement;
161
- let miniWindow = false;
162
- let drawerOpen = false;
166
+ let miniWindow = $state(false);
167
+ let drawerOpen = $state(false);
163
168
  let accountMenu: any;
164
- let active: typeof SvelteComponentDev = Intro;
165
- let clientConfig: ClientConfig;
166
- let user: (UserClass & CurrentUserData) | undefined = undefined;
167
- let userAvatar: string = DEFAULT_AVATAR;
168
- let tilmeldAdmin: boolean | undefined = undefined;
169
- let accountOpen = false;
170
-
171
- $: if (active && mainContent) {
172
- drawerOpen = false;
173
- mainContent.scrollTop = 0;
174
- }
169
+ let clientConfig: Writable<ClientConfig | undefined> = writable();
170
+ let user: Writable<(UserClass & CurrentUserData) | null | undefined> =
171
+ writable();
172
+ let userAvatar: string = $state(DEFAULT_AVATAR);
173
+ let tilmeldAdmin: boolean | undefined = $state();
174
+ let accountOpen = $state(false);
175
175
 
176
- $: if (user) {
177
- user.$gatekeeper('tilmeld/admin').then((value) => (tilmeldAdmin = value));
178
- user.$getAvatar().then((value) => (userAvatar = value));
179
- } else {
180
- tilmeldAdmin = undefined;
181
- userAvatar = DEFAULT_AVATAR;
182
- }
176
+ $effect(() => {
177
+ if ($user) {
178
+ $user
179
+ .$gatekeeper('tilmeld/admin')
180
+ .then((value) => (tilmeldAdmin = value));
181
+ $user.$getAvatar().then((value) => (userAvatar = value));
182
+ } else {
183
+ tilmeldAdmin = undefined;
184
+ userAvatar = DEFAULT_AVATAR;
185
+ }
186
+ });
187
+
188
+ const router = new Navigo('/', { hash: true });
189
+ let CurrentRoute: Component<any> = $state(Intro);
190
+ let params: any = $state({});
191
+
192
+ router.hooks({
193
+ before(done, match) {
194
+ if (mainContent) {
195
+ drawerOpen = false;
196
+ mainContent.scrollTop = 0;
197
+ }
198
+
199
+ currentMatch = match;
200
+
201
+ done();
202
+ },
203
+ });
204
+
205
+ router.on({
206
+ '/': () => {
207
+ CurrentRoute = Intro;
208
+ params = {};
209
+ },
210
+ '/users/edit/:guid': ({ data }: any) => {
211
+ CurrentRoute = UserEdit;
212
+ params = data;
213
+ },
214
+ '/users/': () => {
215
+ CurrentRoute = Users;
216
+ params = {};
217
+ },
218
+ '/users/:query?': ({ data }: any) => {
219
+ CurrentRoute = Users;
220
+ params = data;
221
+ },
222
+ '/groups/edit/:guid': ({ data }: any) => {
223
+ CurrentRoute = GroupEdit;
224
+ params = data;
225
+ },
226
+ '/groups/': () => {
227
+ CurrentRoute = Groups;
228
+ params = {};
229
+ },
230
+ '/groups/:query?': ({ data }: any) => {
231
+ CurrentRoute = Groups;
232
+ params = data;
233
+ },
234
+ });
235
+
236
+ router.notFound(({ hashString }: any) => {
237
+ if (hashString === '') {
238
+ router.navigate('/', { historyAPIMethod: 'replaceState' });
239
+ } else {
240
+ CurrentRoute = NotFound;
241
+ params = {};
242
+ }
243
+ });
244
+
245
+ let currentMatch = $state(router.getCurrentLocation());
246
+ router.resolve();
183
247
 
184
248
  const sections: (
185
249
  | {
186
250
  name: string;
187
251
  indent: number;
188
- route?: typeof SvelteComponentDev;
189
- component?: SvelteComponent;
252
+ href?: string;
253
+ absolute?: boolean;
254
+ component?: ReturnType<Component<any>>;
190
255
  }
191
256
  | { name: string; separator: true }
192
257
  )[] = [
193
258
  {
194
259
  name: 'Introduction',
195
- route: Intro,
260
+ href: '/',
261
+ absolute: true,
196
262
  indent: 0,
197
263
  },
198
264
  {
@@ -201,31 +267,37 @@
201
267
  },
202
268
  {
203
269
  name: 'Users',
204
- route: Users,
270
+ href: 'users/',
205
271
  indent: 0,
206
272
  },
207
273
  {
208
274
  name: 'Groups',
209
- route: Groups,
275
+ href: 'groups/',
210
276
  indent: 0,
211
277
  },
212
278
  ];
213
279
 
214
280
  const onLogin = (currentUser: UserClass & CurrentUserData) => {
215
- user = currentUser;
281
+ $user = currentUser;
282
+ // Helps with admin and debugging.
283
+ (window as any).user = currentUser;
216
284
  };
217
285
  const onLogout = () => {
218
- user = undefined;
286
+ $user = null;
287
+ // Helps with admin and debugging.
288
+ (window as any).user = null;
219
289
  };
220
290
 
221
291
  onMount(setMiniWindow);
222
292
  onMount(async () => {
223
293
  User.on('login', onLogin);
224
294
  User.on('logout', onLogout);
225
- user = (await User.current()) ?? undefined;
226
- });
227
- onMount(async () => {
228
- clientConfig = await User.getClientConfig();
295
+
296
+ $clientConfig = await User.getClientConfig();
297
+
298
+ $user = await User.current();
299
+ // Helps with admin and debugging.
300
+ (window as any).user = $user;
229
301
  });
230
302
 
231
303
  function setMiniWindow() {
package/app/src/nymph.ts CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  } from '@nymphjs/tilmeld-client';
7
7
 
8
8
  const nymph = new Nymph(
9
- (window as unknown as { nymphOptions: NymphOptions }).nymphOptions
9
+ (window as unknown as { nymphOptions: NymphOptions }).nymphOptions,
10
10
  );
11
11
  const User = nymph.addEntityClass(UserClass);
12
12
  const Group = nymph.addEntityClass(GroupClass);