@graffiti-garden/implementation-decentralized 0.0.1 → 0.0.3

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.
Files changed (36) hide show
  1. package/dist/1-services/4-inboxes-tests.d.ts.map +1 -1
  2. package/dist/1-services/4-inboxes.d.ts +3 -3
  3. package/dist/1-services/4-inboxes.d.ts.map +1 -1
  4. package/dist/3-protocol/4-graffiti.d.ts.map +1 -1
  5. package/dist/3-protocol/login-dialog.html.d.ts +1 -1
  6. package/dist/3-protocol/login-dialog.html.d.ts.map +1 -1
  7. package/dist/browser/index.js +7 -7
  8. package/dist/browser/index.js.map +3 -3
  9. package/dist/browser/login-dialog.html-VTDKJZBG.js +44 -0
  10. package/dist/browser/login-dialog.html-VTDKJZBG.js.map +7 -0
  11. package/dist/browser/{style-YUTCEBZV-RWYJV575.js → style-3ALLGCD7-QNFKN6AK.js} +18 -36
  12. package/dist/browser/style-3ALLGCD7-QNFKN6AK.js.map +7 -0
  13. package/dist/cjs/1-services/4-inboxes-tests.js +2 -0
  14. package/dist/cjs/1-services/4-inboxes-tests.js.map +2 -2
  15. package/dist/cjs/1-services/4-inboxes.js +17 -8
  16. package/dist/cjs/1-services/4-inboxes.js.map +2 -2
  17. package/dist/cjs/3-protocol/4-graffiti.js +40 -12
  18. package/dist/cjs/3-protocol/4-graffiti.js.map +2 -2
  19. package/dist/cjs/3-protocol/login-dialog.html.js +9 -9
  20. package/dist/cjs/3-protocol/login-dialog.html.js.map +1 -1
  21. package/dist/esm/1-services/4-inboxes-tests.js +2 -0
  22. package/dist/esm/1-services/4-inboxes-tests.js.map +2 -2
  23. package/dist/esm/1-services/4-inboxes.js +19 -9
  24. package/dist/esm/1-services/4-inboxes.js.map +2 -2
  25. package/dist/esm/3-protocol/4-graffiti.js +41 -12
  26. package/dist/esm/3-protocol/4-graffiti.js.map +2 -2
  27. package/dist/esm/3-protocol/login-dialog.html.js +9 -9
  28. package/dist/esm/3-protocol/login-dialog.html.js.map +1 -1
  29. package/package.json +10 -7
  30. package/src/1-services/4-inboxes-tests.ts +2 -0
  31. package/src/1-services/4-inboxes.ts +25 -15
  32. package/src/3-protocol/4-graffiti.ts +65 -17
  33. package/src/3-protocol/login-dialog.html.ts +9 -9
  34. package/dist/browser/login-dialog.html-XUWYDNNI.js +0 -44
  35. package/dist/browser/login-dialog.html-XUWYDNNI.js.map +0 -7
  36. package/dist/browser/style-YUTCEBZV-RWYJV575.js.map +0 -7
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/3-protocol/login-dialog.html.ts"],
4
- "sourcesContent": ["export const template = `<template id=\"graffiti-login-welcome\">\n <h1>\n <a target=\"_blank\" href=\"https://graffiti.garden\">Graffiti<wbr> Log In</a>\n </h1>\n\n <ul>\n <li><a type=\"button\" id=\"graffiti-login-new\">Create new Graffiti identity</a></li>\n <li><button class=\"secondary\" id=\"graffiti-login-existing\">Use existing Graffiti identity</button></li>\n </ul>\n\n <aside>\n This application is built with\n <a target=\"_blank\" href=\"https://graffiti.garden\">Graffiti</a>.\n </aside>\n</template>\n\n<template id=\"graffiti-login-handle\">\n <h1>\n <a target=\"_blank\" href=\"https://graffiti.garden\">Graffiti<wbr> Log In</a>\n </h1>\n\n <form id=\"graffiti-login-handle-form\">\n <label for=\"username\">Enter your Graffiti handle:</label>\n <input\n type=\"text\"\n name=\"username\"\n id=\"username\"\n autocomplete=\"username\"\n autocapitalize=\"none\"\n spellcheck=\"false\"\n inputmode=\"url\"\n placeholder=\"example.graffiti.actor\"\n required\n >\n <button id=\"graffiti-login-handle-submit\" type=\"submit\">\n Log In\n </button>\n </form>\n\n <p>\n Don't have a Graffiti handle? <a id=\"graffiti-login-new\">Create one</a>.\n </p>\n</template>`;\n"],
4
+ "sourcesContent": ["export const template = `<template id=\"graffiti-login-welcome\">\n <h1>\n <a target=\"_blank\" href=\"https://graffiti.garden\">Graffiti Log&nbsp;In</a>\n </h1>\n\n <ul>\n <li><a type=\"button\" id=\"graffiti-login-new\">Create&nbsp;new Graffiti&nbsp;identity</a></li>\n <li><button class=\"secondary\" id=\"graffiti-login-existing\">Use&nbsp;existing Graffiti&nbsp;identity</button></li>\n </ul>\n\n <aside>\n This application is built with\n <a target=\"_blank\" href=\"https://graffiti.garden\">Graffiti</a>.\n </aside>\n</template>\n\n<template id=\"graffiti-login-handle\">\n<h1>\n <a target=\"_blank\" href=\"https://graffiti.garden\">Graffiti Log&nbsp;In</a>\n</h1>\n\n <form id=\"graffiti-login-handle-form\">\n <label for=\"username\">Graffiti handle:</label>\n <input\n type=\"text\"\n name=\"username\"\n id=\"username\"\n autocomplete=\"username\"\n autocapitalize=\"none\"\n spellcheck=\"false\"\n inputmode=\"url\"\n placeholder=\"you.graffiti.actor\"\n required\n >\n <button id=\"graffiti-login-handle-submit\" type=\"submit\">\n Log In\n </button>\n </form>\n\n <p>\n Don't&nbsp;have&nbsp;a Graffiti&nbsp;handle? <a id=\"graffiti-login-new\">Create&nbsp;one</a>.\n </p>\n</template>`;\n"],
5
5
  "mappings": "AAAO,MAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@graffiti-garden/implementation-decentralized",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "A client for a decentralized implementation of the Graffiti API",
