music on atproto
plyr.fm
1<script lang="ts">
2 import { preferences } from '$lib/preferences.svelte';
3 import { moderation } from '$lib/moderation.svelte';
4
5 interface Props {
6 /** image URL to check for sensitive content */
7 src: string | null | undefined;
8 /** content to render (should include the img element) */
9 children: import('svelte').Snippet;
10 /** tooltip position - 'above' for small images, 'center' for large */
11 tooltipPosition?: 'above' | 'center';
12 /** compact mode - blur only, no tooltip, preserves layout (for avatars in lists) */
13 compact?: boolean;
14 }
15
16 let { src, children, tooltipPosition = 'above', compact = false }: Props = $props();
17
18 let isSensitive = $derived(moderation.isSensitive(src));
19 let shouldBlur = $derived(isSensitive && !preferences.showSensitiveArtwork);
20</script>
21
22<div class="sensitive-wrapper" class:blur={shouldBlur} class:compact class:tooltip-center={tooltipPosition === 'center'}>
23 {@render children()}
24 {#if shouldBlur && !compact}
25 <div class="sensitive-tooltip">
26 <span>sensitive - enable in settings</span>
27 </div>
28 {/if}
29</div>
30
31<style>
32 .sensitive-wrapper {
33 position: relative;
34 display: contents;
35 }
36
37 .sensitive-wrapper.blur {
38 display: block;
39 position: relative;
40 }
41
42 /* compact mode: preserve layout, just blur the image */
43 .sensitive-wrapper.blur.compact {
44 display: contents;
45 }
46
47 .sensitive-wrapper.blur :global(img) {
48 filter: blur(12px);
49 transition: filter 0.2s;
50 }
51
52 .sensitive-wrapper.blur:hover :global(img) {
53 filter: blur(6px);
54 }
55
56 /* larger blur for centered tooltip (detail pages) */
57 .sensitive-wrapper.blur.tooltip-center :global(img) {
58 filter: blur(20px);
59 }
60
61 .sensitive-wrapper.blur.tooltip-center:hover :global(img) {
62 filter: blur(10px);
63 }
64
65 /* default: tooltip appears above the image, aligned left (for player/small images) */
66 .sensitive-tooltip {
67 position: absolute;
68 bottom: 100%;
69 left: 0;
70 margin-bottom: 4px;
71 background: var(--bg-primary);
72 border: 1px solid var(--border-default);
73 border-radius: var(--radius-sm);
74 padding: 0.25rem 0.5rem;
75 font-size: var(--text-xs);
76 color: var(--text-tertiary);
77 white-space: nowrap;
78 opacity: 0;
79 pointer-events: none;
80 transition: opacity 0.2s;
81 z-index: 100;
82 }
83
84 /* centered tooltip for large images (detail pages) */
85 .tooltip-center .sensitive-tooltip {
86 top: 50%;
87 bottom: auto;
88 left: 50%;
89 transform: translate(-50%, -50%);
90 margin-bottom: 0;
91 padding: 0.5rem 0.75rem;
92 font-size: var(--text-sm);
93 }
94
95 .sensitive-wrapper.blur:hover .sensitive-tooltip {
96 opacity: 1;
97 }
98</style>