@phosart/common 0.4.49 → 0.4.51

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"}
@@ -15,6 +15,9 @@ declare const ZMultiSelectionOption: z.ZodObject<{
15
15
  declare const ZStringOption: z.ZodObject<{
16
16
  type: z.ZodLiteral<"string">;
17
17
  }, z.z.core.$strip>;
18
+ declare const ZBigStringOption: z.ZodObject<{
19
+ type: z.ZodUnion<readonly [z.ZodLiteral<"textbox">, z.ZodLiteral<"json">, z.ZodLiteral<"markdown">]>;
20
+ }, z.z.core.$strip>;
18
21
  declare const ZBoolOption: z.ZodObject<{
19
22
  type: z.ZodLiteral<"boolean">;
20
23
  }, z.z.core.$strip>;
@@ -25,6 +28,8 @@ declare const ZStringList: z.ZodObject<{
25
28
  type: z.ZodLiteral<"string-list">;
26
29
  }, z.z.core.$strip>;
27
30
  export declare const ZThemeSettingsSchema: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodObject<{
31
+ type: z.ZodUnion<readonly [z.ZodLiteral<"textbox">, z.ZodLiteral<"json">, z.ZodLiteral<"markdown">]>;
32
+ }, z.z.core.$strip>, z.ZodObject<{
28
33
  type: z.ZodLiteral<"color">;
29
34
  }, z.z.core.$strip>, z.ZodObject<{
30
35
  type: z.ZodLiteral<"selection">;
@@ -54,7 +59,7 @@ export declare const builtinSettings: {
54
59
  };
55
60
  };
56
61
  export type BuiltinSettings = typeof builtinSettings;
57
- type MaterializedOptionFor<T extends ThemeSettingsSchema[string]> = T extends z.infer<typeof ZColorOption> ? `#${string}` : T extends z.infer<typeof ZSelectionOption> ? [...T['options']] : T extends z.infer<typeof ZMultiSelectionOption> ? Array<[...T['options']]> : T extends z.infer<typeof ZStringList> ? Array<string> : T extends z.infer<typeof ZTagsOption> ? Array<string> : T extends z.infer<typeof ZStringOption> ? string : T extends z.infer<typeof ZBoolOption> ? boolean | undefined : never;
62
+ type MaterializedOptionFor<T extends ThemeSettingsSchema[string]> = T extends z.infer<typeof ZColorOption> ? `#${string}` : T extends z.infer<typeof ZSelectionOption> ? [...T['options']] : T extends z.infer<typeof ZMultiSelectionOption> ? Array<[...T['options']]> : T extends z.infer<typeof ZStringList> ? Array<string> : T extends z.infer<typeof ZTagsOption> ? Array<string> : T extends z.infer<typeof ZStringOption> ? string : T extends z.infer<typeof ZBigStringOption> ? string : T extends z.infer<typeof ZBoolOption> ? boolean | undefined : never;
58
63
  export type SettingsFor<T extends ThemeSettingsSchema> = {
59
64
  [K in keyof T]: MaterializedOptionFor<T[K]>;
60
65
  };
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/lib/server/theme/schema.ts"],"names":[],"mappings":"AAGA,OAAO,CAAC,MAAM,KAAK,CAAC;AAcpB,QAAA,MAAM,YAAY;;mBAAyC,CAAC;AAC5D,QAAA,MAAM,gBAAgB;;;;mBAIpB,CAAC;AACH,QAAA,MAAM,qBAAqB;;;;mBAIzB,CAAC;AACH,QAAA,MAAM,aAAa;;mBAA0C,CAAC;AAC9D,QAAA,MAAM,WAAW;;mBAA2C,CAAC;AAC7D,QAAA,MAAM,WAAW;;mBAA4C,CAAC;AAC9D,QAAA,MAAM,WAAW;;mBAA+C,CAAC;AACjE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;sBAWhC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAEvE,eAAO,MAAM,eAAe;;;;;;;;CAGY,CAAC;AACzC,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAC;AAErD,KAAK,qBAAqB,CAAC,CAAC,SAAS,mBAAmB,CAAC,MAAM,CAAC,IAC/D,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,GACnC,IAAI,MAAM,EAAE,GACZ,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,GACzC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,GACjB,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,GAC9C,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GACxB,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,GACpC,KAAK,CAAC,MAAM,CAAC,GACb,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,GACpC,KAAK,CAAC,MAAM,CAAC,GACb,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GACtC,MAAM,GACN,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,GACpC,OAAO,GAAG,SAAS,GACnB,KAAK,CAAC;AAEhB,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,mBAAmB,IAAI;KACvD,CAAC,IAAI,MAAM,CAAC,GAAG,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC3C,CAAC;AAEF,wBAAsB,eAAe,CAAC,CAAC,SAAS,mBAAmB,KAAK,OAAO,CAAC,CAAC,CAAC,CAqBjF;AAyCD,wBAAgB,cAAc,CAAC,CAAC,SAAS,mBAAmB,EAC3D,MAAM,EAAE,CAAC,EACT,GAAG,EAAE,OAAO,GACV,GAAG,IAAI,WAAW,CAAC,CAAC,GAAG,eAAe,CAAC,CAEzC;AAoGD,wBAAsB,eAAe,CAAC,CAAC,SAAS,mBAAmB,EAClE,MAAM,EAAE,CAAC,GACP,OAAO,CAAC,WAAW,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAoB3C;AAED,wBAAsB,gBAAgB,CAAC,CAAC,SAAS,mBAAmB,EACnE,MAAM,EAAE,CAAC,EACT,MAAM,EAAE,WAAW,CAAC,CAAC,GAAG,eAAe,CAAC,GACtC,OAAO,CAAC,IAAI,CAAC,CAIf"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/lib/server/theme/schema.ts"],"names":[],"mappings":"AAGA,OAAO,CAAC,MAAM,KAAK,CAAC;AAcpB,QAAA,MAAM,YAAY;;mBAAyC,CAAC;AAC5D,QAAA,MAAM,gBAAgB;;;;mBAIpB,CAAC;AACH,QAAA,MAAM,qBAAqB;;;;mBAIzB,CAAC;AACH,QAAA,MAAM,aAAa;;mBAA0C,CAAC;AAC9D,QAAA,MAAM,gBAAgB;;mBAEpB,CAAC;AACH,QAAA,MAAM,WAAW;;mBAA2C,CAAC;AAC7D,QAAA,MAAM,WAAW;;mBAA4C,CAAC;AAC9D,QAAA,MAAM,WAAW;;mBAA+C,CAAC;AACjE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;sBAYhC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAEvE,eAAO,MAAM,eAAe;;;;;;;;CAGY,CAAC;AACzC,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAC;AAErD,KAAK,qBAAqB,CAAC,CAAC,SAAS,mBAAmB,CAAC,MAAM,CAAC,IAC/D,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,GACnC,IAAI,MAAM,EAAE,GACZ,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,GACzC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,GACjB,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,GAC9C,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GACxB,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,GACpC,KAAK,CAAC,MAAM,CAAC,GACb,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,GACpC,KAAK,CAAC,MAAM,CAAC,GACb,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GACtC,MAAM,GACN,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,GACzC,MAAM,GACN,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,GACpC,OAAO,GAAG,SAAS,GACnB,KAAK,CAAC;AAEjB,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,mBAAmB,IAAI;KACvD,CAAC,IAAI,MAAM,CAAC,GAAG,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC3C,CAAC;AAEF,wBAAsB,eAAe,CAAC,CAAC,SAAS,mBAAmB,KAAK,OAAO,CAAC,CAAC,CAAC,CAqBjF;AA+CD,wBAAgB,cAAc,CAAC,CAAC,SAAS,mBAAmB,EAC3D,MAAM,EAAE,CAAC,EACT,GAAG,EAAE,OAAO,GACV,GAAG,IAAI,WAAW,CAAC,CAAC,GAAG,eAAe,CAAC,CAEzC;AAoGD,wBAAsB,eAAe,CAAC,CAAC,SAAS,mBAAmB,EAClE,MAAM,EAAE,CAAC,GACP,OAAO,CAAC,WAAW,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAoB3C;AAED,wBAAsB,gBAAgB,CAAC,CAAC,SAAS,mBAAmB,EACnE,MAAM,EAAE,CAAC,EACT,MAAM,EAAE,WAAW,CAAC,CAAC,GAAG,eAAe,CAAC,GACtC,OAAO,CAAC,IAAI,CAAC,CAIf"}
@@ -25,10 +25,14 @@ const ZMultiSelectionOption = z.object({
25
25
  multi: z.literal(true)
26
26
  });
