@phosart/common 0.4.58 → 0.4.60

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.
@@ -20,27 +20,47 @@
20
20
  <div class="preview" style="--preview-size: {cssSize}">
21
21
  <div style="height: {toph}; width: {topw}" class="imgcontainer" class:square={topw === toph}>
22
22
  <div>
23
- <Image alt={pieces[0].alt} picture={pieces[0].image.thumbnail} nsfw={pieces[0].nsfw} />
23
+ <Image
24
+ alt={pieces[0].alt}
25
+ picture={pieces[0].image.thumbnail}
26
+ nsfw={pieces[0].nsfw}
27
+ isThumb
28
+ />
24
29
  </div>
25
30
  </div>
26
31
  {#if pieces[1]}
27
32
  <div style="height: {toph}; width: {topw}" class="imgcontainer" class:square={topw === toph}>
28
33
  <div>
29
- <Image alt={pieces[1].alt} picture={pieces[1].image.thumbnail} nsfw={pieces[0].nsfw} />
34
+ <Image
35
+ alt={pieces[1].alt}
36
+ picture={pieces[1].image.thumbnail}
37
+ nsfw={pieces[0].nsfw}
38
+ isThumb
39
+ />
30
40
  </div>
31
41
  </div>
32
42
  {/if}
33
43
  {#if pieces[2]}
34
44
  <div style="height: {both}; width: {botw}" class="imgcontainer" class:square={botw === both}>
35
45
  <div>
36
- <Image alt={pieces[2].alt} picture={pieces[2].image.thumbnail} nsfw={pieces[0].nsfw} />
46
+ <Image
47
+ alt={pieces[2].alt}
48
+ picture={pieces[2].image.thumbnail}
49
+ nsfw={pieces[0].nsfw}
50
+ isThumb
51
+ />
37
52
  </div>
38
53
  </div>
39
54
  {/if}
40
55
  {#if pieces[3]}
41
56
  <div style="height: {both}; width: {botw}" class="imgcontainer" class:square={botw === both}>
42
57
  <div>
43
- <Image alt={pieces[3].alt} picture={pieces[3].image.thumbnail} nsfw={pieces[0].nsfw} />
58
+ <Image
59
+ alt={pieces[3].alt}
60
+ picture={pieces[3].image.thumbnail}
61
+ nsfw={pieces[0].nsfw}
62
+ isThumb
63
+ />
44
64
  </div>
45
65
  </div>
46
66
  {/if}
package/dist/Image.svelte CHANGED
@@ -16,6 +16,7 @@
16
16
  transformSrc?: (src: string) => string;
17
17
  nsfw?: boolean;
18
18
  lqipFit?: 'cover' | 'contain';
19
+ isThumb?: boolean;
19
20
  }
20
21
 
21
22
  let {
@@ -28,7 +29,8 @@
28
29
  nolqip = false,
29
30
  loading = $bindable(true),
30
31
  transformSrc: userTransformSrc,
31
- lqipFit = 'contain'
32
+ lqipFit = 'contain',
33
+ isThumb = true
32
34
  }: Props = $props();
33
35
 
34
36
  const config = useLibraryConfig();
@@ -113,7 +115,9 @@
113
115
  {#if video}
114
116
  <video
115
117
  style="background: {background}; aspect-ratio: {src.fallback.w} / {src.fallback.h}; {nsfwBlur(
116
- nsfw
118
+ nsfw,
119
+ picture.sha256,
120
+ isThumb ? 'thumb' : 'full'
117
121
  )}"
118
122
  muted
119
123
  autoplay
@@ -129,7 +133,9 @@
129
133
  {:else}
130
134
  <picture
131
135
  style="background: {background}; aspect-ratio: {src.fallback.w} / {src.fallback.h}; {nsfwBlur(
132
- nsfw
136
+ nsfw,
137
+ picture.sha256,
138
+ isThumb ? 'thumb' : 'full'
133
139
  )}"
134
140
  >
