diff options
Diffstat (limited to 'subprojects/frontend')
19 files changed, 408 insertions, 18 deletions
diff --git a/subprojects/frontend/assets-src/favicon.svg b/subprojects/frontend/assets-src/favicon.svg new file mode 100644 index 00000000..39079ef3 --- /dev/null +++ b/subprojects/frontend/assets-src/favicon.svg | |||
@@ -0,0 +1,76 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
2 | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||
3 | |||
4 | <svg | ||
5 | width="512" | ||
6 | height="512" | ||
7 | viewBox="0 0 512 512" | ||
8 | version="1.1" | ||
9 | id="svg5" | ||
10 | inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)" | ||
11 | sodipodi:docname="favicon.svg" | ||
12 | inkscape:export-filename="../public/favicon.png" | ||
13 | inkscape:export-xdpi="6" | ||
14 | inkscape:export-ydpi="6" | ||
15 | xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||
16 | xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||
17 | xmlns="http://www.w3.org/2000/svg" | ||
18 | xmlns:svg="http://www.w3.org/2000/svg"> | ||
19 | <sodipodi:namedview | ||
20 | id="namedview7" | ||
21 | pagecolor="#ffffff" | ||
22 | bordercolor="#666666" | ||
23 | borderopacity="1.0" | ||
24 | inkscape:showpageshadow="2" | ||
25 | inkscape:pageopacity="0.0" | ||
26 | inkscape:pagecheckerboard="0" | ||
27 | inkscape:deskcolor="#d1d1d1" | ||
28 | inkscape:document-units="mm" | ||
29 | showgrid="false" | ||
30 | inkscape:zoom="0.54060743" | ||
31 | inkscape:cx="-107.28672" | ||
32 | inkscape:cy="510.53682" | ||
33 | inkscape:window-width="2560" | ||
34 | inkscape:window-height="1415" | ||
35 | inkscape:window-x="0" | ||
36 | inkscape:window-y="0" | ||
37 | inkscape:window-maximized="1" | ||
38 | inkscape:current-layer="layer2"> | ||
39 | <inkscape:grid | ||
40 | type="xygrid" | ||
41 | id="grid1699" /> | ||
42 | </sodipodi:namedview> | ||
43 | <defs | ||
44 | id="defs2" /> | ||
45 | <g | ||
46 | inkscape:groupmode="layer" | ||
47 | id="layer3" | ||
48 | inkscape:label="Background"> | ||
49 | <rect | ||
50 | style="fill:#21252b;fill-opacity:1;stroke:none;stroke-width:0.264582;stroke-linecap:square;stroke-linejoin:bevel;stroke-opacity:0.6;paint-order:stroke fill markers;stop-color:#000000" | ||
51 | id="rect453" | ||
52 | width="512" | ||
53 | height="512" | ||
54 | x="0" | ||
55 | y="0" | ||
56 | inkscape:label="fill" /> | ||
57 | </g> | ||
58 | <g | ||
59 | inkscape:groupmode="layer" | ||
60 | id="layer2" | ||
61 | inkscape:label="Icon"> | ||
62 | <g | ||
63 | id="g1119-3-1" | ||
64 | transform="matrix(5.6319708,0,0,5.5934499,-125.4721,-122.86304)" | ||
65 | style="display:inline;stroke:none;stroke-width:0;stroke-dasharray:none"> | ||
66 | <path | ||
67 | style="font-size:114.487px;line-height:1.25;font-family:'XITS Math';-inkscape-font-specification:'XITS Math';letter-spacing:0px;word-spacing:0px;fill:#ebebff;fill-opacity:1;stroke:none;stroke-width:0;stroke-dasharray:none" | ||
68 | d="M 101.82441,54.027469 C 76.975254,52.314235 48.331396,44.925914 33.642238,27.686497 v 8.244938 c 6.120483,9.208633 25.828436,17.88188 40.884823,21.629579 -15.056387,3.747699 -34.76434,12.420945 -40.884823,21.629578 V 87.43553 C 48.331396,70.196113 76.975254,62.807792 101.82441,61.094559 Z" | ||
69 | id="path1113-6-8" /> | ||
70 | <path | ||
71 | style="font-size:114.487px;line-height:1.25;font-family:'XITS Math';-inkscape-font-specification:'XITS Math';letter-spacing:0px;word-spacing:0px;display:inline;fill:#56b6c2;fill-opacity:1;stroke:none;stroke-width:0;stroke-dasharray:none" | ||
72 | d="M 101.82441,75.014584 C 81.626821,75.764124 50.779589,82.295828 33.642238,99.42817 v 8.35201 C 50.53477,89.255841 83.340556,83.152445 101.82441,82.081674 Z" | ||
73 | id="path1061-7-7" /> | ||
74 | </g> | ||
75 | </g> | ||
76 | </svg> | ||
diff --git a/subprojects/frontend/assets-src/icon.svg b/subprojects/frontend/assets-src/icon.svg new file mode 100644 index 00000000..f16c9f62 --- /dev/null +++ b/subprojects/frontend/assets-src/icon.svg | |||
@@ -0,0 +1,99 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
2 | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||
3 | |||
4 | <svg | ||
5 | width="512" | ||
6 | height="512" | ||
7 | viewBox="0 0 512 512" | ||
8 | version="1.1" | ||
9 | id="svg5" | ||
10 | inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)" | ||
11 | sodipodi:docname="icon.svg" | ||
12 | inkscape:export-filename="../apple-touch-icon.png" | ||
13 | inkscape:export-xdpi="33.75" | ||
14 | inkscape:export-ydpi="33.75" | ||
15 | xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||
16 | xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||
17 | xmlns="http://www.w3.org/2000/svg" | ||
18 | xmlns:svg="http://www.w3.org/2000/svg"> | ||
19 | <sodipodi:namedview | ||
20 | id="namedview7" | ||
21 | pagecolor="#ffffff" | ||
22 | bordercolor="#666666" | ||
23 | borderopacity="1.0" | ||
24 | inkscape:showpageshadow="2" | ||
25 | inkscape:pageopacity="0.0" | ||
26 | inkscape:pagecheckerboard="0" | ||
27 | inkscape:deskcolor="#d1d1d1" | ||
28 | inkscape:document-units="mm" | ||
29 | showgrid="false" | ||
30 | inkscape:zoom="0.7971076" | ||
31 | inkscape:cx="194.45305" | ||
32 | inkscape:cy="286.03416" | ||
33 | inkscape:window-width="2560" | ||
34 | inkscape:window-height="1415" | ||
35 | inkscape:window-x="0" | ||
36 | inkscape:window-y="0" | ||
37 | inkscape:window-maximized="1" | ||
38 | inkscape:current-layer="layer3" /> | ||
39 | <defs | ||
40 | id="defs2" /> | ||
41 | <g | ||
42 | inkscape:groupmode="layer" | ||
43 | id="layer3" | ||
44 | inkscape:label="Background"> | ||
45 | <rect | ||
46 | style="fill:#21252b;fill-opacity:1;stroke:none;stroke-width:0.264582;stroke-linecap:square;stroke-linejoin:bevel;stroke-opacity:0.6;paint-order:stroke fill markers;stop-color:#000000" | ||
47 | id="rect453" | ||
48 | width="512" | ||
49 | height="512" | ||
50 | x="0" | ||
51 | y="0" | ||
52 | inkscape:label="fill" /> | ||
53 | </g> | ||
54 | <g | ||
55 | inkscape:groupmode="layer" | ||
56 | id="layer2" | ||
57 | inkscape:label="Icon"> | ||
58 | <g | ||
59 | id="g1119-3" | ||
60 | transform="matrix(3.8719803,0,0,3.8954379,-6.2620826,-7.8510277)" | ||
61 | style="display:inline;opacity:1;stroke:none;stroke-width:0;stroke-dasharray:none"> | ||
62 | <path | ||
63 | style="font-size:114.487px;line-height:1.25;font-family:'XITS Math';-inkscape-font-specification:'XITS Math';letter-spacing:0px;word-spacing:0px;fill:#181a1f;fill-opacity:1;stroke:none;stroke-width:0;stroke-dasharray:none" | ||
64 | d="M 101.82441,58.134836 C 76.975254,56.421602 48.331396,49.033281 33.642238,31.793864 v 8.244938 c 6.120483,9.208633 25.828436,17.88188 40.884823,21.629579 -15.056387,3.747699 -34.76434,12.420945 -40.884823,21.629578 v 8.244938 C 48.331396,74.30348 76.975254,66.915159 101.82441,65.201926 Z" | ||
65 | id="path1113-6" /> | ||
66 | <path | ||
67 | style="font-size:114.487px;line-height:1.25;font-family:'XITS Math';-inkscape-font-specification:'XITS Math';letter-spacing:0px;word-spacing:0px;display:inline;fill:#181a1f;fill-opacity:1;stroke:none;stroke-width:0;stroke-dasharray:none" | ||
68 | d="m 101.82441,79.121951 c -20.197589,0.74954 -51.044821,7.281244 -68.182172,24.413589 v 8.35201 C 50.53477,93.363208 83.340556,87.259812 101.82441,86.189041 Z" | ||
69 | id="path1061-7" /> | ||
70 | </g> | ||
71 | <g | ||
72 | id="g1119-3-1" | ||
73 | transform="matrix(3.8719803,0,0,3.8954379,-6.2620826,-7.8510277)" | ||
74 | style="display:inline;stroke:none;stroke-width:0;stroke-dasharray:none"> | ||
75 | <path | ||
76 | style="font-size:114.487px;line-height:1.25;font-family:'XITS Math';-inkscape-font-specification:'XITS Math';letter-spacing:0px;word-spacing:0px;fill:#ebebff;fill-opacity:1;stroke:none;stroke-width:0;stroke-dasharray:none" | ||
77 | d="M 101.82441,54.027469 C 76.975254,52.314235 48.331396,44.925914 33.642238,27.686497 v 8.244938 c 6.120483,9.208633 25.828436,17.88188 40.884823,21.629579 -15.056387,3.747699 -34.76434,12.420945 -40.884823,21.629578 V 87.43553 C 48.331396,70.196113 76.975254,62.807792 101.82441,61.094559 Z" | ||
78 | id="path1113-6-8" /> | ||
79 | <path | ||
80 | style="font-size:114.487px;line-height:1.25;font-family:'XITS Math';-inkscape-font-specification:'XITS Math';letter-spacing:0px;word-spacing:0px;display:inline;fill:#56b6c2;fill-opacity:1;stroke:none;stroke-width:0;stroke-dasharray:none" | ||
81 | d="M 101.82441,75.014584 C 81.626821,75.764124 50.779589,82.295828 33.642238,99.42817 v 8.35201 C 50.53477,89.255841 83.340556,83.152445 101.82441,82.081674 Z" | ||
82 | id="path1061-7-7" /> | ||
83 | </g> | ||
84 | </g> | ||
85 | <g | ||
86 | inkscape:label="Guides" | ||
87 | inkscape:groupmode="layer" | ||
88 | id="layer1" | ||
89 | style="display:none;stroke:#ff00ff"> | ||
90 | <ellipse | ||
91 | style="opacity:1;fill:none;stroke:#ff00ff;stroke-width:0.264582;stroke-linecap:square;stroke-linejoin:bevel;stroke-dasharray:none;stroke-opacity:0.6;paint-order:stroke fill markers;stop-color:#000000" | ||
92 | id="path111" | ||
93 | cx="256" | ||
94 | cy="255.99997" | ||
95 | inkscape:label="safe_zone" | ||
96 | rx="204.14394" | ||
97 | ry="204.14391" /> | ||
98 | </g> | ||
99 | </svg> | ||
diff --git a/subprojects/frontend/assets-src/mask-icon.svg b/subprojects/frontend/assets-src/mask-icon.svg new file mode 100644 index 00000000..fc30ed61 --- /dev/null +++ b/subprojects/frontend/assets-src/mask-icon.svg | |||
@@ -0,0 +1,54 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
2 | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||
3 | |||
4 | <svg | ||
5 | width="512" | ||
6 | height="512" | ||
7 | viewBox="0 0 512 512" | ||
8 | version="1.1" | ||
9 | id="svg5" | ||
10 | inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)" | ||
11 | sodipodi:docname="mask-icon.svg" | ||
12 | inkscape:export-filename="../public/favicon.png" | ||
13 | inkscape:export-xdpi="6" | ||
14 | inkscape:export-ydpi="6" | ||
15 | xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||
16 | xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||
17 | xmlns="http://www.w3.org/2000/svg" | ||
18 | xmlns:svg="http://www.w3.org/2000/svg"> | ||
19 | <sodipodi:namedview | ||
20 | id="namedview7" | ||
21 | pagecolor="#ffffff" | ||
22 | bordercolor="#666666" | ||
23 | borderopacity="1.0" | ||
24 | inkscape:showpageshadow="2" | ||
25 | inkscape:pageopacity="0.0" | ||
26 | inkscape:pagecheckerboard="0" | ||
27 | inkscape:deskcolor="#d1d1d1" | ||
28 | inkscape:document-units="mm" | ||
29 | showgrid="false" | ||
30 | inkscape:zoom="0.54060743" | ||
31 | inkscape:cx="-107.28672" | ||
32 | inkscape:cy="510.53682" | ||
33 | inkscape:window-width="2560" | ||
34 | inkscape:window-height="1415" | ||
35 | inkscape:window-x="0" | ||
36 | inkscape:window-y="0" | ||
37 | inkscape:window-maximized="1" | ||
38 | inkscape:current-layer="layer2"> | ||
39 | <inkscape:grid | ||
40 | type="xygrid" | ||
41 | id="grid1699" /> | ||
42 | </sodipodi:namedview> | ||
43 | <defs | ||
44 | id="defs2" /> | ||
45 | <g | ||
46 | inkscape:groupmode="layer" | ||
47 | id="layer2" | ||
48 | inkscape:label="Icon"> | ||
49 | <path | ||
50 | id="path1113-6-8" | ||
51 | style="font-size:114.487px;line-height:1.25;font-family:'XITS Math';-inkscape-font-specification:'XITS Math';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0;stroke-dasharray:none" | ||
52 | d="M 64 32 L 64 78.117188 C 98.470348 129.62516 209.46467 178.13901 294.26172 199.10156 C 209.46467 220.0641 98.470348 268.57796 64 320.08594 L 64 366.20312 C 146.72883 269.7754 308.05042 228.45007 448 218.86719 L 448 179.33594 C 308.05042 169.75306 146.72883 128.42772 64 32 z M 448 296.72656 C 334.24788 300.91907 160.51696 337.4544 64 433.2832 L 64 480 C 159.13815 376.38513 343.89958 342.24516 448 336.25586 L 448 296.72656 z " /> | ||
53 | </g> | ||
54 | </svg> | ||
diff --git a/subprojects/frontend/build.gradle b/subprojects/frontend/build.gradle index 5ed90c31..da237411 100644 --- a/subprojects/frontend/build.gradle +++ b/subprojects/frontend/build.gradle | |||
@@ -23,7 +23,9 @@ def installFrontend = tasks.named('installFrontend') | |||
23 | 23 | ||
24 | def assembleFrontend = tasks.named('assembleFrontend') | 24 | def assembleFrontend = tasks.named('assembleFrontend') |
25 | assembleFrontend.configure { | 25 | assembleFrontend.configure { |
26 | inputs.dir 'public' | ||
26 | inputs.dir 'src' | 27 | inputs.dir 'src' |
28 | inputs.file 'index.html' | ||
27 | inputs.files('package.json', 'tsconfig.json', 'tsconfig.base.json', 'vite.config.ts') | 29 | inputs.files('package.json', 'tsconfig.json', 'tsconfig.base.json', 'vite.config.ts') |
28 | inputs.file rootProject.file('yarn.lock') | 30 | inputs.file rootProject.file('yarn.lock') |
29 | outputs.dir productionResources | 31 | outputs.dir productionResources |
@@ -80,7 +82,9 @@ tasks.named('check') { | |||
80 | 82 | ||
81 | tasks.register('serveFrontend', RunYarn) { | 83 | tasks.register('serveFrontend', RunYarn) { |
82 | dependsOn installFrontend | 84 | dependsOn installFrontend |
85 | inputs.dir 'public' | ||
83 | inputs.dir 'src' | 86 | inputs.dir 'src' |
87 | inputs.file 'index.html' | ||
84 | inputs.files('package.json', 'tsconfig.json', 'tsconfig.base.json', 'vite.config.ts') | 88 | inputs.files('package.json', 'tsconfig.json', 'tsconfig.base.json', 'vite.config.ts') |
85 | inputs.file rootProject.file('yarn.lock') | 89 | inputs.file rootProject.file('yarn.lock') |
86 | outputs.dir "${viteOutputDir}/development" | 90 | outputs.dir "${viteOutputDir}/development" |
diff --git a/subprojects/frontend/index.html b/subprojects/frontend/index.html index 999e69a3..92cc94c7 100644 --- a/subprojects/frontend/index.html +++ b/subprojects/frontend/index.html | |||
@@ -4,6 +4,14 @@ | |||
4 | <meta charset="utf-8"> | 4 | <meta charset="utf-8"> |
5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
6 | <title>Refinery</title> | 6 | <title>Refinery</title> |
7 | <meta name="description" content="An efficient graph solver for generating well-formed models"> | ||
8 | <link rel="icon" href="/favicon.svg" type="image/svg+xml"> | ||
9 | <link rel="icon" href="/favicon.png" type="image/png" sizes="32x32"> | ||
10 | <link rel="icon" href="/favicon-96x96.png" type="image/png" sizes="96x96"> | ||
11 | <link rel="apple-touch-icon" href="/apple-touch-icon.png" type="image/png" sizes="180x180"> | ||
12 | <link rel="mask-icon" href="/mask-icon.svg" type="image/svg+xml" color="#038a99"> | ||
13 | <meta name="theme-color" media="(prefers-color-scheme: dark)" content="#21252b"> | ||
14 | <meta name="theme-color" media="(prefers-color-scheme: light)" content="#fafafa"> | ||
7 | </head> | 15 | </head> |
8 | <body> | 16 | <body> |
9 | <noscript> | 17 | <noscript> |
diff --git a/subprojects/frontend/package.json b/subprojects/frontend/package.json index 69ff74c6..693f3d06 100644 --- a/subprojects/frontend/package.json +++ b/subprojects/frontend/package.json | |||
@@ -23,7 +23,7 @@ | |||
23 | "homepage": "https://refinery.tools", | 23 | "homepage": "https://refinery.tools", |
24 | "dependencies": { | 24 | "dependencies": { |
25 | "@codemirror/autocomplete": "^6.1.0", | 25 | "@codemirror/autocomplete": "^6.1.0", |
26 | "@codemirror/commands": "^6.0.1", | 26 | "@codemirror/commands": "^6.1.0", |
27 | "@codemirror/language": "^6.2.1", | 27 | "@codemirror/language": "^6.2.1", |
28 | "@codemirror/lint": "^6.0.0", | 28 | "@codemirror/lint": "^6.0.0", |
29 | "@codemirror/search": "^6.1.0", | 29 | "@codemirror/search": "^6.1.0", |
@@ -47,14 +47,15 @@ | |||
47 | "mobx": "^6.6.1", | 47 | "mobx": "^6.6.1", |
48 | "mobx-react-lite": "^3.4.0", | 48 | "mobx-react-lite": "^3.4.0", |
49 | "nanoid": "^4.0.0", | 49 | "nanoid": "^4.0.0", |
50 | "notistack": "^2.0.5", | ||
50 | "react": "^18.2.0", | 51 | "react": "^18.2.0", |
51 | "react-dom": "^18.2.0", | 52 | "react-dom": "^18.2.0", |
52 | "zod": "^3.18.0" | 53 | "zod": "^3.18.0" |
53 | }, | 54 | }, |
54 | "devDependencies": { | 55 | "devDependencies": { |
55 | "@lezer/generator": "^1.1.1", | 56 | "@lezer/generator": "^1.1.1", |
56 | "@types/eslint": "^8.4.5", | 57 | "@types/eslint": "^8.4.6", |
57 | "@types/node": "^18.7.6", | 58 | "@types/node": "^18.7.7", |
58 | "@types/prettier": "^2.7.0", | 59 | "@types/prettier": "^2.7.0", |
59 | "@types/react": "^18.0.17", | 60 | "@types/react": "^18.0.17", |
60 | "@types/react-dom": "^18.0.6", | 61 | "@types/react-dom": "^18.0.6", |
@@ -66,7 +67,7 @@ | |||
66 | "eslint-config-airbnb": "^19.0.4", | 67 | "eslint-config-airbnb": "^19.0.4", |
67 | "eslint-config-airbnb-typescript": "^17.0.0", | 68 | "eslint-config-airbnb-typescript": "^17.0.0", |
68 | "eslint-config-prettier": "^8.5.0", | 69 | "eslint-config-prettier": "^8.5.0", |
69 | "eslint-import-resolver-typescript": "^3.4.1", | 70 | "eslint-import-resolver-typescript": "^3.4.2", |
70 | "eslint-plugin-import": "^2.26.0", | 71 | "eslint-plugin-import": "^2.26.0", |
71 | "eslint-plugin-jsx-a11y": "^6.6.1", | 72 | "eslint-plugin-jsx-a11y": "^6.6.1", |
72 | "eslint-plugin-prettier": "^4.2.1", | 73 | "eslint-plugin-prettier": "^4.2.1", |
@@ -74,7 +75,9 @@ | |||
74 | "eslint-plugin-react-hooks": "^4.6.0", | 75 | "eslint-plugin-react-hooks": "^4.6.0", |
75 | "prettier": "^2.7.1", | 76 | "prettier": "^2.7.1", |
76 | "typescript": "~4.7.4", | 77 | "typescript": "~4.7.4", |
77 | "vite": "^3.0.8", | 78 | "vite": "^3.0.9", |
78 | "vite-plugin-inject-preload": "^1.0.1" | 79 | "vite-plugin-inject-preload": "^1.0.1", |
80 | "vite-plugin-pwa": "^0.12.3", | ||
81 | "workbox-window": "^6.5.4" | ||
79 | } | 82 | } |
80 | } | 83 | } |
diff --git a/subprojects/frontend/public/apple-touch-icon.png b/subprojects/frontend/public/apple-touch-icon.png new file mode 100644 index 00000000..de8549e7 --- /dev/null +++ b/subprojects/frontend/public/apple-touch-icon.png | |||
Binary files differ | |||
diff --git a/subprojects/frontend/public/favicon-96x96.png b/subprojects/frontend/public/favicon-96x96.png new file mode 100644 index 00000000..353fe18a --- /dev/null +++ b/subprojects/frontend/public/favicon-96x96.png | |||
Binary files differ | |||
diff --git a/subprojects/frontend/public/favicon.png b/subprojects/frontend/public/favicon.png new file mode 100644 index 00000000..18e67636 --- /dev/null +++ b/subprojects/frontend/public/favicon.png | |||
Binary files differ | |||
diff --git a/subprojects/frontend/public/favicon.svg b/subprojects/frontend/public/favicon.svg new file mode 100644 index 00000000..b5d1d217 --- /dev/null +++ b/subprojects/frontend/public/favicon.svg | |||
@@ -0,0 +1 @@ | |||
<svg width="512" height="512" xmlns="http://www.w3.org/2000/svg"><style>@media(prefers-color-scheme:dark){#a{fill:#ebebff}#b{fill:#56b6c2}}</style><path d="M447.98 179.335c-139.95-9.583-301.272-50.91-384-147.336v46.117C98.45 129.623 209.442 178.137 294.243 199.1c-84.796 20.963-195.791 69.476-230.265 120.985v46.117c82.73-96.422 244.053-137.752 384.002-147.334z" fill="#35373e" id="a"/><path d="M447.98 296.729c-113.755 4.192-287.485 40.727-384 136.557v46.716c95.14-103.612 279.898-137.754 384-143.745z" fill="#038a99" id="b"/></svg> | |||
diff --git a/subprojects/frontend/public/icon-192x192.png b/subprojects/frontend/public/icon-192x192.png new file mode 100644 index 00000000..7c04fb37 --- /dev/null +++ b/subprojects/frontend/public/icon-192x192.png | |||
Binary files differ | |||
diff --git a/subprojects/frontend/public/icon-512x512.png b/subprojects/frontend/public/icon-512x512.png new file mode 100644 index 00000000..40c602c0 --- /dev/null +++ b/subprojects/frontend/public/icon-512x512.png | |||
Binary files differ | |||
diff --git a/subprojects/frontend/public/icon-any.svg b/subprojects/frontend/public/icon-any.svg new file mode 100644 index 00000000..3f6517b3 --- /dev/null +++ b/subprojects/frontend/public/icon-any.svg | |||
@@ -0,0 +1 @@ | |||
<svg width="512" height="512" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h512v512H0z" fill="#21252b"/><path d="M387.985 218.608c-96.215-6.674-207.125-35.454-264-102.609v32.118c23.698 35.87 100.005 69.657 158.306 84.257-58.297 14.599-134.606 48.385-158.307 84.258v32.117c56.876-67.153 167.786-95.936 264-102.609zm0 81.752c-78.207 2.92-197.646 28.364-264 95.103v32.535c65.409-72.159 192.43-95.936 264-100.108z" fill="#181a1f"/><path d="M387.985 202.606c-96.215-6.674-207.125-35.455-264-102.609v32.117c23.698 35.871 100.005 69.658 158.306 84.258-58.297 14.599-134.606 48.384-158.307 84.257v32.117c56.876-67.152 167.786-95.935 264-102.608z" fill="#ebebff"/><path d="M387.985 284.362c-78.207 2.92-197.646 28.364-264 95.103v32.534c65.409-72.158 192.43-95.936 264-100.108z" fill="#56b6c2"/></svg> \ No newline at end of file | |||
diff --git a/subprojects/frontend/public/mask-icon.svg b/subprojects/frontend/public/mask-icon.svg new file mode 100644 index 00000000..86052c6e --- /dev/null +++ b/subprojects/frontend/public/mask-icon.svg | |||
@@ -0,0 +1 @@ | |||
<svg width="512" height="512" xmlns="http://www.w3.org/2000/svg"><path d="M64 32v46.117c34.47 51.508 145.46 100.02 230.26 120.98C209.463 220.06 98.47 268.573 64 320.077v46.117c82.729-96.428 244.05-137.75 384-147.34v-39.531c-139.95-9.583-301.27-50.908-384-147.34zm384 264.73c-113.75 4.192-287.48 40.728-384 136.56v46.717c95.138-103.61 279.9-137.75 384-143.74v-39.529z"/></svg> | |||
diff --git a/subprojects/frontend/public/robots.txt b/subprojects/frontend/public/robots.txt new file mode 100644 index 00000000..c2a49f4f --- /dev/null +++ b/subprojects/frontend/public/robots.txt | |||
@@ -0,0 +1,2 @@ | |||
1 | User-agent: * | ||
2 | Allow: / | ||
diff --git a/subprojects/frontend/src/RegisterServiceWorker.tsx b/subprojects/frontend/src/RegisterServiceWorker.tsx new file mode 100644 index 00000000..c9b2e353 --- /dev/null +++ b/subprojects/frontend/src/RegisterServiceWorker.tsx | |||
@@ -0,0 +1,85 @@ | |||
1 | import Button from '@mui/material/Button'; | ||
2 | import { | ||
3 | type OptionsObject as SnackbarOptionsObject, | ||
4 | useSnackbar, | ||
5 | } from 'notistack'; | ||
6 | import React, { useEffect } from 'react'; | ||
7 | // eslint-disable-next-line import/no-unresolved -- Importing virtual module. | ||
8 | import { registerSW } from 'virtual:pwa-register'; | ||
9 | |||
10 | import { ContrastThemeProvider } from './theme/ThemeProvider'; | ||
11 | import getLogger from './utils/getLogger'; | ||
12 | |||
13 | const log = getLogger('RegisterServiceWorker'); | ||
14 | |||
15 | function UpdateSnackbarActions({ | ||
16 | closeCurrentSnackbar, | ||
17 | enqueueSnackbar, | ||
18 | updateSW, | ||
19 | }: { | ||
20 | closeCurrentSnackbar: () => void; | ||
21 | enqueueSnackbar: ( | ||
22 | message: string, | ||
23 | options?: SnackbarOptionsObject | undefined, | ||
24 | ) => void; | ||
25 | updateSW: (reloadPage: boolean) => Promise<void>; | ||
26 | }): JSX.Element { | ||
27 | return ( | ||
28 | <ContrastThemeProvider> | ||
29 | <Button | ||
30 | color="primary" | ||
31 | onClick={() => { | ||
32 | closeCurrentSnackbar(); | ||
33 | updateSW(true).catch((error) => { | ||
34 | log.error('Failed to update service worker', error); | ||
35 | enqueueSnackbar('Failed to download update', { | ||
36 | variant: 'error', | ||
37 | }); | ||
38 | }); | ||
39 | }} | ||
40 | > | ||
41 | Reload | ||
42 | </Button> | ||
43 | <Button color="inherit" onClick={closeCurrentSnackbar}> | ||
44 | Dismiss | ||
45 | </Button> | ||
46 | </ContrastThemeProvider> | ||
47 | ); | ||
48 | } | ||
49 | |||
50 | export default function RegisterServiceWorker(): null { | ||
51 | const { enqueueSnackbar, closeSnackbar } = useSnackbar(); | ||
52 | useEffect(() => { | ||
53 | if (import.meta.env.DEV) { | ||
54 | return; | ||
55 | } | ||
56 | if (!('serviceWorker' in navigator)) { | ||
57 | log.debug('No service worker support found'); | ||
58 | return; | ||
59 | } | ||
60 | const updateSW = registerSW({ | ||
61 | onNeedRefresh() { | ||
62 | const key = enqueueSnackbar('An update for Refinery is available', { | ||
63 | persist: true, | ||
64 | action: ( | ||
65 | <UpdateSnackbarActions | ||
66 | closeCurrentSnackbar={() => closeSnackbar(key)} | ||
67 | enqueueSnackbar={enqueueSnackbar} | ||
68 | updateSW={updateSW} | ||
69 | /> | ||
70 | ), | ||
71 | }); | ||
72 | }, | ||
73 | onOfflineReady() { | ||
74 | log.debug('Service worker is ready for offline use'); | ||
75 | }, | ||
76 | onRegistered() { | ||
77 | log.debug('Registered service worker'); | ||
78 | }, | ||
79 | onRegisterError(error) { | ||
80 | log.error('Failed to register service worker', error); | ||
81 | }, | ||
82 | }); | ||
83 | }, [enqueueSnackbar, closeSnackbar]); | ||
84 | return null; | ||
85 | } | ||
diff --git a/subprojects/frontend/src/index.tsx b/subprojects/frontend/src/index.tsx index 2176b277..b108df6d 100644 --- a/subprojects/frontend/src/index.tsx +++ b/subprojects/frontend/src/index.tsx | |||
@@ -1,6 +1,4 @@ | |||
1 | import CssBaseline from '@mui/material/CssBaseline'; | 1 | import CssBaseline from '@mui/material/CssBaseline'; |
2 | import React, { Suspense, lazy } from 'react'; | ||
3 | import { createRoot } from 'react-dom/client'; | ||
4 | import '@fontsource/jetbrains-mono/400.css'; | 2 | import '@fontsource/jetbrains-mono/400.css'; |
5 | import '@fontsource/jetbrains-mono/400-italic.css'; | 3 | import '@fontsource/jetbrains-mono/400-italic.css'; |
6 | import '@fontsource/jetbrains-mono/700.css'; | 4 | import '@fontsource/jetbrains-mono/700.css'; |
@@ -8,15 +6,15 @@ import '@fontsource/jetbrains-mono/700-italic.css'; | |||
8 | import '@fontsource/jetbrains-mono/variable.css'; | 6 | import '@fontsource/jetbrains-mono/variable.css'; |
9 | import '@fontsource/jetbrains-mono/variable-italic.css'; | 7 | import '@fontsource/jetbrains-mono/variable-italic.css'; |
10 | import '@fontsource/roboto/300.css'; | 8 | import '@fontsource/roboto/300.css'; |
11 | import '@fontsource/roboto/300-italic.css'; | ||
12 | import '@fontsource/roboto/400.css'; | 9 | import '@fontsource/roboto/400.css'; |
13 | import '@fontsource/roboto/400-italic.css'; | ||
14 | import '@fontsource/roboto/500.css'; | 10 | import '@fontsource/roboto/500.css'; |
15 | import '@fontsource/roboto/500-italic.css'; | ||
16 | import '@fontsource/roboto/700.css'; | 11 | import '@fontsource/roboto/700.css'; |
17 | import '@fontsource/roboto/700-italic.css'; | 12 | import { SnackbarProvider } from 'notistack'; |
13 | import React, { Suspense, lazy } from 'react'; | ||
14 | import { createRoot } from 'react-dom/client'; | ||
18 | 15 | ||
19 | import Loading from './Loading'; | 16 | import Loading from './Loading'; |
17 | import RegisterServiceWorker from './RegisterServiceWorker'; | ||
20 | import RootStore, { RootStoreProvider } from './RootStore'; | 18 | import RootStore, { RootStoreProvider } from './RootStore'; |
21 | import ThemeProvider from './theme/ThemeProvider'; | 19 | import ThemeProvider from './theme/ThemeProvider'; |
22 | import getLogger from './utils/getLogger'; | 20 | import getLogger from './utils/getLogger'; |
@@ -79,9 +77,12 @@ const app = ( | |||
79 | <RootStoreProvider rootStore={rootStore}> | 77 | <RootStoreProvider rootStore={rootStore}> |
80 | <ThemeProvider> | 78 | <ThemeProvider> |
81 | <CssBaseline enableColorScheme /> | 79 | <CssBaseline enableColorScheme /> |
82 | <Suspense fallback={<Loading />}> | 80 | <SnackbarProvider> |
83 | <App /> | 81 | <RegisterServiceWorker /> |
84 | </Suspense> | 82 | <Suspense fallback={<Loading />}> |
83 | <App /> | ||
84 | </Suspense> | ||
85 | </SnackbarProvider> | ||
85 | </ThemeProvider> | 86 | </ThemeProvider> |
86 | </RootStoreProvider> | 87 | </RootStoreProvider> |
87 | </React.StrictMode> | 88 | </React.StrictMode> |
diff --git a/subprojects/frontend/tsconfig.json b/subprojects/frontend/tsconfig.json index fcde9939..e8053768 100644 --- a/subprojects/frontend/tsconfig.json +++ b/subprojects/frontend/tsconfig.json | |||
@@ -4,7 +4,7 @@ | |||
4 | "jsx": "react", | 4 | "jsx": "react", |
5 | "noEmit": true, | 5 | "noEmit": true, |
6 | "lib": ["DOM", "DOM.Iterable", "ESNext"], | 6 | "lib": ["DOM", "DOM.Iterable", "ESNext"], |
7 | "types": ["vite/client"] | 7 | "types": ["vite/client", "vite-plugin-pwa/client"] |
8 | }, | 8 | }, |
9 | "include": [ | 9 | "include": [ |
10 | "src", | 10 | "src", |
diff --git a/subprojects/frontend/vite.config.ts b/subprojects/frontend/vite.config.ts index d97b0ac9..7c0c2605 100644 --- a/subprojects/frontend/vite.config.ts +++ b/subprojects/frontend/vite.config.ts | |||
@@ -6,11 +6,13 @@ import { lezer } from '@lezer/generator/rollup'; | |||
6 | import react from '@vitejs/plugin-react'; | 6 | import react from '@vitejs/plugin-react'; |
7 | import { defineConfig } from 'vite'; | 7 | import { defineConfig } from 'vite'; |
8 | import injectPreload from 'vite-plugin-inject-preload'; | 8 | import injectPreload from 'vite-plugin-inject-preload'; |
9 | import { VitePWA } from 'vite-plugin-pwa'; | ||
9 | 10 | ||
10 | const thisDir = path.dirname(fileURLToPath(import.meta.url)); | 11 | const thisDir = path.dirname(fileURLToPath(import.meta.url)); |
11 | 12 | ||
12 | const mode = process.env.MODE || 'development'; | 13 | const mode = process.env.MODE || 'development'; |
13 | const isDevelopment = mode === 'development'; | 14 | const isDevelopment = mode === 'development'; |
15 | process.env.NODE_ENV ??= mode; | ||
14 | 16 | ||
15 | function portNumberOrElse(envName: string, fallback: number): number { | 17 | function portNumberOrElse(envName: string, fallback: number): number { |
16 | const value = process.env[envName]; | 18 | const value = process.env[envName]; |
@@ -29,7 +31,7 @@ const { name: packageName, version: packageVersion } = JSON.parse( | |||
29 | readFileSync(path.join(thisDir, 'package.json'), 'utf8'), | 31 | readFileSync(path.join(thisDir, 'package.json'), 'utf8'), |
30 | ) as { name: string; version: string }; | 32 | ) as { name: string; version: string }; |
31 | process.env.VITE_PACKAGE_NAME ??= packageName; | 33 | process.env.VITE_PACKAGE_NAME ??= packageName; |
32 | process.env.VITE_PACKAGE_VERSIOn ??= packageVersion; | 34 | process.env.VITE_PACKAGE_VERSION ??= packageVersion; |
33 | 35 | ||
34 | export default defineConfig({ | 36 | export default defineConfig({ |
35 | logLevel: 'info', | 37 | logLevel: 'info', |
@@ -50,7 +52,7 @@ export default defineConfig({ | |||
50 | files: [ | 52 | files: [ |
51 | { | 53 | { |
52 | match: | 54 | match: |
53 | /(?:jetbrains-mono-latin-variable-wghtOnly-(?:italic|normal)|roboto-latin-(?:400|500)-normal).+\.woff2/, | 55 | /(?:jetbrains-mono-latin-variable-wghtOnly-(?:italic|normal)|roboto-latin-(?:400|500)-normal).+\.woff2$/, |
54 | attributes: { | 56 | attributes: { |
55 | type: 'font/woff2', | 57 | type: 'font/woff2', |
56 | as: 'font', | 58 | as: 'font', |
@@ -60,6 +62,56 @@ export default defineConfig({ | |||
60 | ], | 62 | ], |
61 | }), | 63 | }), |
62 | lezer(), | 64 | lezer(), |
65 | VitePWA({ | ||
66 | strategies: 'generateSW', | ||
67 | registerType: 'prompt', | ||
68 | injectRegister: null, | ||
69 | workbox: { | ||
70 | globPatterns: [ | ||
71 | '**/*.{css,html,js}', | ||
72 | 'roboto-latin-{300,400,500,700}-normal.*.woff2', | ||
73 | 'jetbrains-mono-latin-variable-wghtOnly-{normal,italic}.*.woff2', | ||
74 | ], | ||
75 | dontCacheBustURLsMatching: /\.(?:css|js|woff2?)$/, | ||
76 | navigateFallbackDenylist: [/^\/xtext-service/], | ||
77 | }, | ||
78 | includeAssets: ['apple-touch-icon.png', 'favicon.svg', 'mask-icon.svg'], | ||
79 | manifest: { | ||
80 | lang: 'en-US', | ||
81 | name: 'Refinery', | ||
82 | short_name: 'Refinery', | ||
83 | description: | ||
84 | 'An efficient graph sovler for generating well-formed models', | ||
85 | theme_color: '#21252b', | ||
86 | background_color: '#21252b', | ||
87 | icons: [ | ||
88 | { | ||
89 | src: 'icon-192x192.png', | ||
90 | sizes: '192x192', | ||
91 | type: 'image/png', | ||
92 | purpose: 'any maskable', | ||
93 | }, | ||
94 | { | ||
95 | src: 'icon-512x512.png', | ||
96 | sizes: '512x512', | ||
97 | type: 'image/png', | ||
98 | purpose: 'any maskable', | ||
99 | }, | ||
100 | { | ||
101 | src: 'icon-any.svg', | ||
102 | sizes: 'any', | ||
103 | type: 'image/svg+xml', | ||
104 | purpose: 'any maskable', | ||
105 | }, | ||
106 | { | ||
107 | src: 'mask-icon.svg', | ||
108 | sizes: 'any', | ||
109 | type: 'image/svg+xml', | ||
110 | purpose: 'monochrome', | ||
111 | }, | ||
112 | ], | ||
113 | }, | ||
114 | }), | ||
63 | ], | 115 | ], |
64 | base: '', | 116 | base: '', |
65 | define: { | 117 | define: { |
@@ -67,6 +119,9 @@ export default defineConfig({ | |||
67 | }, | 119 | }, |
68 | build: { | 120 | build: { |
69 | assetsDir: '.', | 121 | assetsDir: '.', |
122 | // If we don't control inlining manually, | ||
123 | // web fonts will randomly get inlined into the CSS, degrading performance. | ||
124 | assetsInlineLimit: 0, | ||
70 | outDir: path.join('build/vite', mode), | 125 | outDir: path.join('build/vite', mode), |
71 | emptyOutDir: true, | 126 | emptyOutDir: true, |
72 | sourcemap: isDevelopment, | 127 | sourcemap: isDevelopment, |