@authrim/sveltekit 0.1.0 → 0.1.2
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/LICENSE +191 -191
- package/README.md +527 -531
- package/dist/components/AuthProvider.svelte +56 -56
- package/dist/components/ProtectedRoute.svelte +71 -71
- package/dist/components/SignInButton.svelte +93 -93
- package/dist/components/SignOutButton.svelte +72 -72
- package/dist/components/UserProfile.svelte +71 -71
- package/dist/ui/account/LinkAccountButton.svelte +133 -133
- package/dist/ui/account/LinkedAccountsList.svelte +233 -233
- package/dist/ui/account/UnlinkAccountButton.svelte +179 -179
- package/dist/ui/forms/EmailCodeForm.svelte +224 -224
- package/dist/ui/forms/PasskeyConditionalInput.svelte +173 -173
- package/dist/ui/forms/SocialLoginButtons.svelte +209 -209
- package/dist/ui/helpers/AuthError.svelte +124 -124
- package/dist/ui/helpers/AuthLoading.svelte +83 -83
- package/dist/ui/helpers/OTPInput.svelte +214 -214
- package/dist/ui/helpers/ResendCodeButton.svelte +140 -140
- package/dist/ui/passkey/PasskeyDeleteButton.svelte +177 -177
- package/dist/ui/passkey/PasskeyList.svelte +225 -225
- package/dist/ui/passkey/PasskeyRegisterButton.svelte +52 -52
- package/dist/ui/session/SessionExpiryIndicator.svelte +109 -109
- package/dist/ui/session/SessionList.svelte +231 -231
- package/dist/ui/session/SessionRevokeButton.svelte +72 -72
- package/dist/ui/shared/Badge.svelte +100 -100
- package/dist/ui/shared/Button.svelte +213 -213
- package/dist/ui/shared/Card.svelte +85 -85
- package/dist/ui/shared/Input.svelte +192 -192
- package/dist/ui/shared/Spinner.svelte +75 -75
- package/dist/ui/styles/base.css +168 -168
- package/dist/ui/styles/theme.css +279 -279
- package/dist/ui/templates/AccountSettingsTemplate.svelte +205 -205
- package/dist/ui/templates/LoginTemplate.svelte +234 -234
- package/dist/ui/templates/SignUpTemplate.svelte +345 -345
- package/package.json +112 -111
|
@@ -1,231 +1,231 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
SessionList Component
|
|
3
|
-
Display and manage active sessions
|
|
4
|
-
-->
|
|
5
|
-
<script lang="ts">
|
|
6
|
-
import { createEventDispatcher } from 'svelte';
|
|
7
|
-
import type { SessionItemDisplay } from '../types.js';
|
|
8
|
-
import Badge from '../shared/Badge.svelte';
|
|
9
|
-
import Spinner from '../shared/Spinner.svelte';
|
|
10
|
-
import SessionRevokeButton from './SessionRevokeButton.svelte';
|
|
11
|
-
import SessionExpiryIndicator from './SessionExpiryIndicator.svelte';
|
|
12
|
-
|
|
13
|
-
export let sessions: SessionItemDisplay[] = [];
|
|
14
|
-
export let currentSessionId: string | undefined = undefined;
|
|
15
|
-
export let loading = false;
|
|
16
|
-
export let revokingId: string | undefined = undefined;
|
|
17
|
-
let className = '';
|
|
18
|
-
export { className as class };
|
|
19
|
-
|
|
20
|
-
const dispatch = createEventDispatcher<{
|
|
21
|
-
revoke: { sessionId: string };
|
|
22
|
-
}>();
|
|
23
|
-
|
|
24
|
-
function formatDate(date: Date | undefined): string {
|
|
25
|
-
if (!date) return 'Unknown';
|
|
26
|
-
return new Intl.DateTimeFormat('en-US', {
|
|
27
|
-
month: 'short',
|
|
28
|
-
day: 'numeric',
|
|
29
|
-
hour: 'numeric',
|
|
30
|
-
minute: '2-digit',
|
|
31
|
-
}).format(date);
|
|
32
|
-
}
|
|
33
|
-
</script>
|
|
34
|
-
|
|
35
|
-
<div class="authrim-session-list {className}" {...$$restProps}>
|
|
36
|
-
{#if loading && sessions.length === 0}
|
|
37
|
-
<div class="authrim-session-list__loading">
|
|
38
|
-
<Spinner size="md" />
|
|
39
|
-
<span>Loading sessions...</span>
|
|
40
|
-
</div>
|
|
41
|
-
{:else if sessions.length === 0}
|
|
42
|
-
<div class="authrim-session-list__empty">
|
|
43
|
-
<p>No active sessions</p>
|
|
44
|
-
</div>
|
|
45
|
-
{:else}
|
|
46
|
-
<ul class="authrim-session-list__items">
|
|
47
|
-
{#each sessions as session, index (session.sessionId)}
|
|
48
|
-
<!-- isCurrent: session.isCurrent takes precedence if set, otherwise compare with currentSessionId -->
|
|
49
|
-
{@const isCurrent = session.isCurrent ?? session.sessionId === currentSessionId}
|
|
50
|
-
<li
|
|
51
|
-
class="authrim-session-list__item"
|
|
52
|
-
class:authrim-session-list__item--current={isCurrent}
|
|
53
|
-
style="animation-delay: {index * 50}ms"
|
|
54
|
-
>
|
|
55
|
-
<div class="authrim-session-list__icon">
|
|
56
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
57
|
-
{#if session.os?.toLowerCase().includes('mobile') || session.os?.toLowerCase().includes('ios') || session.os?.toLowerCase().includes('android')}
|
|
58
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 1.5H8.25A2.25 2.25 0 006 3.75v16.5a2.25 2.25 0 002.25 2.25h7.5A2.25 2.25 0 0018 20.25V3.75a2.25 2.25 0 00-2.25-2.25H13.5m-3 0V3h3V1.5m-3 0h3m-3 18.75h3"/>
|
|
59
|
-
{:else}
|
|
60
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M9 17.25v1.007a3 3 0 01-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0115 18.257V17.25m6-12V15a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 15V5.25m18 0A2.25 2.25 0 0018.75 3H5.25A2.25 2.25 0 003 5.25m18 0V12a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 12V5.25"/>
|
|
61
|
-
{/if}
|
|
62
|
-
</svg>
|
|
63
|
-
</div>
|
|
64
|
-
|
|
65
|
-
<div class="authrim-session-list__info">
|
|
66
|
-
<div class="authrim-session-list__name-row">
|
|
67
|
-
<span class="authrim-session-list__name">
|
|
68
|
-
{session.browser || 'Unknown browser'}
|
|
69
|
-
{#if session.os}
|
|
70
|
-
<span class="authrim-session-list__os">on {session.os}</span>
|
|
71
|
-
{/if}
|
|
72
|
-
</span>
|
|
73
|
-
{#if isCurrent}
|
|
74
|
-
<Badge size="sm" variant="success" dot>Current</Badge>
|
|
75
|
-
{/if}
|
|
76
|
-
</div>
|
|
77
|
-
|
|
78
|
-
<div class="authrim-session-list__meta">
|
|
79
|
-
{#if session.location || session.ip}
|
|
80
|
-
<span class="authrim-session-list__location">
|
|
81
|
-
{session.location || session.ip}
|
|
82
|
-
</span>
|
|
83
|
-
<span class="authrim-session-list__sep">·</span>
|
|
84
|
-
{/if}
|
|
85
|
-
{#if session.lastActiveAt}
|
|
86
|
-
<span>Active {formatDate(session.lastActiveAt)}</span>
|
|
87
|
-
{:else if session.createdAt}
|
|
88
|
-
<span>Started {formatDate(session.createdAt)}</span>
|
|
89
|
-
{/if}
|
|
90
|
-
</div>
|
|
91
|
-
|
|
92
|
-
{#if session.expiresAt}
|
|
93
|
-
<SessionExpiryIndicator expiresAt={session.expiresAt} />
|
|
94
|
-
{/if}
|
|
95
|
-
</div>
|
|
96
|
-
|
|
97
|
-
{#if !isCurrent}
|
|
98
|
-
<SessionRevokeButton
|
|
99
|
-
sessionId={session.sessionId}
|
|
100
|
-
loading={revokingId === session.sessionId}
|
|
101
|
-
on:click={() => dispatch('revoke', { sessionId: session.sessionId })}
|
|
102
|
-
/>
|
|
103
|
-
{/if}
|
|
104
|
-
</li>
|
|
105
|
-
{/each}
|
|
106
|
-
</ul>
|
|
107
|
-
{/if}
|
|
108
|
-
</div>
|
|
109
|
-
|
|
110
|
-
<style>
|
|
111
|
-
.authrim-session-list__loading {
|
|
112
|
-
display: flex;
|
|
113
|
-
flex-direction: column;
|
|
114
|
-
align-items: center;
|
|
115
|
-
gap: var(--authrim-space-3);
|
|
116
|
-
padding: var(--authrim-space-8);
|
|
117
|
-
color: var(--authrim-color-text-secondary);
|
|
118
|
-
font-size: var(--authrim-text-sm);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
.authrim-session-list__empty {
|
|
122
|
-
padding: var(--authrim-space-8);
|
|
123
|
-
text-align: center;
|
|
124
|
-
color: var(--authrim-color-text-muted);
|
|
125
|
-
font-size: var(--authrim-text-sm);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
.authrim-session-list__empty p {
|
|
129
|
-
margin: 0;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
.authrim-session-list__items {
|
|
133
|
-
list-style: none;
|
|
134
|
-
margin: 0;
|
|
135
|
-
padding: 0;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
.authrim-session-list__item {
|
|
139
|
-
display: flex;
|
|
140
|
-
align-items: flex-start;
|
|
141
|
-
gap: var(--authrim-space-4);
|
|
142
|
-
padding: var(--authrim-space-4);
|
|
143
|
-
border-bottom: 1px solid var(--authrim-color-border-subtle);
|
|
144
|
-
animation: slide-in var(--authrim-duration-normal) var(--authrim-ease-out) both;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
@keyframes slide-in {
|
|
148
|
-
from {
|
|
149
|
-
opacity: 0;
|
|
150
|
-
transform: translateX(8px);
|
|
151
|
-
}
|
|
152
|
-
to {
|
|
153
|
-
opacity: 1;
|
|
154
|
-
transform: translateX(0);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
.authrim-session-list__item:last-child {
|
|
159
|
-
border-bottom: none;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
.authrim-session-list__item--current {
|
|
163
|
-
background: var(--authrim-color-success-subtle);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
.authrim-session-list__icon {
|
|
167
|
-
flex-shrink: 0;
|
|
168
|
-
display: flex;
|
|
169
|
-
align-items: center;
|
|
170
|
-
justify-content: center;
|
|
171
|
-
width: 40px;
|
|
172
|
-
height: 40px;
|
|
173
|
-
background: var(--authrim-color-bg-subtle);
|
|
174
|
-
border-radius: var(--authrim-radius-md);
|
|
175
|
-
color: var(--authrim-color-text-secondary);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
.authrim-session-list__item--current .authrim-session-list__icon {
|
|
179
|
-
background: var(--authrim-color-bg);
|
|
180
|
-
color: var(--authrim-color-success);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
.authrim-session-list__icon svg {
|
|
184
|
-
width: 20px;
|
|
185
|
-
height: 20px;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
.authrim-session-list__info {
|
|
189
|
-
flex: 1;
|
|
190
|
-
min-width: 0;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
.authrim-session-list__name-row {
|
|
194
|
-
display: flex;
|
|
195
|
-
align-items: center;
|
|
196
|
-
gap: var(--authrim-space-2);
|
|
197
|
-
flex-wrap: wrap;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
.authrim-session-list__name {
|
|
201
|
-
font-size: var(--authrim-text-sm);
|
|
202
|
-
font-weight: 500;
|
|
203
|
-
color: var(--authrim-color-text);
|
|
204
|
-
letter-spacing: var(--authrim-tracking-tight);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
.authrim-session-list__os {
|
|
208
|
-
font-weight: 400;
|
|
209
|
-
color: var(--authrim-color-text-secondary);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
.authrim-session-list__meta {
|
|
213
|
-
display: flex;
|
|
214
|
-
align-items: center;
|
|
215
|
-
gap: var(--authrim-space-1);
|
|
216
|
-
margin-top: var(--authrim-space-1);
|
|
217
|
-
font-size: var(--authrim-text-xs);
|
|
218
|
-
color: var(--authrim-color-text-muted);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
.authrim-session-list__sep {
|
|
222
|
-
color: var(--authrim-color-border-strong);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
.authrim-session-list__location {
|
|
226
|
-
max-width: 120px;
|
|
227
|
-
overflow: hidden;
|
|
228
|
-
text-overflow: ellipsis;
|
|
229
|
-
white-space: nowrap;
|
|
230
|
-
}
|
|
231
|
-
</style>
|
|
1
|
+
<!--
|
|
2
|
+
SessionList Component
|
|
3
|
+
Display and manage active sessions
|
|
4
|
+
-->
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import { createEventDispatcher } from 'svelte';
|
|
7
|
+
import type { SessionItemDisplay } from '../types.js';
|
|
8
|
+
import Badge from '../shared/Badge.svelte';
|
|
9
|
+
import Spinner from '../shared/Spinner.svelte';
|
|
10
|
+
import SessionRevokeButton from './SessionRevokeButton.svelte';
|
|
11
|
+
import SessionExpiryIndicator from './SessionExpiryIndicator.svelte';
|
|
12
|
+
|
|
13
|
+
export let sessions: SessionItemDisplay[] = [];
|
|
14
|
+
export let currentSessionId: string | undefined = undefined;
|
|
15
|
+
export let loading = false;
|
|
16
|
+
export let revokingId: string | undefined = undefined;
|
|
17
|
+
let className = '';
|
|
18
|
+
export { className as class };
|
|
19
|
+
|
|
20
|
+
const dispatch = createEventDispatcher<{
|
|
21
|
+
revoke: { sessionId: string };
|
|
22
|
+
}>();
|
|
23
|
+
|
|
24
|
+
function formatDate(date: Date | undefined): string {
|
|
25
|
+
if (!date) return 'Unknown';
|
|
26
|
+
return new Intl.DateTimeFormat('en-US', {
|
|
27
|
+
month: 'short',
|
|
28
|
+
day: 'numeric',
|
|
29
|
+
hour: 'numeric',
|
|
30
|
+
minute: '2-digit',
|
|
31
|
+
}).format(date);
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<div class="authrim-session-list {className}" {...$$restProps}>
|
|
36
|
+
{#if loading && sessions.length === 0}
|
|
37
|
+
<div class="authrim-session-list__loading">
|
|
38
|
+
<Spinner size="md" />
|
|
39
|
+
<span>Loading sessions...</span>
|
|
40
|
+
</div>
|
|
41
|
+
{:else if sessions.length === 0}
|
|
42
|
+
<div class="authrim-session-list__empty">
|
|
43
|
+
<p>No active sessions</p>
|
|
44
|
+
</div>
|
|
45
|
+
{:else}
|
|
46
|
+
<ul class="authrim-session-list__items">
|
|
47
|
+
{#each sessions as session, index (session.sessionId)}
|
|
48
|
+
<!-- isCurrent: session.isCurrent takes precedence if set, otherwise compare with currentSessionId -->
|
|
49
|
+
{@const isCurrent = session.isCurrent ?? session.sessionId === currentSessionId}
|
|
50
|
+
<li
|
|
51
|
+
class="authrim-session-list__item"
|
|
52
|
+
class:authrim-session-list__item--current={isCurrent}
|
|
53
|
+
style="animation-delay: {index * 50}ms"
|
|
54
|
+
>
|
|
55
|
+
<div class="authrim-session-list__icon">
|
|
56
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
57
|
+
{#if session.os?.toLowerCase().includes('mobile') || session.os?.toLowerCase().includes('ios') || session.os?.toLowerCase().includes('android')}
|
|
58
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 1.5H8.25A2.25 2.25 0 006 3.75v16.5a2.25 2.25 0 002.25 2.25h7.5A2.25 2.25 0 0018 20.25V3.75a2.25 2.25 0 00-2.25-2.25H13.5m-3 0V3h3V1.5m-3 0h3m-3 18.75h3"/>
|
|
59
|
+
{:else}
|
|
60
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M9 17.25v1.007a3 3 0 01-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0115 18.257V17.25m6-12V15a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 15V5.25m18 0A2.25 2.25 0 0018.75 3H5.25A2.25 2.25 0 003 5.25m18 0V12a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 12V5.25"/>
|
|
61
|
+
{/if}
|
|
62
|
+
</svg>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<div class="authrim-session-list__info">
|
|
66
|
+
<div class="authrim-session-list__name-row">
|
|
67
|
+
<span class="authrim-session-list__name">
|
|
68
|
+
{session.browser || 'Unknown browser'}
|
|
69
|
+
{#if session.os}
|
|
70
|
+
<span class="authrim-session-list__os">on {session.os}</span>
|
|
71
|
+
{/if}
|
|
72
|
+
</span>
|
|
73
|
+
{#if isCurrent}
|
|
74
|
+
<Badge size="sm" variant="success" dot>Current</Badge>
|
|
75
|
+
{/if}
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<div class="authrim-session-list__meta">
|
|
79
|
+
{#if session.location || session.ip}
|
|
80
|
+
<span class="authrim-session-list__location">
|
|
81
|
+
{session.location || session.ip}
|
|
82
|
+
</span>
|
|
83
|
+
<span class="authrim-session-list__sep">·</span>
|
|
84
|
+
{/if}
|
|
85
|
+
{#if session.lastActiveAt}
|
|
86
|
+
<span>Active {formatDate(session.lastActiveAt)}</span>
|
|
87
|
+
{:else if session.createdAt}
|
|
88
|
+
<span>Started {formatDate(session.createdAt)}</span>
|
|
89
|
+
{/if}
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
{#if session.expiresAt}
|
|
93
|
+
<SessionExpiryIndicator expiresAt={session.expiresAt} />
|
|
94
|
+
{/if}
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
{#if !isCurrent}
|
|
98
|
+
<SessionRevokeButton
|
|
99
|
+
sessionId={session.sessionId}
|
|
100
|
+
loading={revokingId === session.sessionId}
|
|
101
|
+
on:click={() => dispatch('revoke', { sessionId: session.sessionId })}
|
|
102
|
+
/>
|
|
103
|
+
{/if}
|
|
104
|
+
</li>
|
|
105
|
+
{/each}
|
|
106
|
+
</ul>
|
|
107
|
+
{/if}
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<style>
|
|
111
|
+
.authrim-session-list__loading {
|
|
112
|
+
display: flex;
|
|
113
|
+
flex-direction: column;
|
|
114
|
+
align-items: center;
|
|
115
|
+
gap: var(--authrim-space-3);
|
|
116
|
+
padding: var(--authrim-space-8);
|
|
117
|
+
color: var(--authrim-color-text-secondary);
|
|
118
|
+
font-size: var(--authrim-text-sm);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.authrim-session-list__empty {
|
|
122
|
+
padding: var(--authrim-space-8);
|
|
123
|
+
text-align: center;
|
|
124
|
+
color: var(--authrim-color-text-muted);
|
|
125
|
+
font-size: var(--authrim-text-sm);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.authrim-session-list__empty p {
|
|
129
|
+
margin: 0;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.authrim-session-list__items {
|
|
133
|
+
list-style: none;
|
|
134
|
+
margin: 0;
|
|
135
|
+
padding: 0;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.authrim-session-list__item {
|
|
139
|
+
display: flex;
|
|
140
|
+
align-items: flex-start;
|
|
141
|
+
gap: var(--authrim-space-4);
|
|
142
|
+
padding: var(--authrim-space-4);
|
|
143
|
+
border-bottom: 1px solid var(--authrim-color-border-subtle);
|
|
144
|
+
animation: slide-in var(--authrim-duration-normal) var(--authrim-ease-out) both;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@keyframes slide-in {
|
|
148
|
+
from {
|
|
149
|
+
opacity: 0;
|
|
150
|
+
transform: translateX(8px);
|
|
151
|
+
}
|
|
152
|
+
to {
|
|
153
|
+
opacity: 1;
|
|
154
|
+
transform: translateX(0);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.authrim-session-list__item:last-child {
|
|
159
|
+
border-bottom: none;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.authrim-session-list__item--current {
|
|
163
|
+
background: var(--authrim-color-success-subtle);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.authrim-session-list__icon {
|
|
167
|
+
flex-shrink: 0;
|
|
168
|
+
display: flex;
|
|
169
|
+
align-items: center;
|
|
170
|
+
justify-content: center;
|
|
171
|
+
width: 40px;
|
|
172
|
+
height: 40px;
|
|
173
|
+
background: var(--authrim-color-bg-subtle);
|
|
174
|
+
border-radius: var(--authrim-radius-md);
|
|
175
|
+
color: var(--authrim-color-text-secondary);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.authrim-session-list__item--current .authrim-session-list__icon {
|
|
179
|
+
background: var(--authrim-color-bg);
|
|
180
|
+
color: var(--authrim-color-success);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.authrim-session-list__icon svg {
|
|
184
|
+
width: 20px;
|
|
185
|
+
height: 20px;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.authrim-session-list__info {
|
|
189
|
+
flex: 1;
|
|
190
|
+
min-width: 0;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.authrim-session-list__name-row {
|
|
194
|
+
display: flex;
|
|
195
|
+
align-items: center;
|
|
196
|
+
gap: var(--authrim-space-2);
|
|
197
|
+
flex-wrap: wrap;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.authrim-session-list__name {
|
|
201
|
+
font-size: var(--authrim-text-sm);
|
|
202
|
+
font-weight: 500;
|
|
203
|
+
color: var(--authrim-color-text);
|
|
204
|
+
letter-spacing: var(--authrim-tracking-tight);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.authrim-session-list__os {
|
|
208
|
+
font-weight: 400;
|
|
209
|
+
color: var(--authrim-color-text-secondary);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.authrim-session-list__meta {
|
|
213
|
+
display: flex;
|
|
214
|
+
align-items: center;
|
|
215
|
+
gap: var(--authrim-space-1);
|
|
216
|
+
margin-top: var(--authrim-space-1);
|
|
217
|
+
font-size: var(--authrim-text-xs);
|
|
218
|
+
color: var(--authrim-color-text-muted);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.authrim-session-list__sep {
|
|
222
|
+
color: var(--authrim-color-border-strong);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.authrim-session-list__location {
|
|
226
|
+
max-width: 120px;
|
|
227
|
+
overflow: hidden;
|
|
228
|
+
text-overflow: ellipsis;
|
|
229
|
+
white-space: nowrap;
|
|
230
|
+
}
|
|
231
|
+
</style>
|
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
SessionRevokeButton Component
|
|
3
|
-
Button to revoke a session
|
|
4
|
-
-->
|
|
5
|
-
<script lang="ts">
|
|
6
|
-
import { createEventDispatcher } from 'svelte';
|
|
7
|
-
import Spinner from '../shared/Spinner.svelte';
|
|
8
|
-
|
|
9
|
-
export let sessionId: string;
|
|
10
|
-
export let loading = false;
|
|
11
|
-
let className = '';
|
|
12
|
-
export { className as class };
|
|
13
|
-
|
|
14
|
-
const dispatch = createEventDispatcher<{ click: void }>();
|
|
15
|
-
</script>
|
|
16
|
-
|
|
17
|
-
<button
|
|
18
|
-
type="button"
|
|
19
|
-
class="authrim-session-revoke {className}"
|
|
20
|
-
disabled={loading}
|
|
21
|
-
on:click={() => dispatch('click')}
|
|
22
|
-
aria-label="Revoke session"
|
|
23
|
-
data-session-id={sessionId}
|
|
24
|
-
{...$$restProps}
|
|
25
|
-
>
|
|
26
|
-
{#if loading}
|
|
27
|
-
<Spinner size="sm" />
|
|
28
|
-
{:else}
|
|
29
|
-
<svg viewBox="0 0 20 20" fill="currentColor">
|
|
30
|
-
<path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"/>
|
|
31
|
-
</svg>
|
|
32
|
-
{/if}
|
|
33
|
-
</button>
|
|
34
|
-
|
|
35
|
-
<style>
|
|
36
|
-
.authrim-session-revoke {
|
|
37
|
-
flex-shrink: 0;
|
|
38
|
-
display: flex;
|
|
39
|
-
align-items: center;
|
|
40
|
-
justify-content: center;
|
|
41
|
-
width: 36px;
|
|
42
|
-
height: 36px;
|
|
43
|
-
padding: 0;
|
|
44
|
-
background: transparent;
|
|
45
|
-
border: none;
|
|
46
|
-
border-radius: var(--authrim-radius-sm);
|
|
47
|
-
color: var(--authrim-color-text-muted);
|
|
48
|
-
cursor: pointer;
|
|
49
|
-
transition:
|
|
50
|
-
color var(--authrim-duration-fast) var(--authrim-ease-default),
|
|
51
|
-
background-color var(--authrim-duration-fast) var(--authrim-ease-default);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.authrim-session-revoke:hover:not(:disabled) {
|
|
55
|
-
color: var(--authrim-color-error);
|
|
56
|
-
background: var(--authrim-color-error-subtle);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
.authrim-session-revoke:focus-visible {
|
|
60
|
-
outline: none;
|
|
61
|
-
box-shadow: var(--authrim-shadow-focus-error);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.authrim-session-revoke:disabled {
|
|
65
|
-
cursor: wait;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.authrim-session-revoke svg {
|
|
69
|
-
width: 18px;
|
|
70
|
-
height: 18px;
|
|
71
|
-
}
|
|
72
|
-
</style>
|
|
1
|
+
<!--
|
|
2
|
+
SessionRevokeButton Component
|
|
3
|
+
Button to revoke a session
|
|
4
|
+
-->
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import { createEventDispatcher } from 'svelte';
|
|
7
|
+
import Spinner from '../shared/Spinner.svelte';
|
|
8
|
+
|
|
9
|
+
export let sessionId: string;
|
|
10
|
+
export let loading = false;
|
|
11
|
+
let className = '';
|
|
12
|
+
export { className as class };
|
|
13
|
+
|
|
14
|
+
const dispatch = createEventDispatcher<{ click: void }>();
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<button
|
|
18
|
+
type="button"
|
|
19
|
+
class="authrim-session-revoke {className}"
|
|
20
|
+
disabled={loading}
|
|
21
|
+
on:click={() => dispatch('click')}
|
|
22
|
+
aria-label="Revoke session"
|
|
23
|
+
data-session-id={sessionId}
|
|
24
|
+
{...$$restProps}
|
|
25
|
+
>
|
|
26
|
+
{#if loading}
|
|
27
|
+
<Spinner size="sm" />
|
|
28
|
+
{:else}
|
|
29
|
+
<svg viewBox="0 0 20 20" fill="currentColor">
|
|
30
|
+
<path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"/>
|
|
31
|
+
</svg>
|
|
32
|
+
{/if}
|
|
33
|
+
</button>
|
|
34
|
+
|
|
35
|
+
<style>
|
|
36
|
+
.authrim-session-revoke {
|
|
37
|
+
flex-shrink: 0;
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
justify-content: center;
|
|
41
|
+
width: 36px;
|
|
42
|
+
height: 36px;
|
|
43
|
+
padding: 0;
|
|
44
|
+
background: transparent;
|
|
45
|
+
border: none;
|
|
46
|
+
border-radius: var(--authrim-radius-sm);
|
|
47
|
+
color: var(--authrim-color-text-muted);
|
|
48
|
+
cursor: pointer;
|
|
49
|
+
transition:
|
|
50
|
+
color var(--authrim-duration-fast) var(--authrim-ease-default),
|
|
51
|
+
background-color var(--authrim-duration-fast) var(--authrim-ease-default);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.authrim-session-revoke:hover:not(:disabled) {
|
|
55
|
+
color: var(--authrim-color-error);
|
|
56
|
+
background: var(--authrim-color-error-subtle);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.authrim-session-revoke:focus-visible {
|
|
60
|
+
outline: none;
|
|
61
|
+
box-shadow: var(--authrim-shadow-focus-error);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.authrim-session-revoke:disabled {
|
|
65
|
+
cursor: wait;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.authrim-session-revoke svg {
|
|
69
|
+
width: 18px;
|
|
70
|
+
height: 18px;
|
|
71
|
+
}
|
|
72
|
+
</style>
|