135
141
  {#each Object.entries(src.sources) as [format, images] (format)}
@@ -10,6 +10,7 @@ interface Props {
10
10
  transformSrc?: (src: string) => string;
11
11
  nsfw?: boolean;
12
12
  lqipFit?: 'cover' | 'contain';
13
+ isThumb?: boolean;
13
14
  }
14
15
  declare const Image: import("svelte").Component<Props, {}, "loading">;
15
16
  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;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;IACf,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC9B;AA4HF,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;IACf,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAiIF,QAAA,MAAM,KAAK,kDAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
@@ -50,7 +50,12 @@
50
50
  role="button"
51
51
  tabindex={-1}
52
52
  >
53
- <Image picture={piece.image.thumbnail} alt={piece.alt} nsfw={piece.nsfw} />
53
+ <Image
54
+ picture={piece.image.thumbnail}
55
+ alt={piece.alt}
56
+ nsfw={piece.nsfw}
57
+ isThumb={false}
58
+ />
54
59
  </div>
55
60
  {/each}
56
61
  </div>
@@ -138,6 +138,7 @@
138
138
  <!-- svelte-ignore a11y_no_static_element_interactions -->
139
139
  <div
140
140
  class="main-container overscroll-contain"
141
+ class:comic-mode={isComic}
141
142
  ondragstartcapture={(e) => e.preventDefault()}
142
143
  onpointerdown={onPointerDown}
143
144
  onpointerup={onPointerUp}
@@ -181,6 +182,7 @@
181
182
  alt={image.alt}
182
183
  nsfw={image.nsfw}
183
184
  {onloaded}
185
+ isThumb={false}
184
186
  />
185
187
  </div>
186
188
  {/snippet}
@@ -223,6 +225,7 @@
223
225
  alt={selPiece.alt}
224
226
  loading={false}
225
227
  nolqip
228
+ isThumb
226
229
  />
227
230
  </div>
228
231
  </div>
@@ -264,7 +267,13 @@
264
267
  )}px; border-radius: {i === piece.alts.length - 1 ? '0 0 12px 12px' : '0px'};"
265
268
  >
266
269
  <div class="image-container" style="top: 0; ">
267
- <Image video={alt.video?.full} controls picture={alt.image.full} alt={alt.alt} />
270
+ <Image
271
+ video={alt.video?.full}
272
+ controls
273
+ picture={alt.image.full}
274
+ alt={alt.alt}
275
+ isThumb={false}
276
+ />
268
277
  </div>
269
278
  </div>
270
279
  {/each}
@@ -290,7 +299,7 @@
290
299
  .nav-container.nav-container {
291
300
  width: 0;
292
301
  }
293
- .main-container.main-container {
302
+ .main-container.main-container.comic-mode {
294
303
  max-width: 90vw;
295
304
  }
296
305
  }
@@ -326,6 +335,10 @@
326
335
  color: white;
327
336
  }
328
337
 
338
+ .main-container.comic-mode {
339
+ max-width: 50vw;
340
+ }
341
+
329
342
  .main-container {
330
343
  flex-grow: 1;
331
344
  height: 100%;
@@ -334,7 +347,6 @@
334
347
  justify-content: center;
335
348
  align-items: center;
336
349
  overflow: hidden;
337
- max-width: 80vw;
338
350
  }
339
351
 
