@axium/client 0.20.1 → 0.21.0

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.
package/assets/styles.css CHANGED
@@ -312,6 +312,7 @@ h6 {
312
312
  gap: 1em;
313
313
  text-align: right;
314
314
  align-items: end;
315
+ z-index: 25;
315
316
  }
316
317
 
317
318
  div.toast {
@@ -19,7 +19,6 @@ export declare function session(): {
19
19
  isAdmin: boolean;
20
20
  isSuspended: boolean;
21
21
  emailVerified?: Date | null | undefined;
22
- image?: string | null | undefined;
23
22
  };
24
23
  name?: string | null | undefined;
25
24
  };
package/dist/config.d.ts CHANGED
@@ -16,7 +16,6 @@ export declare const ClientConfig: z.ZodObject<{
16
16
  name: z.ZodString;
17
17
  email: z.ZodEmail;
18
18
  emailVerified: z.ZodOptional<z.ZodNullable<z.ZodCoercedDate<unknown>>>;
19
- image: z.ZodOptional<z.ZodNullable<z.ZodURL>>;
20
19
  preferences: z.ZodLazy<z.ZodObject<{
21
20
  debug: z.ZodDefault<z.ZodBoolean>;
22
21
  }, z.core.$strip>>;
package/dist/locales.d.ts CHANGED
@@ -112,8 +112,13 @@ declare let currentLoaded: {
112
112
  readonly title: "Passkeys";
113
113
  };
114
114
  readonly personal_info: "Personal Information";
115
+ readonly pfp: {
116
+ readonly update: "Upload";
117
+ readonly remove: "Remove";
118
+ readonly toast_removed: "Profile picture removed";
119
+ readonly toast_updated: "Profile picture updated";
120
+ };
115
121
  readonly preferences: "Preferences";
116
- readonly profile_alt: "User profile";
117
122
  readonly sessions: "Sessions";
118
123
  readonly title: "Your Account";
119
124
  readonly user_id: "User ID";
package/lib/Icon.svelte CHANGED
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
- const { i, ...rest } = $props();
2
+ import type { SVGAttributes } from 'svelte/elements';
3
+ const { i, ...rest }: { i: string } & SVGAttributes<SVGSVGElement> = $props();
3
4
  const [style, id] = $derived(i.includes('/') ? i.split('/') : ['solid', i]);
4
5
  const href = $derived(`/icons/${style}.svg#${id}`);
5
6
  </script>
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { text } from '@axium/client';
3
- import { getUserImage } from '@axium/core';
4
- import type { User } from '@axium/core/user';
3
+ import type { UserPublic } from '@axium/core/user';
4
+ import UserPFP from './UserPFP.svelte';
5
5
 
6
6
  const {
7
7
  user,
@@ -10,7 +10,7 @@
10
10
  href,
11
11
  you = false,
12
12
  }: {
13
- user: Partial<User>;
13
+ user: UserPublic;
14
14
  /** If true, don't show the picture */
15
15
  compact?: boolean;
16
16
  /** Whether the user is viewing their own profile */
@@ -24,7 +24,7 @@
24
24
 
25
25
  <a class={['User', self && 'self']} {href}>
26
26
  {#if !compact}
27
- <img src={getUserImage(user)} alt={user.name} />
27
+ <UserPFP {user} />
28
28
  {/if}
29
29
  {user.name}
30
30
  {#if self && you}
@@ -38,12 +38,4 @@
38
38
  width: max-content;
39
39
  height: max-content;
40
40
  }
41
-
42
- img {
43
- width: 2em;
44
- height: 2em;
45
- border-radius: 50%;
46
- vertical-align: middle;
47
- margin-right: 0.5em;
48
- }
49
41
  </style>
@@ -1,9 +1,10 @@
1
1
  <script lang="ts">
2
2
  import { text } from '@axium/client';
3
3
  import { fetchAPI } from '@axium/client/requests';
4
- import { getUserImage, type UserPublic } from '@axium/core';
4
+ import type { UserPublic } from '@axium/core';
5
5
  import { errorText } from 'ioium';
6
6
  import Icon from './Icon.svelte';
7
+ import UserPFP from './UserPFP.svelte';
7
8
 
8
9
  const {
9
10
  onSelect,
@@ -63,7 +64,7 @@
63
64
  {#if !excludeTargets.includes(result.target)}
64
65
  <div class="result" onclick={select(result.target)}>
65
66
  {#if result.type == 'user'}
66
- <span><img src={getUserImage(result.value)} alt={result.value.name} />{result.value.name}</span>
67
+ <span><UserPFP user={result.value} /> {result.value.name}</span>
67
68
  {:else if result.type == 'role'}
68
69
  <span>
69
70
  <span class="icon-text non-user"><Icon i="at" />{result.value}</span>
@@ -135,12 +136,4 @@
135
136
  cursor: pointer;
136
137
  background-color: var(--bg-strong);
137
138
  }
138
-
139
- img {
140
- width: 2em;
141
- height: 2em;
142
- border-radius: 50%;
143
- vertical-align: middle;
144
- margin-right: 0.5em;
145
- }
146
139
  </style>
@@ -1,10 +1,10 @@
1
1
  <script lang="ts">
2
2
  import { fetchAPI, text } from '@axium/client';
3
- import { getUserImage } from '@axium/core';
4
3
  import type { UserPublic } from '@axium/core/user';
5
4
  import Icon from './Icon.svelte';
6
5
  import Logout from './Logout.svelte';
7
6
  import Popover from './Popover.svelte';
7
+ import UserPFP from './UserPFP.svelte';
8
8
 
9
9
  const { user }: { user?: UserPublic } = $props();
10
10
  </script>
@@ -13,7 +13,7 @@
13
13
  <Popover>
14
14
  {#snippet toggle()}
15
15
  <div class="UserMenu toggle">
16
- <img src={getUserImage(user)} alt={user.name} />
16
+ <UserPFP {user} />
17
17
  {user.name}
18
18
  </div>
19
19
  {/snippet}
@@ -73,14 +73,6 @@
73
73
  background-color: var(--bg-alt);
74
74
  }
75
75
 
76
- img {
77
- width: 2em;
78
- height: 2em;
79
- border-radius: 50%;
80
- vertical-align: middle;
81
- margin-right: 0.5em;
82
- }
83
-
84
76
  .logout {
85
77
  color: hsl(0 33 var(--fg-light));
86
78
  font-size: 16px;
@@ -0,0 +1,42 @@
1
+ <script lang="ts">
2
+ import type { UserPublic } from '@axium/core';
3
+ import { colorHashRGB } from '@axium/core/color';
4
+
5
+ let { user, isDefault = $bindable() }: { user: UserPublic; isDefault?: boolean } = $props();
6
+
7
+ const defaultImage = $derived(
8
+ `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" style="background-color:${colorHashRGB(user.name ?? '\0')};display:flex;align-items:center;justify-content:center;">
9
+ <text x="23" y="28" style="font-family:sans-serif;font-weight:bold;" fill="white">${(user.name.replaceAll(/\W/g, '') || '?')[0]}</text>
10
+ </svg>`.replaceAll(/[\t\n]/g, '')
11
+ );
12
+
13
+ let src = $state(`/raw/pfp/${user.id}`);
14
+
15
+ $effect(() => {
16
+ // Reset the attempted source when the user changes
17
+ src = `/raw/pfp/${user.id}`;
18
+ });
19
+ </script>
20
+
21
+ <img
22
+ class="UserPFP"
23
+ {src}
24
+ alt={user.name}
25
+ onerror={() => {
26
+ isDefault = true;
27
+ src = defaultImage;
28
+ }}
29
+ />
30
+
31
+ <style>
32
+ img.UserPFP {
33
+ width: var(--size, 2em);
34
+ height: var(--size, 2em);
35
+ border-radius: 50%;
36
+ border: 1px solid #8888;
37
+ vertical-align: middle;
38
+ margin-right: 0.5em;
39
+ /* see https://drafts.csswg.org/css-image-animation-1/ */
40
+ image-animation: stopped;
41
+ }
42
+ </style>
package/lib/index.ts CHANGED
@@ -15,6 +15,7 @@ export { default as Upload } from './Upload.svelte';
15
15
  export { default as URLText } from './URLText.svelte';
16
16
  export { default as UserCard } from './UserCard.svelte';
17
17
  export { default as UserDiscovery } from './UserDiscovery.svelte';
18
+ export { default as UserPFP } from './UserPFP.svelte';
18
19
  export { default as UserMenu } from './UserMenu.svelte';
19
20
  export { default as Version } from './Version.svelte';
20
21
  export { default as ZodForm } from './ZodForm.svelte';
package/locales/en.json CHANGED
@@ -106,8 +106,13 @@
106
106
  "title": "Passkeys"
107
107
  },
108
108
  "personal_info": "Personal Information",
109
+ "pfp": {
110
+ "update": "Upload",
111
+ "remove": "Remove",
112
+ "toast_removed": "Profile picture removed",
113
+ "toast_updated": "Profile picture updated"
114
+ },
109
115
  "preferences": "Preferences",
110
- "profile_alt": "User profile",
111
116
  "sessions": "Sessions",
112
117
  "title": "Your Account",
113
118
  "user_id": "User ID",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axium/client",
3
- "version": "0.20.1",
3
+ "version": "0.21.0",
4
4
  "author": "James Prevett <jp@jamespre.dev>",
5
5
  "funding": {
6
6
  "type": "individual",