5
- "types": "./dist/src/index.d.ts",
5
+ "types": "./dist/index.d.ts",
6
6
  "module": "./dist/esm/index.js",
7
7
  "main": "./dist/cjs/index.js",
8
8
  "browser": "./dist/browser/index.js",
9
9
  "exports": {
10
10
  ".": {
11
11
  "import": {
12
- "types": "./dist/src/index.d.ts",
12
+ "types": "./dist/index.d.ts",
13
13
  "default": "./dist/esm/index.js"
14
14
  },
15
15
  "require": {
16
- "types": "./dist/src/index.d.ts",
16
+ "types": "./dist/index.d.ts",
17
17
  "default": "./dist/cjs/index.js"
18
18
  }
19
19
  }
@@ -27,7 +27,9 @@
27
27
  "author": "Theia Henderson",
28
28
  "license": "GPL-3.0-or-later",
29
29
  "scripts": {
30
- "test": "NODE_TLS_REJECT_UNAUTHORIZED=0 vitest",
30
+ "test": "NODE_TLS_REJECT_UNAUTHORIZED=0 vitest run",
31
+ "test:watch": "NODE_TLS_REJECT_UNAUTHORIZED=0 vitest --watch",
32
+ "test:coverage": "NODE_TLS_REJECT_UNAUTHORIZED=0 vitest --coverage",
31
33
  "build:types": "tsc --declaration --emitDeclarationOnly",
32
34
  "build:js": "tsx esbuild.config.mts",
33
35
  "build": "rm -rf dist && npm run build:types && npm run build:js",
@@ -42,13 +44,14 @@
42
44
  },
43
45
  "devDependencies": {
44
46
  "@types/node": "^25.0.9",
47
+ "@vitest/coverage-v8": "^4.0.17",
45
48
  "tsx": "^4.21.0",
46
49
  "typescript": "^5.9.3",
47
50
  "vitest": "^4.0.17"
48
51
  },
49
52
  "dependencies": {
50
- "@graffiti-garden/api": "^1.1.0",
51
- "@graffiti-garden/modal": "^1.0.1",
53
+ "@graffiti-garden/api": "^1.1.1",
54
+ "@graffiti-garden/modal": "^1.0.2",
52
55
  "@ipld/dag-cbor": "^9.2.5",
53
56
  "@noble/ed25519": "^3.0.0",
54
57
  "@noble/hashes": "^2.0.1",
@@ -32,6 +32,7 @@ export function inboxTests(inboxEndpoint: string, inboxToken: string) {
32
32
 
33
33
  // Get the message back
34
34
  const message = await inboxes.get(inboxEndpoint, messageId, inboxToken);
35
+ assert(message !== null);
35
36
  expect(message.m).toEqual(sending);
36
37
  expect(message.l).toEqual(0);
37
38
 
@@ -62,6 +63,7 @@ export function inboxTests(inboxEndpoint: string, inboxToken: string) {
62
63
  expect(endResult2.done).toBe(true);
63
64
 
64
65
  const message2 = await inboxes.get(inboxEndpoint, messageId, inboxToken);
66
+ assert(message2 !== null);
65
67
  expect(message2.m).toEqual(sending);
66
68
  expect(message2.l).toEqual(42);
67
69
  });
@@ -7,6 +7,7 @@ import {
7
7
  import {
8
8
  compileGraffitiObjectSchema,
9
9
  GraffitiErrorCursorExpired,
10
+ GraffitiErrorNotFound,
10
11
  } from "@graffiti-garden/api";
11
12
  import {
12
13
  encode as dagCborEncode,
@@ -61,23 +62,32 @@ export class Inboxes {
61
62
  inboxUrl: string,
62
63
  messageId: string,
63
64
  inboxToken?: string | null,
64
- ): Promise<LabeledMessageBase> {
65
+ ): Promise<LabeledMessageBase | null> {
65
66
  const messageCacheKey = getMessageCacheKey(inboxUrl, messageId);
66
67
  const cache = await this.cache;
67
68
  const cached = await cache.messages.get(messageCacheKey);
68
- if (cached) return cached;
69
+ if (cached !== undefined) return cached;
69
70
 
70
71
  const url = `${inboxUrl}/message/${messageId}`;
71
- const response = await fetchWithErrorHandling(url, {
72
- method: "GET",
73
- headers: {
74
- ...(inboxToken
75
- ? {
76
- Authorization: `Bearer ${inboxToken}`,
77
- }
78
- : {}),
79
- },
80
- });
72
+ let response: Response | null = null;
73
+ try {
74
+ response = await fetchWithErrorHandling(url, {
75
+ method: "GET",
76
+ headers: {
77
+ ...(inboxToken
78
+ ? {
79
+ Authorization: `Bearer ${inboxToken}`,
80
+ }
81
+ : {}),
82
+ },
83
+ });
84
+ } catch (e) {
85
+ if (e instanceof GraffitiErrorNotFound) {
86
+ await cache.messages.set(messageCacheKey, null);
87
+ return null;
88
+ }
89
+ throw e;
90
+ }
81
91
 
82
92
  const blob = await response.blob();
83
93
  const cbor = dagCborDecode(await blob.arrayBuffer());
@@ -607,8 +617,8 @@ async function canUseIDB(): Promise<boolean> {
607
617
 
608
618
  type Cache = {
609
619
  messages: {
610
- get(k: string): Promise<LabeledMessageBase | undefined>;
611
- set(k: string, value: LabeledMessageBase): Promise<void>;
620
+ get(k: string): Promise<LabeledMessageBase | null | undefined>;
621
+ set(k: string, value: LabeledMessageBase | null): Promise<void>;
612
622
  del(k: string): Promise<void>;
613
623
  };
614
624
  messageIds: {
@@ -695,7 +705,7 @@ async function createCache(): Promise<Cache> {
695
705
  };
696
706
  }
697
707
 
698
- const m = new Map<string, LabeledMessageBase>();
708
+ const m = new Map<string, LabeledMessageBase | null>();
699
709
  const q = new Map<string, CacheQueryValue>();
700
710
 
701
711
  return {
@@ -29,6 +29,7 @@ import { Authorization } from "../1-services/1-authorization";
29
29
  import { StorageBuckets } from "../1-services/3-storage-buckets";
30
30
  import {
31
31
  Inboxes,
32
+ LABELED_MESSAGE_LABEL_KEY,
32
33
  LABELED_MESSAGE_MESSAGE_KEY,
33
34
  MESSAGE_METADATA_KEY,
34
35
  MESSAGE_OBJECT_KEY,
@@ -239,11 +240,7 @@ export class GraffitiDecentralized implements Graffiti {
239
240
  ) as HTMLInputElement | null;
240
241
  input?.setAttribute("value", proposedHandle);
241
242
  input?.addEventListener("focus", () => input?.select());
242
- new Promise<void>((r) => {
243
- setTimeout(() => r(), 0);
244
- }).then(() => {
245
- input?.focus();
246
- });
243
+ setTimeout(() => input?.focus(), 0);
247
244
 
248
245
  template
249
246
  ?.querySelector("#graffiti-login-handle-form")
@@ -293,13 +290,16 @@ export class GraffitiDecentralized implements Graffiti {
293
290
  e.preventDefault();
294
291
  this.login_("");
295
292
  });
296
- new Promise<void>((r) => {
297
- setTimeout(() => r(), 0);
298
- }).then(() => {
299
- (
300
- template?.querySelector("#graffiti-login-new") as HTMLAnchorElement
301
- )?.focus();
302
- });
293
+
294
+ setTimeout(
295
+ () =>
296
+ (
297
+ template?.querySelector(
298
+ "#graffiti-login-new",
299
+ ) as HTMLAnchorElement
300
+ )?.focus(),
301
+ 0,
302
+ );
303
303
  }
304
304
 
305
305
  const createUrl = new URL(this.identityCreatorEndpoint);
@@ -1017,7 +1017,12 @@ export class GraffitiDecentralized implements Graffiti {
1017
1017
  const result = itResult.value;
1018
1018
 
1019
1019
  const label = result.l;
1020
- if (label !== MESSAGE_LABEL_VALID && label !== MESSAGE_LABEL_UNLABELED)
1020
+ // Anything invalid or unexpected, we can skip
1021
+ if (
1022
+ label !== MESSAGE_LABEL_VALID &&
1023
+ label !== MESSAGE_LABEL_UNLABELED &&
1024
+ label !== MESSAGE_LABEL_TRASH
1025
+ )
1021
1026
  continue;
1022
1027
 
1023
1028
  const messageId = result.id;
@@ -1061,9 +1066,50 @@ export class GraffitiDecentralized implements Graffiti {
1061
1066
  announcements,
1062
1067
  };
1063
1068
  continue;
1069
+ } else if (label === MESSAGE_LABEL_TRASH) {
1070
+ // If it is simply trash, just continue.
1071
+ if (!tombstonedMessageId) continue;
1072
+
1073
+ // Make sure the tombstone points to a real message
1074
+ const past = await this.inboxes.get(
1075
+ inboxEndpoint,
1076
+ tombstonedMessageId,
1077
+ inboxToken,
1078
+ );
1079
+ if (
1080
+ !past ||
1081
+ past[LABELED_MESSAGE_MESSAGE_KEY][MESSAGE_OBJECT_KEY].url !==
1082
+ object.url
1083
+ )
1084
+ continue;
1085
+
1086
+ // If the referred to message isn't labeled as trash, trash it
1087
+ // This may happen if a trash message is processed on another
1088
+ // device and the device cache is out of date.
1089
+ if (past[LABELED_MESSAGE_LABEL_KEY] !== MESSAGE_LABEL_TRASH) {
1090
+ // Label the message as trash
1091
+ this.inboxes.label(
1092
+ inboxEndpoint,
1093
+ tombstonedMessageId,
1094
+ MESSAGE_LABEL_TRASH,
1095
+ inboxToken,
1096
+ );
1097
+ }
1098
+
1099
+ // Return the tombstone
1100
+ yield {
1101
+ messageId,
1102
+ tombstone: true,
1103
+ object,
1104
+ storageBucketKey,
1105
+ allowedTickets,
1106
+ tags: receivedTags,
1107
+ announcements,
1108
+ };
1109
+ continue;
1064
1110
  }
1065
1111
 
1066
- // Try to validate the object
1112
+ // Otherwise, unlabeled: try to validate the object
1067
1113
  let validationError: unknown | undefined = undefined;
1068
1114
  try {
1069
1115
  const actor = object.actor;
@@ -1123,13 +1169,15 @@ export class GraffitiDecentralized implements Graffiti {
1123
1169
  // Get the referenced message
1124
1170
  .get(inboxEndpoint, tombstonedMessageId, inboxToken)
1125
1171
  .then((result) => {
1126
- // Make sure that it actually references the object being deleted
1127
1172
  if (
1173
+ // Make sure that it actually references the object being deleted
1128
1174
  result &&
1129
1175
  result[LABELED_MESSAGE_MESSAGE_KEY][MESSAGE_OBJECT_KEY].url ===
1130
- object.url
1176
+ object.url &&
1177
+ // And that the object is not already marked as trash
1178
+ result[LABELED_MESSAGE_LABEL_KEY] !== MESSAGE_LABEL_TRASH
1131
1179
  ) {
1132
- // If it does, label the message as trash, it is no longer needed
1180
+ // If valid but not yet trash, label the message as trash
1133
1181
  this.inboxes.label(
1134
1182
  inboxEndpoint,
1135
1183
  tombstonedMessageId,
@@ -1,11 +1,11 @@
1
1
  export const template = `<template id="graffiti-login-welcome">
2
2
  <h1>
3
- <a target="_blank" href="https://graffiti.garden">Graffiti<wbr> Log In</a>
3
+ <a target="_blank" href="https://graffiti.garden">Graffiti Log&nbsp;In</a>
4
4
  </h1>
5
5
 
6
6
  <ul>
7
- <li><a type="button" id="graffiti-login-new">Create new Graffiti identity</a></li>
8
- <li><button class="secondary" id="graffiti-login-existing">Use existing Graffiti identity</button></li>
7
+ <li><a type="button" id="graffiti-login-new">Create&nbsp;new Graffiti&nbsp;identity</a></li>
8
+ <li><button class="secondary" id="graffiti-login-existing">Use&nbsp;existing Graffiti&nbsp;identity</button></li>
9
9
  </ul>
10
10
 
11
11
  <aside>
@@ -15,12 +15,12 @@ export const template = `<template id="graffiti-login-welcome">
15
15
  </template>
16
16
 
17
17
  <template id="graffiti-login-handle">
18
- <h1>
19
- <a target="_blank" href="https://graffiti.garden">Graffiti<wbr> Log In</a>
20
- </h1>
18
+ <h1>
19
+ <a target="_blank" href="https://graffiti.garden">Graffiti Log&nbsp;In</a>
20
+ </h1>
21
21
 
22
22
  <form id="graffiti-login-handle-form">
23
- <label for="username">Enter your Graffiti handle:</label>
23
+ <label for="username">Graffiti handle:</label>
24
24
  <input
25
25
  type="text"
26
26
  name="username"
@@ -29,7 +29,7 @@ export const template = `<template id="graffiti-login-welcome">
29
29
  autocapitalize="none"
30
30
  spellcheck="false"
31
31
  inputmode="url"
32
- placeholder="example.graffiti.actor"
32
+ placeholder="you.graffiti.actor"
33
33
  required
34
34
  >
35
35
  <button id="graffiti-login-handle-submit" type="submit">
@@ -38,6 +38,6 @@ export const template = `<template id="graffiti-login-welcome">
38
38
  </form>
39
39
 
40
40
  <p>
41
- Don't have a Graffiti handle? <a id="graffiti-login-new">Create one</a>.
41
+ Don't&nbsp;have&nbsp;a Graffiti&nbsp;handle? <a id="graffiti-login-new">Create&nbsp;one</a>.
42
42
  </p>
43
43
  </template>`;
@@ -1,44 +0,0 @@
1
- import"./chunk-RFBBAUMM.js";var t=`<template id="graffiti-login-welcome">
2
- <h1>
3
- <a target="_blank" href="https://graffiti.garden">Graffiti<wbr> Log In</a>
4
- </h1>
5
-
6
- <ul>
7
- <li><a type="button" id="graffiti-login-new">Create new Graffiti identity</a></li>
8
- <li><button class="secondary" id="graffiti-login-existing">Use existing Graffiti identity</button></li>
9
- </ul>
10
-
11
- <aside>
12
- This application is built with
13
- <a target="_blank" href="https://graffiti.garden">Graffiti</a>.
14
- </aside>
15
- </template>
16
-
17
- <template id="graffiti-login-handle">
18
- <h1>
19
- <a target="_blank" href="https://graffiti.garden">Graffiti<wbr> Log In</a>
20
- </h1>
21
-
22
- <form id="graffiti-login-handle-form">
23
- <label for="username">Enter your Graffiti handle:</label>
24
- <input
25
- type="text"
26
- name="username"
27
- id="username"
28
- autocomplete="username"
29
- autocapitalize="none"
30
- spellcheck="false"
31
- inputmode="url"
32
- placeholder="example.graffiti.actor"
33
- required
34
- >
35
- <button id="graffiti-login-handle-submit" type="submit">
36
- Log In
37
- </button>
38
- </form>
39
-
40
- <p>
41
- Don't have a Graffiti handle? <a id="graffiti-login-new">Create one</a>.
42
- </p>
43
- </template>`;export{t as template};
44
- //# sourceMappingURL=login-dialog.html-XUWYDNNI.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/3-protocol/login-dialog.html.ts"],
4
- "sourcesContent": ["export const template = `<template id=\"graffiti-login-welcome\">\n <h1>\n <a target=\"_blank\" href=\"https://graffiti.garden\">Graffiti<wbr> Log In</a>\n </h1>\n\n <ul>\n <li><a type=\"button\" id=\"graffiti-login-new\">Create new Graffiti identity</a></li>\n <li><button class=\"secondary\" id=\"graffiti-login-existing\">Use existing Graffiti identity</button></li>\n </ul>\n\n <aside>\n This application is built with\n <a target=\"_blank\" href=\"https://graffiti.garden\">Graffiti</a>.\n </aside>\n</template>\n\n<template id=\"graffiti-login-handle\">\n <h1>\n <a target=\"_blank\" href=\"https://graffiti.garden\">Graffiti<wbr> Log In</a>\n </h1>\n\n <form id=\"graffiti-login-handle-form\">\n <label for=\"username\">Enter your Graffiti handle:</label>\n <input\n type=\"text\"\n name=\"username\"\n id=\"username\"\n autocomplete=\"username\"\n autocapitalize=\"none\"\n spellcheck=\"false\"\n inputmode=\"url\"\n placeholder=\"example.graffiti.actor\"\n required\n >\n <button id=\"graffiti-login-handle-submit\" type=\"submit\">\n Log In\n </button>\n </form>\n\n <p>\n Don't have a Graffiti handle? <a id=\"graffiti-login-new\">Create one</a>.\n </p>\n</template>`;\n"],
5
- "mappings": "4BAAO,IAAMA,EAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
6
- "names": ["template"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../node_modules/@graffiti-garden/modal/src/style.css"],
4
- "sourcesContent": [".graffiti-modal {\n --back: rgb(26, 26, 26, 0.85);\n --halfback: rgba(80, 80, 80, 0.85);\n --halfback2: rgba(26, 26, 26, 0.85);\n --hover: rgba(202, 122, 204, 0.3);\n --frontfaded: rgba(190, 190, 190);\n --front: rgba(240, 240, 240);\n --emph: rgb(202, 122, 204);\n --blurpix: 3px;\n border-color: var(--emph);\n box-sizing: border-box;\n border-width: 2px;\n padding: 0;\n margin: 0;\n border-radius: 1rem;\n box-shadow: 0 0 2rem black;\n overflow: hidden;\n opacity: 0;\n transition: opacity 0.3s;\n pointer-events: none;\n display: block;\n min-width: 95dvw;\n min-height: 95dvh;\n height: 95dvh;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: center;\n font-family:\n Inter,\n -apple-system,\n BlinkMacSystemFont,\n \"Segoe UI\",\n Roboto,\n Oxygen,\n Ubuntu,\n Cantarell,\n \"Fira Sans\",\n \"Droid Sans\",\n \"Helvetica Neue\",\n sans-serif;\n color: var(--front);\n font-size: 150%;\n\n * {\n box-sizing: border-box;\n padding: 0;\n margin: 0;\n }\n\n ::selection {\n background: rgba(202, 122, 204, 0.3);\n }\n\n :focus {\n outline: 2px solid var(--front);\n }\n\n header {\n width: 100%;\n display: flex;\n justify-content: flex-end;\n }\n\n main {\n flex: 1;\n max-width: 600px;\n width: 100%;\n gap: 2em;\n padding-top: 4dvh;\n padding-bottom: 4dvh;\n margin-top: 4dvh;\n margin-bottom: 4dvh;\n margin-left: 4dvw;\n margin-right: 4dvw;\n padding-left: 4dvw;\n padding-right: 4dvw;\n background: var(--back);\n border-radius: 1rem;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n scrollbar-color: var(--emph) rgba(0, 0, 0, 0);\n }\n\n ul {\n list-style-type: none;\n display: flex;\n flex-direction: column;\n gap: 0.5em;\n align-items: stretch;\n justify-content: stretch;\n }\n\n aside {\n color: var(--frontfaded);\n }\n\n .secondary,\n a:not([type=\"button\"]) {\n color: var(--emph);\n }\n\n h1 {\n font-size: 120%;\n font-family:\n Rock Salt,\n cursive,\n sans-serif;\n letter-spacing: 0.1em;\n text-align: center;\n color: var(--front);\n }\n\n h1 a:not([type=\"button\"]) {\n color: inherit;\n }\n\n h1 a:hover {\n background: none;\n color: inherit;\n }\n\n button,\n input[type=\"submit\"],\n input[type=\"text\"],\n a[type=\"button\"] {\n font-size: inherit;\n width: 100%;\n text-align: center;\n display: block;\n border-radius: 1rem;\n border: 2px solid var(--emph);\n padding: 1em;\n padding-top: 0.5em;\n padding-bottom: 0.5em;\n transition: 0.1s;\n text-overflow: ellipsis;\n background: none;\n line-height: 1.2em;\n }\n\n input[type=\"text\"] {\n font-weight: 500;\n background: var(--front);\n text-align: left;\n color: black;\n }\n\n header button {\n border-radius: 0 0 0 1rem;\n border-right: none;\n border-top: none;\n background-color: var(--halfback2);\n width: fit-content;\n position: relative;\n overflow: hidden;\n }\n\n header button::before {\n z-index: -1;\n top: 0;\n left: 0;\n height: 100%;\n position: absolute;\n width: 100%;\n content: \"\";\n background-color: var(--back);\n }\n\n @media (max-width: 600px) {\n main {\n border-radius: 0;\n margin: auto;\n overflow: auto;\n }\n\n header button {\n border-radius: 0;\n border-left: none;\n width: 100%;\n }\n\n html {\n justify-content: safe center;\n }\n }\n\n a {\n text-decoration: none;\n }\n\n :is(button, ul a, input[type=\"submit\"]):hover {\n cursor: pointer;\n background: var(--hover);\n color: var(--front);\n }\n\n a:hover {\n text-decoration: underline;\n cursor: pointer;\n }\n\n form {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: stretch;\n gap: 0.5em;\n }\n\n iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n\n :is(button, a[type=\"button\"], input[type=\"submit\"]).secondary {\n color: rgb(244, 213, 244);\n background: rgba(26, 26, 26, 0.6);\n }\n\n :is(button, a[type=\"button\"], input[type=\"submit\"]):not(.secondary) {\n background: var(--hover);\n color: white;\n }\n\n :is(button, a[type=\"button\"], input[type=\"submit\"]):hover {\n background: rgba(202, 122, 204, 0.6);\n color: white;\n text-decoration: none;\n }\n\n h3 {\n color: var(--frontfaded);\n }\n\n h2 {\n text-align: center;\n font-weight: 500;\n font-size: 150%;\n background: var(--halfback2);\n padding: 1rem;\n border-radius: 1rem;\n border: 1px solid var(--frontfaded);\n color: var(--front);\n }\n\n main > div {\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: stretch;\n gap: 0.5rem;\n }\n}\n\n.graffiti-modal[open] {\n pointer-events: inherit;\n opacity: 1;\n}\n\n.graffiti-modal::backdrop {\n background-color: black;\n opacity: 0.5;\n}\n\n.graffiti-modal::before {\n content: \"\";\n position: fixed;\n left: 0;\n right: 0;\n z-index: -1;\n background-image: url(graffiti.jpg);\n background-size: cover;\n background-repeat: no-repeat;\n background-position: 50% 50%;\n height: calc(100% + 2 * var(--blurpix));\n width: calc(100% + 2 * var(--blurpix));\n filter: blur(var(--blurpix));\n margin: calc(-1 * var(--blurpix));\n}\n"],
5
- "mappings": "4BAAA,IAAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;",
6
- "names": ["style_default"]
7
- }