340
352
  .bounding-div {
@@ -1,7 +1,11 @@
1
+ import { SvelteSet } from 'svelte/reactivity';
2
+ export type ImageId = string;
1
3
  export declare const nsfwConsented: {
2
- consented: boolean;
4
+ unblurThumbnails: boolean;
5
+ unblurText: boolean;
6
+ consented: "all" | SvelteSet<ImageId>;
3
7
  };
4
8
  export declare const nsfwBlurStyle = "filter: blur(200px); overflow: hidden;";
5
- export declare function nsfwBlur(nsfw?: boolean): string;
9
+ export declare function nsfwBlur(nsfw: boolean | undefined, sha256?: ImageId, imageType?: 'full' | 'thumb'): string;
6
10
  export declare function nsfwRedact(s: string, nsfw?: boolean): string;
7
11
  //# sourceMappingURL=nsfw_helper.svelte.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"nsfw_helper.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/util/nsfw_helper.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAE7B,eAAO,MAAM,aAAa;sBACP,OAAO;gBACb,OAAO;eACR,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC;CACwC,CAAC;AAE/E,eAAO,MAAM,aAAa,2CAA2C,CAAC;AAEtE,wBAAgB,QAAQ,CACvB,IAAI,EAAE,OAAO,GAAG,SAAS,EACzB,MAAM,GAAE,OAAa,EACrB,SAAS,GAAE,MAAM,GAAG,OAAiB,GACnC,MAAM,CAOR;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAK5D"}
@@ -1,13 +1,16 @@
1
- export const nsfwConsented = $state({ consented: false });
1
+ import { SvelteSet } from 'svelte/reactivity';
2
+ export const nsfwConsented = $state({ unblurThumbnails: false, consented: new SvelteSet(), unblurText: false });
2
3
  export const nsfwBlurStyle = 'filter: blur(200px); overflow: hidden;';
3
- export function nsfwBlur(nsfw) {
4
- if (nsfw && !nsfwConsented.consented) {
4
+ export function nsfwBlur(nsfw, sha256 = '.', imageType = 'thumb') {
5
+ const didConsent = nsfwConsented.consented === 'all' || nsfwConsented.consented.has(sha256);
6
+ const shouldBlur = didConsent && (nsfwConsented.unblurThumbnails || imageType === 'full');
7
+ if (nsfw && shouldBlur) {
5
8
  return nsfwBlurStyle;
6
9
  }
7
10
  return '';
8
11
  }
9
12
  export function nsfwRedact(s, nsfw) {
10
- if (nsfw && !nsfwConsented.consented) {
13
+ if (nsfw && !nsfwConsented.unblurText) {
11
14
  return '[redacted: nsfw]';
12
15
  }
13
16
  return s;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phosart/common",
3
- "version": "0.4.58",
3
+ "version": "0.4.60",
4
4
  "files": [
5
5
  "dist",
6
6
  "!dist/**/*.test.*",
@@ -20,27 +20,47 @@
20
20
  <div class="preview" style="--preview-size: {cssSize}">
21
21
  <div style="height: {toph}; width: {topw}" class="imgcontainer" class:square={topw === toph}>
22
22
  <div>
23
- <Image alt={pieces[0].alt} picture={pieces[0].image.thumbnail} nsfw={pieces[0].nsfw} />
23
+ <Image
24
+ alt={pieces[0].alt}
25
+ picture={pieces[0].image.thumbnail}
26
+ nsfw={pieces[0].nsfw}
27
+ isThumb
28
+ />
24
29
  </div>
25
30
  </div>
26
31
  {#if pieces[1]}
27
32
  <div style="height: {toph}; width: {topw}" class="imgcontainer" class:square={topw === toph}>
28
33
  <div>
29
- <Image alt={pieces[1].alt} picture={pieces[1].image.thumbnail} nsfw={pieces[0].nsfw} />
34
+ <Image
35
+ alt={pieces[1].alt}
36
+ picture={pieces[1].image.thumbnail}
37
+ nsfw={pieces[0].nsfw}
38
+ isThumb
39
+ />
30
40
  </div>
31
41
  </div>
32
42
  {/if}
33
43
  {#if pieces[2]}
34
44
  <div style="height: {both}; width: {botw}" class="imgcontainer" class:square={botw === both}>
35
45
  <div>
36
- <Image alt={pieces[2].alt} picture={pieces[2].image.thumbnail} nsfw={pieces[0].nsfw} />
46
+ <Image
47
+ alt={pieces[2].alt}
48
+ picture={pieces[2].image.thumbnail}
49
+ nsfw={pieces[0].nsfw}
50
+ isThumb
51
+ />
37
52
  </div>
38
53
  </div>
39
54
  {/if}
40
55
  {#if pieces[3]}
41
56
  <div style="height: {both}; width: {botw}" class="imgcontainer" class:square={botw === both}>
42
57
  <div>
43
- <Image alt={pieces[3].alt} picture={pieces[3].image.thumbnail} nsfw={pieces[0].nsfw} />
58
+ <Image
59
+ alt={pieces[3].alt}
60
+ picture={pieces[3].image.thumbnail}
61
+ nsfw={pieces[0].nsfw}
62
+ isThumb
63
+ />
44
64
  </div>
45
65
  </div>
46
66
  {/if}
@@ -16,6 +16,7 @@
16
16
  transformSrc?: (src: string) => string;
17
17
  nsfw?: boolean;
18
18
  lqipFit?: 'cover' | 'contain';
19
+ isThumb?: boolean;
19
20
  }
20
21
 
21
22
  let {
@@ -28,7 +29,8 @@
28
29
  nolqip = false,
29
30
  loading = $bindable(true),
30
31
  transformSrc: userTransformSrc,
31
- lqipFit = 'contain'
32
+ lqipFit = 'contain',
33
+ isThumb = true
32
34
  }: Props = $props();
33
35
 
34
36
  const config = useLibraryConfig();
@@ -113,7 +115,9 @@
113
115
  {#if video}
114
116
  <video
115
117
  style="background: {background}; aspect-ratio: {src.fallback.w} / {src.fallback.h}; {nsfwBlur(
116
- nsfw
118
+ nsfw,
119
+ picture.sha256,
120
+ isThumb ? 'thumb' : 'full'
117
121
  )}"
118
122
  muted
119
123
  autoplay
@@ -129,7 +133,9 @@
129
133
  {:else}
130
134
  <picture
131
135
  style="background: {background}; aspect-ratio: {src.fallback.w} / {src.fallback.h}; {nsfwBlur(
132
- nsfw
136
+ nsfw,
137
+ picture.sha256,
138
+ isThumb ? 'thumb' : 'full'
133
139
  )}"
134
140
  >
135
141
  {#each Object.entries(src.sources) as [format, images] (format)}
@@ -50,7 +50,12 @@
50
50
  role="button"
51
51
  tabindex={-1}
52
52
  >
53
- <Image picture={piece.image.thumbnail} alt={piece.alt} nsfw={piece.nsfw} />
53
+ <Image
54
+ picture={piece.image.thumbnail}
55
+ alt={piece.alt}
56
+ nsfw={piece.nsfw}
57
+ isThumb={false}
58
+ />
54
59
  </div>
55
60
  {/each}
56
61
  </div>
@@ -138,6 +138,7 @@
138
138
  <!-- svelte-ignore a11y_no_static_element_interactions -->
139
139
  <div
140
140
  class="main-container overscroll-contain"
141
+ class:comic-mode={isComic}
141
142
  ondragstartcapture={(e) => e.preventDefault()}
142
143
  onpointerdown={onPointerDown}
143
144
  onpointerup={onPointerUp}
@@ -181,6 +182,7 @@
181
182
  alt={image.alt}
182
183
  nsfw={image.nsfw}
183
184
  {onloaded}
185
+ isThumb={false}
184
186
  />
185
187
  </div>
186
188
  {/snippet}
@@ -223,6 +225,7 @@
223
225
  alt={selPiece.alt}
224
226
  loading={false}
225
227
  nolqip
228
+ isThumb
226
229
  />
227
230
  </div>
228
231
  </div>
@@ -264,7 +267,13 @@
264
267
  )}px; border-radius: {i === piece.alts.length - 1 ? '0 0 12px 12px' : '0px'};"
265
268
  >
266
269
  <div class="image-container" style="top: 0; ">
267
- <Image video={alt.video?.full} controls picture={alt.image.full} alt={alt.alt} />
270
+ <Image
271
+ video={alt.video?.full}
272
+ controls
273
+ picture={alt.image.full}
274
+ alt={alt.alt}
275
+ isThumb={false}
276
+ />
268
277
  </div>
269
278
  </div>
270
279
  {/each}
@@ -290,7 +299,7 @@
290
299
  .nav-container.nav-container {
291
300
  width: 0;
292
301
  }
293
- .main-container.main-container {
302
+ .main-container.main-container.comic-mode {
294
303
  max-width: 90vw;
295
304
  }
296
305
  }
@@ -326,6 +335,10 @@
326
335
  color: white;
327
336
  }
328
337
 
338
+ .main-container.comic-mode {
339
+ max-width: 50vw;
340
+ }
341
+
329
342
  .main-container {
330
343
  flex-grow: 1;
331
344
  height: 100%;
@@ -334,7 +347,6 @@
334
347
  justify-content: center;
335
348
  align-items: center;
336
349
  overflow: hidden;
337
- max-width: 80vw;
338
350
  }
339
351
 
340
352
  .bounding-div {
@@ -1,16 +1,30 @@
1
- export const nsfwConsented = $state({ consented: false });
1
+ import { SvelteSet } from 'svelte/reactivity';
2
+
3
+ export type ImageId = string;
4
+
5
+ export const nsfwConsented = $state<{
6
+ unblurThumbnails: boolean;
7
+ unblurText: boolean;
8
+ consented: 'all' | SvelteSet<ImageId>;
9
+ }>({ unblurThumbnails: false, consented: new SvelteSet(), unblurText: false });
2
10
 
3
11
  export const nsfwBlurStyle = 'filter: blur(200px); overflow: hidden;';
4
12
 
5
- export function nsfwBlur(nsfw?: boolean): string {
6
- if (nsfw && !nsfwConsented.consented) {
13
+ export function nsfwBlur(
14
+ nsfw: boolean | undefined,
15
+ sha256: ImageId = '.',
16
+ imageType: 'full' | 'thumb' = 'thumb'
17
+ ): string {
18
+ const didConsent = nsfwConsented.consented === 'all' || nsfwConsented.consented.has(sha256);
19
+ const shouldBlur = didConsent && (nsfwConsented.unblurThumbnails || imageType === 'full');
20
+ if (nsfw && shouldBlur) {
7
21
  return nsfwBlurStyle;
8
22
  }
9
23
  return '';
10
24
  }
11
25
 
12
26
  export function nsfwRedact(s: string, nsfw?: boolean): string {
13
- if (nsfw && !nsfwConsented.consented) {
27
+ if (nsfw && !nsfwConsented.unblurText) {
14
28
  return '[redacted: nsfw]';
15
29
  }
16
30
  return s;