tangled
alpha
login
or
join now
mary.my.id
/
boat
22
fork
atom
handy online tools for AT Protocol
boat.kelinci.net
atproto
bluesky
atcute
typescript
solidjs
22
fork
atom
overview
issues
pulls
pipelines
feat: copy plc audit entry to clipboard
mary.my.id
1 year ago
2fa56343
b0d1f544
verified
This commit was signed with the committer's
known signature
.
mary.my.id
SSH Key Fingerprint:
SHA256:ZlTP/auFSGpGnaoDg4mCTG1g9OZvXp62jWR4c6H4O3c=
+62
-5
3 changed files
expand all
collapse all
unified
split
src
components
ic-icons
baseline-check.tsx
baseline-content-copy.tsx
views
identity
plc-oplogs.tsx
+5
src/components/ic-icons/baseline-check.tsx
···
1
1
+
import { createIcon } from './_icon';
2
2
+
3
3
+
const CheckIcon = createIcon([['M9 16.17L4.83 12l-1.42 1.41L9 19L21 7l-1.41-1.41z']]);
4
4
+
5
5
+
export default CheckIcon;
+9
src/components/ic-icons/baseline-content-copy.tsx
···
1
1
+
import { createIcon } from './_icon';
2
2
+
3
3
+
const ContentCopyIcon = createIcon([
4
4
+
[
5
5
+
'M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2m0 16H8V7h11z',
6
6
+
],
7
7
+
]);
8
8
+
9
9
+
export default ContentCopyIcon;
+48
-5
src/views/identity/plc-oplogs.tsx
···
1
1
-
import { JSX, Match, Switch } from 'solid-js';
1
1
+
import { createSignal, JSX, Match, onCleanup, Switch } from 'solid-js';
2
2
import * as v from 'valibot';
3
3
4
4
import { At } from '@atcute/client/lexicons';
···
15
15
import CircularProgressView from '~/components/circular-progress-view';
16
16
import DiffTable from '~/components/diff-table';
17
17
import ErrorView from '~/components/error-view';
18
18
+
import ContentCopyIcon from '~/components/ic-icons/baseline-content-copy';
19
19
+
import CheckIcon from '~/components/ic-icons/baseline-check';
18
20
19
21
const PlcOperationLogPage = () => {
20
22
const [params, setParams] = useSearchParams({
···
301
303
</div>
302
304
303
305
<div class="flex min-w-0 grow flex-col py-4">
304
304
-
<p class="font-mono text-[0.8125rem] leading-5 text-gray-600">
305
305
-
<span class={!nullified ? `` : `line-through`}>{/* @once */ entry.createdAt}</span>
306
306
-
{nullified && <span> (nullified)</span>}
307
307
-
</p>
306
306
+
<div class="flex justify-between gap-4">
307
307
+
<div class="min-w-0 break-words font-mono text-[0.8125rem] leading-5 text-gray-600">
308
308
+
<p>
309
309
+
<span class={!nullified ? `` : `line-through`}>
310
310
+
{/* @once */ entry.createdAt}
311
311
+
</span>
312
312
+
{nullified && <span> (nullified)</span>}
313
313
+
</p>
314
314
+
</div>
315
315
+
316
316
+
<div>
317
317
+
<CopyButton text={JSON.stringify(entry, null, 2)} />
318
318
+
</div>
319
319
+
</div>
308
320
309
321
{node}
310
322
</div>
···
321
333
};
322
334
323
335
export default PlcOperationLogPage;
336
336
+
337
337
+
const CopyButton = (props: { text: string }) => {
338
338
+
const [copied, setCopied] = createSignal(false);
339
339
+
let timeout: number | undefined;
340
340
+
341
341
+
onCleanup(() => clearTimeout(timeout));
342
342
+
343
343
+
const copy = () => {
344
344
+
navigator.clipboard.writeText(props.text).then(() => {
345
345
+
clearTimeout(timeout);
346
346
+
347
347
+
setCopied(true);
348
348
+
timeout = setTimeout(() => setCopied(false), 500);
349
349
+
});
350
350
+
};
351
351
+
352
352
+
return (
353
353
+
<button
354
354
+
title="Copy to clipboard"
355
355
+
onClick={copy}
356
356
+
class={
357
357
+
`grid h-6 w-6 place-items-center rounded text-base` +
358
358
+
(!copied()
359
359
+
? ` text-gray-600 hover:bg-gray-200 hover:text-black active:bg-gray-200`
360
360
+
: ` bg-green-600 text-white`)
361
361
+
}
362
362
+
>
363
363
+
{!copied() ? <ContentCopyIcon /> : <CheckIcon />}
364
364
+
</button>
365
365
+
);
366
366
+
};
324
367
325
368
const groupBy = <K, T>(items: T[], keyFn: (item: T, index: number) => K): Map<K, T[]> => {
326
369
const map = new Map<K, T[]>();