@phosart/common 0.4.49 → 0.4.50

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.
@@ -19,21 +19,29 @@
19
19
  {@const both = 'calc(var(--preview-size) / 2)'}
20
20
  <div class="preview" style="--preview-size: {cssSize}">
21
21
  <div style="height: {toph}; width: {topw}" class="imgcontainer" class:square={topw === toph}>
22
- <div><Image alt={pieces[0].alt} picture={pieces[0].image.thumbnail} /></div>
22
+ <div>
23
+ <Image alt={pieces[0].alt} picture={pieces[0].image.thumbnail} nsfw={pieces[0].nsfw} />
24
+ </div>
23
25
  </div>
24
26
  {#if pieces[1]}
25
27
  <div style="height: {toph}; width: {topw}" class="imgcontainer" class:square={topw === toph}>
26
- <div><Image alt={pieces[1].alt} picture={pieces[1].image.thumbnail} /></div>
28
+ <div>
29
+ <Image alt={pieces[1].alt} picture={pieces[1].image.thumbnail} nsfw={pieces[0].nsfw} />
30
+ </div>
27
31
  </div>
28
32
  {/if}
29
33
  {#if pieces[2]}
30
34
  <div style="height: {both}; width: {botw}" class="imgcontainer" class:square={botw === both}>
31
- <div><Image alt={pieces[2].alt} picture={pieces[2].image.thumbnail} /></div>
35
+ <div>
36
+ <Image alt={pieces[2].alt} picture={pieces[2].image.thumbnail} nsfw={pieces[0].nsfw} />
37
+ </div>
32
38
  </div>
33
39
  {/if}
34
40
  {#if pieces[3]}
35
41
  <div style="height: {both}; width: {botw}" class="imgcontainer" class:square={botw === both}>
36
- <div><Image alt={pieces[3].alt} picture={pieces[3].image.thumbnail} /></div>
42
+ <div>
43
+ <Image alt={pieces[3].alt} picture={pieces[3].image.thumbnail} nsfw={pieces[0].nsfw} />
44
+ </div>
37
45
  </div>
38
46
  {/if}
39
47
  </div>
@@ -1 +1 @@
1
- {"version":3,"file":"GalleryPreview.svelte.d.ts","sourceRoot":"","sources":["../src/lib/GalleryPreview.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAI5C,UAAU,KAAK;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CAChB;AA0CF,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"GalleryPreview.svelte.d.ts","sourceRoot":"","sources":["../src/lib/GalleryPreview.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAI5C,UAAU,KAAK;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CAChB;AAkDF,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
package/dist/Image.svelte CHANGED
@@ -3,6 +3,7 @@
3
3
  import { untrack } from 'svelte';
4
4
  import { isHighRes } from './HighResContext.svelte';
5
5
  import { useLibraryConfig } from './util/phosart_config.svelte.js';
6
+ import { nsfwBlur } from './util/nsfw_helper.svelte.js';
6
7
 
7
8
  interface Props {
8
9
  picture: ImageModel;
@@ -13,11 +14,13 @@
13
14
  onloaded?: () => void;
14
15
  loading?: boolean;
15
16
  transformSrc?: (src: string) => string;
17
+ nsfw?: boolean;
16
18
  }
17
19
 
18
20
  let {
19
21
  picture,
20
22
  alt,
23
+ nsfw,
21
24
  onloaded = undefined,
22
25
  video = undefined,
23
26
  controls = false,
@@ -102,10 +105,12 @@
102
105
  }
103
106
  </script>
104
107
 
105
- {#each [{ src, video }] as pic (JSON.stringify(pic))}
108
+ {#key JSON.stringify({ src, video })}
106
109
  {#if video}
107
110
  <video
108
- style="background: {background}; aspect-ratio: {src.fallback.w} / {src.fallback.h};"
111
+ style="background: {background}; aspect-ratio: {src.fallback.w} / {src.fallback.h}; {nsfwBlur(
112
+ nsfw
113
+ )}"
109
114
  muted
110
115
  autoplay
111
116
  {controls}
@@ -118,7 +123,11 @@
118
123
  <source src={transformSrc(video)} type="video/mp4" />
119
124
  </video>
120
125
  {:else}
121
- <picture style="background: {background}; aspect-ratio: {src.fallback.w} / {src.fallback.h};">
126
+ <picture
127
+ style="background: {background}; aspect-ratio: {src.fallback.w} / {src.fallback.h}; {nsfwBlur(
128
+ nsfw
129
+ )}"
130
+ >
122
131
  {#each Object.entries(src.sources) as [format, images] (format)}
123
132
  <source
124
133
  srcset={images.map((img) => `${transformSrc(img.src)} ${img.w}w`).join(', ')}
@@ -140,7 +149,7 @@
140
149
  />
141
150
  </picture>
142
151
  {/if}
143
- {/each}
152
+ {/key}
144
153
 
145
154
  <style>
146
155
  picture,
@@ -8,6 +8,7 @@ interface Props {
8
8
  onloaded?: () => void;
9
9
  loading?: boolean;
10
10
  transformSrc?: (src: string) => string;
11
+ nsfw?: boolean;
11
12
  }
12
13
  declare const Image: import("svelte").Component<Props, {}, "loading">;
13
14
  type Image = ReturnType<typeof Image>;
@@ -1 +1 @@
1
- {"version":3,"file":"Image.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Image.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAe,KAAK,KAAK,IAAI,UAAU,EAAQ,MAAM,eAAe,CAAC;AAM3E,UAAU,KAAK;IACd,OAAO,EAAE,UAAU,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACvC;AAmHF,QAAA,MAAM,KAAK,kDAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"Image.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Image.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAe,KAAK,KAAK,IAAI,UAAU,EAAQ,MAAM,eAAe,CAAC;AAO3E,UAAU,KAAK;IACd,OAAO,EAAE,UAAU,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IACvC,IAAI,CAAC,EAAE,OAAO,CAAC;CACf;AAyHF,QAAA,MAAM,KAAK,kDAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
@@ -50,7 +50,7 @@
50
50
  role="button"
51
51
  tabindex={-1}
52
52
  >
53
- <Image picture={piece.image.thumbnail} alt={piece.alt} />
53
+ <Image picture={piece.image.thumbnail} alt={piece.alt} nsfw={piece.nsfw} />
54
54
  </div>
55
55
  {/each}
56
56
  </div>
@@ -169,6 +169,7 @@
169
169
  controls
170
170
  picture={image.image.full}
171
171
  alt={image.alt}
172
+ nsfw={image.nsfw}
172
173
  {onloaded}
173
174
  />
174
175
  </div>
@@ -8,6 +8,7 @@
8
8
  import Chip from './Chip.svelte';
9
9
  import { useCharacters } from '../util/charactercontext.svelte.js';
10
10
  import { useArtists } from '../util/artistcontext.svelte.js';
11
+ import { nsfwRedact } from '../util/nsfw_helper.svelte.js';
11
12
 
12
13
  interface Props {
13
14
  piece: ArtPiece;
@@ -37,7 +38,7 @@
37
38
  {#if showName}
38
39
  <div style="margin-bottom: 0.5rem;">
39
40
  <span style="border-bottom: 1px dashed #8886; font-style: italic;">
40
- {piece.name}
41
+ {nsfwRedact(piece.name, piece.nsfw)}
41
42
  </span>
42
43
  </div>
43
44
  {/if}
@@ -49,7 +50,10 @@
49
50
  >
50
51
  <!-- eslint-disable-next-line svelte/no-at-html-tags -->
51
52
  {@html markdown(
52
- (selectedAlt && piece.alts?.[selectedAlt]?.description) || piece.description || ''
53
+ nsfwRedact(
54
+ (selectedAlt && piece.alts?.[selectedAlt]?.description) || piece.description || '',
55
+ piece.nsfw
56
+ )
53
57
  )}
54
58
  </div>
55
59
 
@@ -1 +1 @@
1
- {"version":3,"file":"Description.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/Postcard/Description.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,+CAA+C,CAAC;AAGvD,OAAO,EAAE,KAAK,QAAQ,EAAuC,MAAM,gBAAgB,CAAC;AAQnF,UAAU,KAAK;IACd,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AA2GF,QAAA,MAAM,WAAW,kDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"Description.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/Postcard/Description.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,+CAA+C,CAAC;AAGvD,OAAO,EAAE,KAAK,QAAQ,EAAuC,MAAM,gBAAgB,CAAC;AASnF,UAAU,KAAK;IACd,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AA+GF,QAAA,MAAM,WAAW,kDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import { nsfwRedact } from '../util/nsfw_helper.svelte.js';
2
3
  import { normalizeArtist, type ArtPiece } from '../util/art.js';
3
4
  import { useArtists } from '../util/artistcontext.svelte.js';
4
5
  import ArtistLink from './ArtistLink.svelte';
@@ -25,7 +26,7 @@
25
26
  <div style="display: flex">
26
27
  {#if showName}
27
28
  <div style="padding-right: 2rem" class="piece-name">
28
- {piece.name}
29
+ {nsfwRedact(piece.name, piece.nsfw)}
29
30
  </div>
30
31
  {/if}
31
32
  <div
@@ -1 +1 @@
1
- {"version":3,"file":"Headline.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/Postcard/Headline.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAK/D,UAAU,KAAK;IACd,KAAK,EAAE,QAAQ,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAElB,kBAAkB,EAAE,OAAO,CAAC;CAC5B;AAkCF,QAAA,MAAM,QAAQ,6DAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"Headline.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/Postcard/Headline.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAK/D,UAAU,KAAK;IACd,KAAK,EAAE,QAAQ,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAElB,kBAAkB,EAAE,OAAO,CAAC;CAC5B;AAmCF,QAAA,MAAM,QAAQ,6DAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
@@ -10,4 +10,5 @@ export { setLibraryConfig, type LibraryConfig } from './phosart_config.svelte.ts
10
10
  export { asRecord, multiRecordBy, deduplicateBy, sveltekitAbsolutePath, sveltekitAnchoredPath } from './util.ts';
11
11
  export { asTree, pathView } from './tree.ts';
12
12
  export type { FolderElement, GalleryElement, GalleryTree, TreeElement } from './tree.ts';
13
+ export { nsfwBlur, nsfwBlurStyle, nsfwConsented, nsfwRedact } from './nsfw_helper.svelte.ts';
13
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/util/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAClF,YAAY,EACX,QAAQ,EACR,MAAM,EACN,SAAS,EACT,YAAY,EACZ,OAAO,EACP,UAAU,EACV,KAAK,EACL,gBAAgB,EAChB,OAAO,EACP,MAAM,EACN,UAAU,EACV,YAAY,EACZ,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,aAAa,EACb,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAClF,OAAO,EACN,QAAQ,EACR,aAAa,EACb,aAAa,EACb,qBAAqB,EACrB,qBAAqB,EACrB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC7C,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/util/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAClF,YAAY,EACX,QAAQ,EACR,MAAM,EACN,SAAS,EACT,YAAY,EACZ,OAAO,EACP,UAAU,EACV,KAAK,EACL,gBAAgB,EAChB,OAAO,EACP,MAAM,EACN,UAAU,EACV,YAAY,EACZ,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,aAAa,EACb,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAClF,OAAO,EACN,QAAQ,EACR,aAAa,EACb,aAAa,EACb,qBAAqB,EACrB,qBAAqB,EACrB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC7C,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAEzF,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC"}
@@ -8,3 +8,4 @@ export { smoothScroll } from "./smoothscroll.js";
8
8
  export { setLibraryConfig } from "./phosart_config.svelte.js";
9
9
  export { asRecord, multiRecordBy, deduplicateBy, sveltekitAbsolutePath, sveltekitAnchoredPath } from "./util.js";
10
10
  export { asTree, pathView } from "./tree.js";
11
+ export { nsfwBlur, nsfwBlurStyle, nsfwConsented, nsfwRedact } from "./nsfw_helper.svelte.js";
@@ -0,0 +1,7 @@
1
+ export declare const nsfwConsented: {
2
+ consented: boolean;
3
+ };
4
+ export declare const nsfwBlurStyle = "filter: blur(200px); overflow: hidden;";
5
+ export declare function nsfwBlur(nsfw?: boolean): string;
6
+ export declare function nsfwRedact(s: string, nsfw?: boolean): string;
7
+ //# sourceMappingURL=nsfw_helper.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nsfw_helper.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/util/nsfw_helper.svelte.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa;;CAA+B,CAAC;AAE1D,eAAO,MAAM,aAAa,2CAA2C,CAAC;AAEtE,wBAAgB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAK/C;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAK5D"}
@@ -0,0 +1,14 @@
1
+ export const nsfwConsented = $state({ consented: false });
2
+ export const nsfwBlurStyle = 'filter: blur(200px); overflow: hidden;';
3
+ export function nsfwBlur(nsfw) {
4
+ if (nsfw && !nsfwConsented.consented) {
5
+ return nsfwBlurStyle;
6
+ }
7
+ return '';
8
+ }
9
+ export function nsfwRedact(s, nsfw) {
10
+ if (nsfw && !nsfwConsented.consented) {
11
+ return '[redacted: nsfw]';
12
+ }
13
+ return s;
14
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phosart/common",
3
- "version": "0.4.49",
3
+ "version": "0.4.50",
4
4
  "files": [
5
5
  "dist",
6
6
  "!dist/**/*.test.*",
@@ -19,21 +19,29 @@
19
19
  {@const both = 'calc(var(--preview-size) / 2)'}
20
20
  <div class="preview" style="--preview-size: {cssSize}">
21
21
  <div style="height: {toph}; width: {topw}" class="imgcontainer" class:square={topw === toph}>
22
- <div><Image alt={pieces[0].alt} picture={pieces[0].image.thumbnail} /></div>
22
+ <div>
23
+ <Image alt={pieces[0].alt} picture={pieces[0].image.thumbnail} nsfw={pieces[0].nsfw} />
24
+ </div>
23
25
  </div>
24
26
  {#if pieces[1]}
25
27
  <div style="height: {toph}; width: {topw}" class="imgcontainer" class:square={topw === toph}>
26
- <div><Image alt={pieces[1].alt} picture={pieces[1].image.thumbnail} /></div>
28
+ <div>
29
+ <Image alt={pieces[1].alt} picture={pieces[1].image.thumbnail} nsfw={pieces[0].nsfw} />
30
+ </div>
27
31
  </div>
28
32
  {/if}
29
33
  {#if pieces[2]}
30
34
  <div style="height: {both}; width: {botw}" class="imgcontainer" class:square={botw === both}>
31
- <div><Image alt={pieces[2].alt} picture={pieces[2].image.thumbnail} /></div>
35
+ <div>
36
+ <Image alt={pieces[2].alt} picture={pieces[2].image.thumbnail} nsfw={pieces[0].nsfw} />
37
+ </div>
32
38
  </div>
33
39
  {/if}
34
40
  {#if pieces[3]}
35
41
  <div style="height: {both}; width: {botw}" class="imgcontainer" class:square={botw === both}>
36
- <div><Image alt={pieces[3].alt} picture={pieces[3].image.thumbnail} /></div>
42
+ <div>
43
+ <Image alt={pieces[3].alt} picture={pieces[3].image.thumbnail} nsfw={pieces[0].nsfw} />
44
+ </div>
37
45
  </div>
38
46
  {/if}
39
47
  </div>
@@ -3,6 +3,7 @@
3
3
  import { untrack } from 'svelte';
4
4
  import { isHighRes } from './HighResContext.svelte';
5
5
  import { useLibraryConfig } from './util/phosart_config.svelte.ts';
6
+ import { nsfwBlur } from './util/nsfw_helper.svelte.ts';
6
7
 
7
8
  interface Props {
8
9
  picture: ImageModel;
@@ -13,11 +14,13 @@
13
14
  onloaded?: () => void;
14
15
  loading?: boolean;
15
16
  transformSrc?: (src: string) => string;
17
+ nsfw?: boolean;
16
18
  }
17
19
 
18
20
  let {
19
21
  picture,
20
22
  alt,
23
+ nsfw,
21
24
  onloaded = undefined,
22
25
  video = undefined,
23
26
  controls = false,
@@ -102,10 +105,12 @@
102
105
  }
103
106
  </script>
104
107
 
105
- {#each [{ src, video }] as pic (JSON.stringify(pic))}
108
+ {#key JSON.stringify({ src, video })}
106
109
  {#if video}
107
110
  <video
108
- style="background: {background}; aspect-ratio: {src.fallback.w} / {src.fallback.h};"
111
+ style="background: {background}; aspect-ratio: {src.fallback.w} / {src.fallback.h}; {nsfwBlur(
112
+ nsfw
113
+ )}"
109
114
  muted
110
115
  autoplay
111
116
  {controls}
@@ -118,7 +123,11 @@
118
123
  <source src={transformSrc(video)} type="video/mp4" />
119
124
  </video>
120
125
  {:else}
121
- <picture style="background: {background}; aspect-ratio: {src.fallback.w} / {src.fallback.h};">
126
+ <picture
127
+ style="background: {background}; aspect-ratio: {src.fallback.w} / {src.fallback.h}; {nsfwBlur(
128
+ nsfw
129
+ )}"
130
+ >
122
131
  {#each Object.entries(src.sources) as [format, images] (format)}
123
132
  <source
124
133
  srcset={images.map((img) => `${transformSrc(img.src)} ${img.w}w`).join(', ')}
@@ -140,7 +149,7 @@
140
149
  />
141
150
  </picture>
142
151
  {/if}
143
- {/each}
152
+ {/key}
144
153
 
145
154
  <style>
146
155
  picture,
@@ -50,7 +50,7 @@
50
50
  role="button"
51
51
  tabindex={-1}
52
52
  >
53
- <Image picture={piece.image.thumbnail} alt={piece.alt} />
53
+ <Image picture={piece.image.thumbnail} alt={piece.alt} nsfw={piece.nsfw} />
54
54
  </div>
55
55
  {/each}
56
56
  </div>
@@ -169,6 +169,7 @@
169
169
  controls
170
170
  picture={image.image.full}
171
171
  alt={image.alt}
172
+ nsfw={image.nsfw}
172
173
  {onloaded}
173
174
  />
174
175
  </div>
@@ -8,6 +8,7 @@
8
8
  import Chip from './Chip.svelte';
9
9
  import { useCharacters } from '../util/charactercontext.svelte.ts';
10
10
  import { useArtists } from '../util/artistcontext.svelte.ts';
11
+ import { nsfwRedact } from '../util/nsfw_helper.svelte.ts';
11
12
 
12
13
  interface Props {
13
14
  piece: ArtPiece;
@@ -37,7 +38,7 @@
37
38
  {#if showName}
38
39
  <div style="margin-bottom: 0.5rem;">
39
40
  <span style="border-bottom: 1px dashed #8886; font-style: italic;">
40
- {piece.name}
41
+ {nsfwRedact(piece.name, piece.nsfw)}
41
42
  </span>
42
43
  </div>
43
44
  {/if}
@@ -49,7 +50,10 @@
49
50
  >
50
51
  <!-- eslint-disable-next-line svelte/no-at-html-tags -->
51
52
  {@html markdown(
52
- (selectedAlt && piece.alts?.[selectedAlt]?.description) || piece.description || ''
53
+ nsfwRedact(
54
+ (selectedAlt && piece.alts?.[selectedAlt]?.description) || piece.description || '',
55
+ piece.nsfw
56
+ )
53
57
  )}
54
58
  </div>
55
59
 
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import { nsfwRedact } from '../util/nsfw_helper.svelte.ts';
2
3
  import { normalizeArtist, type ArtPiece } from '../util/art.ts';
3
4
  import { useArtists } from '../util/artistcontext.svelte.ts';
4
5
  import ArtistLink from './ArtistLink.svelte';
@@ -25,7 +26,7 @@
25
26
  <div style="display: flex">
26
27
  {#if showName}
27
28
  <div style="padding-right: 2rem" class="piece-name">
28
- {piece.name}
29
+ {nsfwRedact(piece.name, piece.nsfw)}
29
30
  </div>
30
31
  {/if}
31
32
  <div
@@ -34,3 +34,5 @@ export {
34
34
  } from './util.ts';
35
35
  export { asTree, pathView } from './tree.ts';
36
36
  export type { FolderElement, GalleryElement, GalleryTree, TreeElement } from './tree.ts';
37
+
38
+ export { nsfwBlur, nsfwBlurStyle, nsfwConsented, nsfwRedact } from './nsfw_helper.svelte.ts';
@@ -0,0 +1,17 @@
1
+ export const nsfwConsented = $state({ consented: false });
2
+
3
+ export const nsfwBlurStyle = 'filter: blur(200px); overflow: hidden;';
4
+
5
+ export function nsfwBlur(nsfw?: boolean): string {
6
+ if (nsfw && !nsfwConsented.consented) {
7
+ return nsfwBlurStyle;
8
+ }
9
+ return '';
10
+ }
11
+
12
+ export function nsfwRedact(s: string, nsfw?: boolean): string {
13
+ if (nsfw && !nsfwConsented.consented) {
14
+ return '[redacted: nsfw]';
15
+ }
16
+ return s;
17
+ }