27
27
  const ZStringOption = z.object({ type: z.literal('string') });
28
+ const ZBigStringOption = z.object({
29
+ type: z.union([z.literal('textbox'), z.literal('json'), z.literal('markdown')])
30
+ });
28
31
  const ZBoolOption = z.object({ type: z.literal('boolean') });
29
32
  const ZTagsOption = z.object({ type: z.literal('tag-list') });
30
33
  const ZStringList = z.object({ type: z.literal('string-list') });
31
34
  export const ZThemeSettingsSchema = z.record(z.string(), z.union([
35
+ ZBigStringOption,
32
36
  ZColorOption,
33
37
  ZSelectionOption,
34
38
  ZMultiSelectionOption,
@@ -85,8 +89,14 @@ async function writeGeneratedSchema(schema) {
85
89
  break;
86
90
  }
87
91
  case 'string':
92
+ case 'json':
93
+ case 'markdown':
94
+ case 'textbox':
88
95
  ts += `\n "${escape(k)}": string;`;
89
96
  break;
97
+ case 'boolean':
98
+ ts += `\n "${escape(k)}": boolean;`;
99
+ break;
90
100
  case 'string-list':
91
101
  case 'tag-list':
92
102
  ts += `\n "${escape(k)}": string[]`;
@@ -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.51",
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
@@ -27,12 +27,16 @@ const ZMultiSelectionOption = z.object({
27
27
  multi: z.literal(true)
28
28
  });
29
29
  const ZStringOption = z.object({ type: z.literal('string') });
30
+ const ZBigStringOption = z.object({
31
+ type: z.union([z.literal('textbox'), z.literal('json'), z.literal('markdown')])
32
+ });
30
33
  const ZBoolOption = z.object({ type: z.literal('boolean') });
31
34
  const ZTagsOption = z.object({ type: z.literal('tag-list') });
32
35
  const ZStringList = z.object({ type: z.literal('string-list') });
33
36
  export const ZThemeSettingsSchema = z.record(
34
37
  z.string(),
35
38
  z.union([
39
+ ZBigStringOption,
36
40
  ZColorOption,
37
41
  ZSelectionOption,
38
42
  ZMultiSelectionOption,
@@ -64,9 +68,11 @@ type MaterializedOptionFor<T extends ThemeSettingsSchema[string]> =
64
68
  ? Array<string>
65
69
  : T extends z.infer<typeof ZStringOption>
66
70
  ? string
67
- : T extends z.infer<typeof ZBoolOption>
68
- ? boolean | undefined
69
- : never;
71
+ : T extends z.infer<typeof ZBigStringOption>
72
+ ? string
73
+ : T extends z.infer<typeof ZBoolOption>
74
+ ? boolean | undefined
75
+ : never;
70
76
 
71
77
  export type SettingsFor<T extends ThemeSettingsSchema> = {
72
78
  [K in keyof T]: MaterializedOptionFor<T[K]>;
@@ -116,8 +122,14 @@ async function writeGeneratedSchema<T extends ThemeSettingsSchema>(schema: T) {
116
122
  break;
117
123
  }
118
124
  case 'string':
125
+ case 'json':
126
+ case 'markdown':
127
+ case 'textbox':
119
128
  ts += `\n "${escape(k)}": string;`;
120
129
  break;
130
+ case 'boolean':
131
+ ts += `\n "${escape(k)}": boolean;`;
132
+ break;
121
133
  case 'string-list':
122
134
  case 'tag-list':
123
135
  ts += `\n "${escape(k)}": string[]`;
@@ -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
+ }