@hkonda/loco-translate 1.0.4 → 1.0.6

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 (98) hide show
  1. package/README.md +17 -8
  2. package/assets/animated/ai-translating.svg +39 -0
  3. package/assets/animated/backup.svg +36 -0
  4. package/assets/animated/batch-progress.svg +52 -0
  5. package/assets/animated/connected.svg +33 -0
  6. package/assets/animated/disconnected.svg +29 -0
  7. package/assets/animated/discovering-phrases.svg +44 -0
  8. package/assets/animated/language-switch.svg +35 -0
  9. package/assets/animated/parrot-typing.svg +53 -0
  10. package/assets/animated/scanning-page.svg +43 -0
  11. package/assets/animated/syncing.svg +34 -0
  12. package/assets/animated/uploading.svg +32 -0
  13. package/assets/connecting.svg +43 -0
  14. package/assets/empty-state.svg +75 -0
  15. package/assets/error.svg +28 -0
  16. package/assets/icons/ai-sparkle.svg +13 -0
  17. package/assets/icons/calendar.svg +6 -0
  18. package/assets/icons/check.svg +3 -0
  19. package/assets/icons/copy.svg +4 -0
  20. package/assets/icons/export.svg +5 -0
  21. package/assets/icons/eye-off.svg +4 -0
  22. package/assets/icons/eye.svg +4 -0
  23. package/assets/icons/filter.svg +3 -0
  24. package/assets/icons/import.svg +5 -0
  25. package/assets/icons/plus.svg +4 -0
  26. package/assets/icons/refresh.svg +4 -0
  27. package/assets/icons/screenshot.svg +10 -0
  28. package/assets/icons/search.svg +4 -0
  29. package/assets/icons/settings.svg +4 -0
  30. package/assets/icons/translate.svg +5 -0
  31. package/assets/icons/trash.svg +6 -0
  32. package/assets/icons/warning.svg +5 -0
  33. package/assets/loading-spinner.svg +46 -0
  34. package/assets/loco_animated.svg +213 -0
  35. package/assets/loco_icon.svg +65 -0
  36. package/assets/loco_logo.svg +127 -0
  37. package/assets/success-check.svg +38 -0
  38. package/assets/translating-progress.svg +49 -0
  39. package/dist/assets/index-DyVMYkB3.css +1 -0
  40. package/dist/assets/index-P6vDH3Gg.js +64 -0
  41. package/dist/index.html +2 -2
  42. package/dist-server/app.d.ts.map +1 -1
  43. package/dist-server/app.js +39 -6
  44. package/dist-server/app.js.map +1 -1
  45. package/dist-server/routes/analytics.d.ts +5 -0
  46. package/dist-server/routes/analytics.d.ts.map +1 -0
  47. package/dist-server/routes/analytics.js +412 -0
  48. package/dist-server/routes/analytics.js.map +1 -0
  49. package/dist-server/routes/chrome-extension.d.ts.map +1 -1
  50. package/dist-server/routes/chrome-extension.js +95 -0
  51. package/dist-server/routes/chrome-extension.js.map +1 -1
  52. package/docs/build/.gitkeep +0 -0
  53. package/docs/build/404.html +16 -0
  54. package/docs/build/ai-translations/index.html +54 -0
  55. package/docs/build/api-reference/index.html +136 -0
  56. package/docs/build/assets/css/styles.d3f1f9bb.css +1 -0
  57. package/docs/build/assets/js/0e384e19.b48aab1c.js +1 -0
  58. package/docs/build/assets/js/11b43341.c57e94d9.js +1 -0
  59. package/docs/build/assets/js/17896441.4600feec.js +2 -0
  60. package/docs/build/assets/js/17896441.4600feec.js.LICENSE.txt +1 -0
  61. package/docs/build/assets/js/237.02169453.js +1 -0
  62. package/docs/build/assets/js/32670c8d.ceebaa1a.js +1 -0
  63. package/docs/build/assets/js/3b8c55ea.e08719c4.js +1 -0
  64. package/docs/build/assets/js/4b4bae81.5326d3c0.js +1 -0
  65. package/docs/build/assets/js/55.f44d6ffb.js +1 -0
  66. package/docs/build/assets/js/5e95c892.b17c16b4.js +1 -0
  67. package/docs/build/assets/js/673f2855.29507adf.js +1 -0
  68. package/docs/build/assets/js/72e14192.960bc879.js +1 -0
  69. package/docs/build/assets/js/85999b64.89b2983d.js +1 -0
  70. package/docs/build/assets/js/91fe4173.90773e87.js +1 -0
  71. package/docs/build/assets/js/964ae018.6d77944b.js +1 -0
  72. package/docs/build/assets/js/a03cb668.697c2cc5.js +1 -0
  73. package/docs/build/assets/js/a2564e04.dce49d26.js +1 -0
  74. package/docs/build/assets/js/a7bd4aaa.81de9950.js +1 -0
  75. package/docs/build/assets/js/a94703ab.cb0a0c60.js +1 -0
  76. package/docs/build/assets/js/aba21aa0.1b76a209.js +1 -0
  77. package/docs/build/assets/js/dcf88df3.2c91af30.js +1 -0
  78. package/docs/build/assets/js/edd278ef.7ace55ff.js +1 -0
  79. package/docs/build/assets/js/main.8f359375.js +2 -0
  80. package/docs/build/assets/js/main.8f359375.js.LICENSE.txt +51 -0
  81. package/docs/build/assets/js/runtime~main.e2462c61.js +1 -0
  82. package/docs/build/chrome-extension/index.html +44 -0
  83. package/docs/build/client-api/index.html +60 -0
  84. package/docs/build/file-mode/index.html +32 -0
  85. package/docs/build/img/loco_icon.svg +65 -0
  86. package/docs/build/index.html +32 -0
  87. package/docs/build/installation/index.html +37 -0
  88. package/docs/build/phrase-discovery/index.html +55 -0
  89. package/docs/build/quick-start/index.html +43 -0
  90. package/docs/build/self-hosting/index.html +39 -0
  91. package/docs/build/server-mode/index.html +36 -0
  92. package/docs/build/sitemap.xml +1 -0
  93. package/docs/build/translation-json/index.html +36 -0
  94. package/docs/build/variable-slots/index.html +48 -0
  95. package/landing/index.html +699 -0
  96. package/package.json +5 -2
  97. package/dist/assets/index-CGo6e-bA.js +0 -59
  98. package/dist/assets/index-DBcQDZ75.css +0 -1
package/README.md CHANGED
@@ -58,15 +58,24 @@ Copy the `<script>` tags from the terminal output and paste them into any HTML p
58
58
 
59
59
  ### Configuration
60
60
 
61
- Set these environment variables to customise Loco's behaviour:
61
+ Run `loco --help` to see all options:
62
62
 
63
- | Variable | Default | Description |
64
- |---|---|---|
65
- | `PORT` | `6101` | Server port |
66
- | `LOCO_DATA_DIR` | `.loco/` in cwd | Directory where `loco.db` is stored |
67
- | `BASE_PATH` | _(empty)_ | URL prefix for reverse-proxy deployments |
68
- | `BLUEHIVE_API_KEY` | _(none)_ | BlueHive key for AI translations |
69
- | `PUBLIC_URL` | _(auto)_ | Override the printed public URL |
63
+ ```
64
+ Options:
65
+ -p, --port <number> Port to listen on (default: 6101)
66
+ -d, --data-dir <path> Directory for loco.db (default: .loco/ in cwd)
67
+ -h, --help Show this help message
68
+ ```
69
+
70
+ Or set environment variables (in a `.env` file or your shell):
71
+
72
+ | Variable | Flag equivalent | Default | Description |
73
+ |---|---|---|---|
74
+ | `PORT` | `-p, --port` | `6101` | Server port |
75
+ | `LOCO_DATA_DIR` | `-d, --data-dir` | `.loco/` in cwd | Directory where `loco.db` is stored |
76
+ | `BASE_PATH` | — | _(empty)_ | URL prefix for reverse-proxy deployments |
77
+ | `BLUEHIVE_API_KEY` | — | _(none)_ | BlueHive key for AI translations |
78
+ | `PUBLIC_URL` | — | _(auto)_ | Override the printed public URL |
70
79
 
71
80
  Create a `.env` file in your working directory to set these:
72
81
 
@@ -0,0 +1,39 @@
1
+ <svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
2
+ <title>AI Translating</title>
3
+ <defs>
4
+ <style>
5
+ @keyframes textFade { 0%,20%{opacity:1} 40%,60%{opacity:0} 80%,100%{opacity:1} }
6
+ @keyframes textAppear { 0%,40%{opacity:0} 60%,100%{opacity:1} }
7
+ @keyframes sparkSpin { 0%{transform:rotate(0deg)} 100%{transform:rotate(360deg)} }
8
+ @keyframes sparkPulse { 0%,100%{opacity:0.3;r:2} 50%{opacity:1;r:3.5} }
9
+ #src-text { animation: textFade 3s ease-in-out infinite; }
10
+ #tgt-text { animation: textAppear 3s ease-in-out infinite; }
11
+ #spark-ring { animation: sparkSpin 3s linear infinite; transform-origin: 60px 60px; }
12
+ .sp { animation: sparkPulse 1.5s ease-in-out infinite; }
13
+ .sp2 { animation: sparkPulse 1.5s ease-in-out 0.3s infinite; }
14
+ .sp3 { animation: sparkPulse 1.5s ease-in-out 0.6s infinite; }
15
+ .sp4 { animation: sparkPulse 1.5s ease-in-out 0.9s infinite; }
16
+ </style>
17
+ </defs>
18
+
19
+ <!-- background circle -->
20
+ <circle cx="60" cy="60" r="50" fill="#1a1f2e"/>
21
+
22
+ <!-- rotating sparkle ring -->
23
+ <g id="spark-ring">
24
+ <circle class="sp" cx="60" cy="14" r="2.5" fill="#FFB833"/>
25
+ <circle class="sp2" cx="106" cy="60" r="2.5" fill="#2ECC88"/>
26
+ <circle class="sp3" cx="60" cy="106" r="2.5" fill="#3A8FE0"/>
27
+ <circle class="sp4" cx="14" cy="60" r="2.5" fill="#F07040"/>
28
+ </g>
29
+
30
+ <!-- source text fading out -->
31
+ <g id="src-text">
32
+ <text x="60" y="55" text-anchor="middle" font-family="system-ui,sans-serif" font-size="14" font-weight="600" fill="#E6F1FB">Hello</text>
33
+ </g>
34
+
35
+ <!-- target text fading in -->
36
+ <g id="tgt-text">
37
+ <text x="60" y="75" text-anchor="middle" font-family="system-ui,sans-serif" font-size="14" font-weight="600" fill="#2ECC88">Bonjour</text>
38
+ </g>
39
+ </svg>
@@ -0,0 +1,36 @@
1
+ <svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
2
+ <title>Backup in progress</title>
3
+ <defs>
4
+ <style>
5
+ @keyframes diskSpin { 0%{transform:rotate(0deg)} 100%{transform:rotate(360deg)} }
6
+ @keyframes fileFly1 { 0%{transform:translate(0,0);opacity:1} 100%{transform:translate(20px,-20px);opacity:0} }
7
+ @keyframes fileFly2 { 0%{transform:translate(0,0);opacity:1} 100%{transform:translate(20px,-15px);opacity:0} }
8
+ @keyframes fileFly3 { 0%{transform:translate(0,0);opacity:1} 100%{transform:translate(18px,-22px);opacity:0} }
9
+ @keyframes shieldPulse { 0%,100%{opacity:0.8;transform:scale(1)} 50%{opacity:1;transform:scale(1.05)} }
10
+ #disk-ring { animation: diskSpin 3s linear infinite; transform-origin: 72px 52px; }
11
+ .fly1 { animation: fileFly1 2s ease-out infinite; }
12
+ .fly2 { animation: fileFly2 2s ease-out 0.5s infinite; }
13
+ .fly3 { animation: fileFly3 2s ease-out 1s infinite; }
14
+ #shield { animation: shieldPulse 2s ease-in-out infinite; transform-origin: 72px 52px; }
15
+ </style>
16
+ </defs>
17
+
18
+ <!-- source database -->
19
+ <ellipse cx="42" cy="50" rx="20" ry="8" fill="#3A8FE0"/>
20
+ <rect x="22" y="50" width="40" height="20" fill="#3A8FE0"/>
21
+ <ellipse cx="42" cy="70" rx="20" ry="8" fill="#2a6ab8"/>
22
+ <ellipse cx="42" cy="60" rx="20" ry="8" fill="none" stroke="#2a6ab8" stroke-width="1"/>
23
+
24
+ <!-- flying files -->
25
+ <rect class="fly1" x="52" y="44" width="8" height="10" rx="1" fill="#2ECC88"/>
26
+ <rect class="fly2" x="50" y="52" width="8" height="10" rx="1" fill="#FFB833"/>
27
+ <rect class="fly3" x="54" y="48" width="8" height="10" rx="1" fill="#F07040"/>
28
+
29
+ <!-- target disk/shield -->
30
+ <g id="shield">
31
+ <path d="M72 35 L88 40 L88 58 Q88 70 72 75 Q56 70 56 58 L56 40 Z" fill="#1a1f2e" stroke="#2ECC88" stroke-width="2"/>
32
+ <polyline points="64,54 70,60 80,48" fill="none" stroke="#2ECC88" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
33
+ </g>
34
+
35
+ <text x="60" y="100" text-anchor="middle" font-family="system-ui,sans-serif" font-size="10" fill="#888">Backing up...</text>
36
+ </svg>
@@ -0,0 +1,52 @@
1
+ <svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
2
+ <title>Processing batch</title>
3
+ <defs>
4
+ <style>
5
+ @keyframes barGrow1 { 0%{width:0} 40%{width:44px} 100%{width:44px} }
6
+ @keyframes barGrow2 { 0%,20%{width:0} 60%{width:36px} 100%{width:36px} }
7
+ @keyframes barGrow3 { 0%,40%{width:0} 80%{width:40px} 100%{width:40px} }
8
+ @keyframes barGrow4 { 0%,60%{width:0} 100%{width:28px} }
9
+ @keyframes countUp { 0%{opacity:0} 10%{opacity:1} }
10
+ @keyframes checkPop { 0%{transform:scale(0);opacity:0} 100%{transform:scale(1);opacity:1} }
11
+ #bar1 { animation: barGrow1 3s ease-out infinite; }
12
+ #bar2 { animation: barGrow2 3s ease-out infinite; }
13
+ #bar3 { animation: barGrow3 3s ease-out infinite; }
14
+ #bar4 { animation: barGrow4 3s ease-out infinite; }
15
+ #c1 { animation: checkPop 0.3s ease 1.2s both; transform-origin: 88px 35px; }
16
+ #c2 { animation: checkPop 0.3s ease 1.8s both; transform-origin: 88px 50px; }
17
+ #c3 { animation: checkPop 0.3s ease 2.4s both; transform-origin: 88px 65px; }
18
+ #c4 { animation: checkPop 0.3s ease 3s both; transform-origin: 88px 80px; }
19
+ #pct { animation: countUp 3s ease infinite; }
20
+ </style>
21
+ </defs>
22
+
23
+ <!-- background -->
24
+ <rect x="10" y="15" width="100" height="90" rx="8" fill="#1a1f2e"/>
25
+
26
+ <!-- row labels -->
27
+ <text x="22" y="38" font-family="system-ui,sans-serif" font-size="9" fill="#888">fr</text>
28
+ <text x="22" y="53" font-family="system-ui,sans-serif" font-size="9" fill="#888">es</text>
29
+ <text x="22" y="68" font-family="system-ui,sans-serif" font-size="9" fill="#888">ja</text>
30
+ <text x="22" y="83" font-family="system-ui,sans-serif" font-size="9" fill="#888">de</text>
31
+
32
+ <!-- progress bars background -->
33
+ <rect x="36" y="30" width="44" height="8" rx="4" fill="#2a3040"/>
34
+ <rect x="36" y="45" width="44" height="8" rx="4" fill="#2a3040"/>
35
+ <rect x="36" y="60" width="44" height="8" rx="4" fill="#2a3040"/>
36
+ <rect x="36" y="75" width="44" height="8" rx="4" fill="#2a3040"/>
37
+
38
+ <!-- animated progress bars -->
39
+ <rect id="bar1" x="36" y="30" width="0" height="8" rx="4" fill="#2ECC88"/>
40
+ <rect id="bar2" x="36" y="45" width="0" height="8" rx="4" fill="#3A8FE0"/>
41
+ <rect id="bar3" x="36" y="60" width="0" height="8" rx="4" fill="#FFB833"/>
42
+ <rect id="bar4" x="36" y="75" width="0" height="8" rx="4" fill="#F07040"/>
43
+
44
+ <!-- checkmarks appearing -->
45
+ <g id="c1"><polyline points="84,35 87,38 92,32" fill="none" stroke="#2ECC88" stroke-width="2" stroke-linecap="round"/></g>
46
+ <g id="c2"><polyline points="84,50 87,53 92,47" fill="none" stroke="#3A8FE0" stroke-width="2" stroke-linecap="round"/></g>
47
+ <g id="c3"><polyline points="84,65 87,68 92,62" fill="none" stroke="#FFB833" stroke-width="2" stroke-linecap="round"/></g>
48
+ <g id="c4"><polyline points="84,80 87,83 92,77" fill="none" stroke="#F07040" stroke-width="2" stroke-linecap="round"/></g>
49
+
50
+ <!-- percentage counter -->
51
+ <text id="pct" x="60" y="104" text-anchor="middle" font-family="system-ui,sans-serif" font-size="10" font-weight="600" fill="#2ECC88">Translating...</text>
52
+ </svg>
@@ -0,0 +1,33 @@
1
+ <svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
2
+ <title>Connected</title>
3
+ <defs>
4
+ <style>
5
+ @keyframes pulseGlow {
6
+ 0%,100% { r: 8; opacity: 1; }
7
+ 50% { r: 12; opacity: 0.6; }
8
+ }
9
+ @keyframes signalWave1 { 0%{opacity:0;transform:scale(0.5)} 50%{opacity:0.8} 100%{opacity:0;transform:scale(1.5)} }
10
+ @keyframes signalWave2 { 0%{opacity:0;transform:scale(0.5)} 50%{opacity:0.6} 100%{opacity:0;transform:scale(2)} }
11
+ @keyframes checkBounce { 0%{transform:scale(0)} 60%{transform:scale(1.2)} 100%{transform:scale(1)} }
12
+ #green-dot { animation: pulseGlow 2s ease-in-out infinite; }
13
+ #wave1 { animation: signalWave1 2s ease-out infinite; transform-origin: 60px 55px; }
14
+ #wave2 { animation: signalWave2 2s ease-out 0.5s infinite; transform-origin: 60px 55px; }
15
+ #conn-check { animation: checkBounce 0.5s ease 0.3s both; transform-origin: 60px 80px; }
16
+ </style>
17
+ </defs>
18
+
19
+ <!-- signal waves -->
20
+ <circle id="wave1" cx="60" cy="55" r="20" fill="none" stroke="#2ECC88" stroke-width="2"/>
21
+ <circle id="wave2" cx="60" cy="55" r="20" fill="none" stroke="#2ECC88" stroke-width="1.5"/>
22
+
23
+ <!-- server icon -->
24
+ <rect x="45" y="35" width="30" height="40" rx="4" fill="#1a1f2e" stroke="#2ECC88" stroke-width="1.5"/>
25
+ <circle id="green-dot" cx="60" cy="48" r="8" fill="#2ECC88"/>
26
+ <rect x="52" y="58" width="16" height="3" rx="1.5" fill="#333"/>
27
+ <rect x="52" y="64" width="16" height="3" rx="1.5" fill="#333"/>
28
+
29
+ <!-- connection status -->
30
+ <g id="conn-check">
31
+ <text x="60" y="100" text-anchor="middle" font-family="system-ui,sans-serif" font-size="10" font-weight="600" fill="#2ECC88">Connected</text>
32
+ </g>
33
+ </svg>
@@ -0,0 +1,29 @@
1
+ <svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
2
+ <title>Disconnected</title>
3
+ <defs>
4
+ <style>
5
+ @keyframes blink { 0%,100%{opacity:1} 50%{opacity:0.3} }
6
+ @keyframes shake { 0%,100%{transform:translateX(0)} 25%{transform:translateX(-2px)} 75%{transform:translateX(2px)} }
7
+ #red-dot { animation: blink 1.5s ease-in-out infinite; }
8
+ #disc-icon { animation: shake 2s ease-in-out infinite; transform-origin: 60px 50px; }
9
+ </style>
10
+ </defs>
11
+
12
+ <g id="disc-icon">
13
+ <!-- server icon -->
14
+ <rect x="45" y="35" width="30" height="40" rx="4" fill="#1a1f2e" stroke="#E24B4A" stroke-width="1.5"/>
15
+ <circle id="red-dot" cx="60" cy="48" r="8" fill="#E24B4A"/>
16
+ <rect x="52" y="58" width="16" height="3" rx="1.5" fill="#333"/>
17
+ <rect x="52" y="64" width="16" height="3" rx="1.5" fill="#333"/>
18
+
19
+ <!-- broken connection lines -->
20
+ <line x1="35" y1="42" x2="25" y2="35" stroke="#E24B4A" stroke-width="2" stroke-linecap="round" stroke-dasharray="3 3"/>
21
+ <line x1="85" y1="42" x2="95" y2="35" stroke="#E24B4A" stroke-width="2" stroke-linecap="round" stroke-dasharray="3 3"/>
22
+
23
+ <!-- X overlay -->
24
+ <line x1="50" y1="42" x2="70" y2="58" stroke="#E24B4A" stroke-width="2.5" stroke-linecap="round" opacity="0.6"/>
25
+ <line x1="70" y1="42" x2="50" y2="58" stroke="#E24B4A" stroke-width="2.5" stroke-linecap="round" opacity="0.6"/>
26
+ </g>
27
+
28
+ <text x="60" y="100" text-anchor="middle" font-family="system-ui,sans-serif" font-size="10" font-weight="600" fill="#E24B4A">Disconnected</text>
29
+ </svg>
@@ -0,0 +1,44 @@
1
+ <svg width="160" height="120" viewBox="0 0 160 120" xmlns="http://www.w3.org/2000/svg">
2
+ <title>Discovering phrases</title>
3
+ <defs>
4
+ <style>
5
+ @keyframes highlight1 { 0%,100%{fill:#e0e0e0} 30%,70%{fill:#2ECC88} }
6
+ @keyframes highlight2 { 0%,100%{fill:#e0e0e0} 40%,80%{fill:#3A8FE0} }
7
+ @keyframes highlight3 { 0%,100%{fill:#e0e0e0} 50%,90%{fill:#FFB833} }
8
+ @keyframes cursorBlink { 0%,100%{opacity:1} 50%{opacity:0} }
9
+ @keyframes slideRight { 0%{transform:translateX(-5px);opacity:0} 50%{opacity:1} 100%{transform:translateX(5px);opacity:0} }
10
+ .hl1 { animation: highlight1 3s ease-in-out infinite; }
11
+ .hl2 { animation: highlight2 3s ease-in-out 0.5s infinite; }
12
+ .hl3 { animation: highlight3 3s ease-in-out 1s infinite; }
13
+ #cursor { animation: cursorBlink 0.8s step-end infinite; }
14
+ .tag { animation: slideRight 2s ease-in-out infinite; }
15
+ .tag2 { animation: slideRight 2s ease-in-out 0.7s infinite; }
16
+ .tag3 { animation: slideRight 2s ease-in-out 1.4s infinite; }
17
+ </style>
18
+ </defs>
19
+
20
+ <!-- browser window frame -->
21
+ <rect x="10" y="10" width="140" height="100" rx="6" fill="#fff" stroke="#ddd" stroke-width="1.5"/>
22
+ <rect x="10" y="10" width="140" height="18" rx="6" fill="#f5f5f5"/>
23
+ <circle cx="22" cy="19" r="3" fill="#E24B4A"/>
24
+ <circle cx="32" cy="19" r="3" fill="#FFB833"/>
25
+ <circle cx="42" cy="19" r="3" fill="#2ECC88"/>
26
+ <!-- url bar -->
27
+ <rect x="52" y="14" width="88" height="10" rx="3" fill="#eee"/>
28
+
29
+ <!-- page content with highlighting text -->
30
+ <rect class="hl1" x="20" y="36" width="50" height="6" rx="3"/>
31
+ <rect x="74" y="36" width="30" height="6" rx="3" fill="#e0e0e0"/>
32
+ <rect x="20" y="48" width="35" height="6" rx="3" fill="#e0e0e0"/>
33
+ <rect class="hl2" x="59" y="48" width="42" height="6" rx="3"/>
34
+ <rect x="20" y="60" width="60" height="6" rx="3" fill="#e0e0e0"/>
35
+ <rect class="hl3" x="20" y="72" width="38" height="6" rx="3"/>
36
+ <rect x="62" y="72" width="44" height="6" rx="3" fill="#e0e0e0"/>
37
+ <rect x="20" y="84" width="50" height="6" rx="3" fill="#e0e0e0"/>
38
+ <rect x="74" y="84" width="28" height="6" rx="3" fill="#e0e0e0"/>
39
+
40
+ <!-- floating tags being collected -->
41
+ <rect class="tag" x="115" y="40" width="20" height="10" rx="3" fill="#2ECC88" opacity="0.7"/>
42
+ <rect class="tag2" x="118" y="55" width="18" height="10" rx="3" fill="#3A8FE0" opacity="0.7"/>
43
+ <rect class="tag3" x="116" y="70" width="22" height="10" rx="3" fill="#FFB833" opacity="0.7"/>
44
+ </svg>
@@ -0,0 +1,35 @@
1
+ <svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
2
+ <title>Language switching</title>
3
+ <defs>
4
+ <style>
5
+ @keyframes flipOut { 0%{transform:scaleX(1);opacity:1} 50%{transform:scaleX(0);opacity:0} 100%{transform:scaleX(0);opacity:0} }
6
+ @keyframes flipIn { 0%{transform:scaleX(0);opacity:0} 50%{transform:scaleX(0);opacity:0} 100%{transform:scaleX(1);opacity:1} }
7
+ @keyframes arrowSpin { 0%{transform:rotate(0deg)} 100%{transform:rotate(360deg)} }
8
+ #lang-en { animation: flipOut 2.5s ease-in-out infinite alternate; transform-origin: 60px 50px; }
9
+ #lang-fr { animation: flipIn 2.5s ease-in-out infinite alternate; transform-origin: 60px 50px; }
10
+ #swap-arrows { animation: arrowSpin 2.5s ease-in-out infinite; transform-origin: 60px 50px; }
11
+ </style>
12
+ </defs>
13
+
14
+ <!-- swap arrows circle -->
15
+ <g id="swap-arrows">
16
+ <path d="M60 25 A25 25 0 0 1 85 50" fill="none" stroke="#3A8FE0" stroke-width="2.5" stroke-linecap="round"/>
17
+ <polygon points="85,45 85,55 78,50" fill="#3A8FE0"/>
18
+ <path d="M60 75 A25 25 0 0 1 35 50" fill="none" stroke="#2ECC88" stroke-width="2.5" stroke-linecap="round"/>
19
+ <polygon points="35,55 35,45 42,50" fill="#2ECC88"/>
20
+ </g>
21
+
22
+ <!-- english label -->
23
+ <g id="lang-en">
24
+ <rect x="40" y="40" width="40" height="20" rx="6" fill="#E6F1FB" stroke="#3A8FE0" stroke-width="1.2"/>
25
+ <text x="60" y="54" text-anchor="middle" font-family="system-ui,sans-serif" font-size="11" font-weight="600" fill="#185FA5">EN</text>
26
+ </g>
27
+
28
+ <!-- french label -->
29
+ <g id="lang-fr">
30
+ <rect x="40" y="40" width="40" height="20" rx="6" fill="#E1F5EE" stroke="#2ECC88" stroke-width="1.2"/>
31
+ <text x="60" y="54" text-anchor="middle" font-family="system-ui,sans-serif" font-size="11" font-weight="600" fill="#085041">FR</text>
32
+ </g>
33
+
34
+ <text x="60" y="100" text-anchor="middle" font-family="system-ui,sans-serif" font-size="9" fill="#888">Switching language</text>
35
+ </svg>
@@ -0,0 +1,53 @@
1
+ <svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
2
+ <title>Parrot typing / processing</title>
3
+ <defs>
4
+ <style>
5
+ @keyframes headBob { 0%,100%{transform:translateY(0) rotate(0deg)} 25%{transform:translateY(-2px) rotate(-3deg)} 75%{transform:translateY(-2px) rotate(3deg)} }
6
+ @keyframes typeDot1 { 0%,60%,100%{opacity:0.3;r:3} 30%{opacity:1;r:4} }
7
+ @keyframes typeDot2 { 0%,60%,100%{opacity:0.3;r:3} 30%{opacity:1;r:4} }
8
+ @keyframes typeDot3 { 0%,60%,100%{opacity:0.3;r:3} 30%{opacity:1;r:4} }
9
+ @keyframes eyeShift { 0%,100%{transform:translateX(0)} 50%{transform:translateX(1.5px)} }
10
+ #typing-parrot { animation: headBob 1.5s ease-in-out infinite; transform-origin: 60px 45px; }
11
+ #td1 { animation: typeDot1 1.4s ease-in-out infinite; }
12
+ #td2 { animation: typeDot2 1.4s ease-in-out 0.2s infinite; }
13
+ #td3 { animation: typeDot3 1.4s ease-in-out 0.4s infinite; }
14
+ .peye { animation: eyeShift 2s ease-in-out infinite; }
15
+ </style>
16
+ </defs>
17
+
18
+ <!-- parrot head -->
19
+ <g id="typing-parrot">
20
+ <!-- head -->
21
+ <circle cx="60" cy="45" r="24" fill="#2ECC88"/>
22
+ <!-- forehead -->
23
+ <ellipse cx="60" cy="33" rx="14" ry="8" fill="#FFB833"/>
24
+ <!-- eyes -->
25
+ <g class="peye">
26
+ <circle cx="52" cy="43" r="6.5" fill="white"/>
27
+ <circle cx="53" cy="44" r="4" fill="#2C2C2A"/>
28
+ <circle cx="54.5" cy="42" r="1.5" fill="white"/>
29
+ <circle cx="68" cy="43" r="6.5" fill="white"/>
30
+ <circle cx="67" cy="44" r="4" fill="#2C2C2A"/>
31
+ <circle cx="68.5" cy="42" r="1.5" fill="white"/>
32
+ </g>
33
+ <!-- beak -->
34
+ <path d="M56 52 Q60 48 64 52 Q64 57 60 59 Q56 57 56 52Z" fill="#E8A020"/>
35
+ <!-- cheeks -->
36
+ <ellipse cx="46" cy="48" rx="5" ry="3.5" fill="#F07040" opacity="0.6"/>
37
+ <ellipse cx="74" cy="48" rx="5" ry="3.5" fill="#F07040" opacity="0.6"/>
38
+ <!-- crest -->
39
+ <line x1="55" y1="23" x2="52" y2="16" stroke="#FFB833" stroke-width="2.5" stroke-linecap="round"/>
40
+ <line x1="60" y1="22" x2="60" y2="14" stroke="#7BC74A" stroke-width="2.5" stroke-linecap="round"/>
41
+ <line x1="65" y1="23" x2="68" y2="16" stroke="#F07040" stroke-width="2.5" stroke-linecap="round"/>
42
+ <circle cx="52" cy="15" r="3" fill="#FFB833"/>
43
+ <circle cx="60" cy="13" r="3" fill="#7BC74A"/>
44
+ <circle cx="68" cy="15" r="3" fill="#F07040"/>
45
+ </g>
46
+
47
+ <!-- speech bubble with typing dots -->
48
+ <rect x="35" y="78" width="50" height="24" rx="12" fill="#f0f0f0" stroke="#ddd" stroke-width="1"/>
49
+ <polygon points="55,78 50,72 62,78" fill="#f0f0f0" stroke="#ddd" stroke-width="1"/>
50
+ <circle id="td1" cx="48" cy="90" r="3" fill="#2ECC88"/>
51
+ <circle id="td2" cx="60" cy="90" r="3" fill="#3A8FE0"/>
52
+ <circle id="td3" cx="72" cy="90" r="3" fill="#FFB833"/>
53
+ </svg>
@@ -0,0 +1,43 @@
1
+ <svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
2
+ <title>Scanning page</title>
3
+ <defs>
4
+ <style>
5
+ @keyframes scanLine {
6
+ 0% { transform: translateY(-30px); opacity: 0; }
7
+ 10% { opacity: 1; }
8
+ 90% { opacity: 1; }
9
+ 100% { transform: translateY(30px); opacity: 0; }
10
+ }
11
+ @keyframes textHighlight {
12
+ 0%,30% { fill: #555; }
13
+ 50% { fill: #2ECC88; }
14
+ 70%,100% { fill: #555; }
15
+ }
16
+ @keyframes docPulse {
17
+ 0%,100% { transform: scale(1); }
18
+ 50% { transform: scale(1.02); }
19
+ }
20
+ #scan-line { animation: scanLine 2s ease-in-out infinite; }
21
+ #doc { animation: docPulse 2s ease-in-out infinite; transform-origin: 60px 60px; }
22
+ .txt1 { animation: textHighlight 2s ease-in-out infinite; }
23
+ .txt2 { animation: textHighlight 2s ease-in-out 0.3s infinite; }
24
+ .txt3 { animation: textHighlight 2s ease-in-out 0.6s infinite; }
25
+ .txt4 { animation: textHighlight 2s ease-in-out 0.9s infinite; }
26
+ </style>
27
+ </defs>
28
+
29
+ <!-- page document -->
30
+ <g id="doc">
31
+ <rect x="30" y="20" width="60" height="80" rx="4" fill="#f8f8f8" stroke="#ddd" stroke-width="1.5"/>
32
+ <!-- text lines -->
33
+ <rect class="txt1" x="38" y="32" width="44" height="4" rx="2" fill="#555"/>
34
+ <rect class="txt2" x="38" y="42" width="36" height="4" rx="2" fill="#555"/>
35
+ <rect class="txt3" x="38" y="52" width="40" height="4" rx="2" fill="#555"/>
36
+ <rect class="txt4" x="38" y="62" width="30" height="4" rx="2" fill="#555"/>
37
+ <rect x="38" y="72" width="38" height="4" rx="2" fill="#ddd"/>
38
+ <rect x="38" y="82" width="28" height="4" rx="2" fill="#ddd"/>
39
+ </g>
40
+
41
+ <!-- scanning beam -->
42
+ <rect id="scan-line" x="28" y="58" width="64" height="3" rx="1.5" fill="#2ECC88" opacity="0.7"/>
43
+ </svg>
@@ -0,0 +1,34 @@
1
+ <svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
2
+ <title>Syncing</title>
3
+ <defs>
4
+ <style>
5
+ @keyframes syncSpin { 0%{transform:rotate(0deg)} 100%{transform:rotate(360deg)} }
6
+ @keyframes arrowPulse { 0%,100%{opacity:0.6} 50%{opacity:1} }
7
+ @keyframes dotTravel {
8
+ 0%{transform:translate(0,0);opacity:0}
9
+ 10%{opacity:1}
10
+ 90%{opacity:1}
11
+ 100%{transform:translate(0,-30px);opacity:0}
12
+ }
13
+ #sync-arrows { animation: syncSpin 2s linear infinite; transform-origin: 60px 60px; }
14
+ .sync-dot1 { animation: dotTravel 1.5s ease-in-out infinite; }
15
+ .sync-dot2 { animation: dotTravel 1.5s ease-in-out 0.5s infinite; }
16
+ .sync-dot3 { animation: dotTravel 1.5s ease-in-out 1s infinite; }
17
+ </style>
18
+ </defs>
19
+
20
+ <circle cx="60" cy="60" r="50" fill="#1a1f2e"/>
21
+
22
+ <!-- spinning arrows -->
23
+ <g id="sync-arrows">
24
+ <path d="M60 25 A30 30 0 0 1 85 50" fill="none" stroke="#2ECC88" stroke-width="3.5" stroke-linecap="round"/>
25
+ <polygon points="87,44 87,56 79,50" fill="#2ECC88"/>
26
+ <path d="M60 95 A30 30 0 0 1 35 70" fill="none" stroke="#3A8FE0" stroke-width="3.5" stroke-linecap="round"/>
27
+ <polygon points="33,76 33,64 41,70" fill="#3A8FE0"/>
28
+ </g>
29
+
30
+ <!-- traveling dots -->
31
+ <circle class="sync-dot1" cx="48" cy="75" r="2.5" fill="#FFB833"/>
32
+ <circle class="sync-dot2" cx="60" cy="75" r="2.5" fill="#2ECC88"/>
33
+ <circle class="sync-dot3" cx="72" cy="75" r="2.5" fill="#F07040"/>
34
+ </svg>
@@ -0,0 +1,32 @@
1
+ <svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
2
+ <title>Uploading/Exporting</title>
3
+ <defs>
4
+ <style>
5
+ @keyframes arrowUp {
6
+ 0% { transform: translateY(8px); opacity: 0; }
7
+ 50% { opacity: 1; }
8
+ 100% { transform: translateY(-8px); opacity: 0; }
9
+ }
10
+ @keyframes cloudBob {
11
+ 0%,100% { transform: translateY(0); }
12
+ 50% { transform: translateY(-3px); }
13
+ }
14
+ #up-arrow1 { animation: arrowUp 1.5s ease-in-out infinite; }
15
+ #up-arrow2 { animation: arrowUp 1.5s ease-in-out 0.3s infinite; }
16
+ #up-arrow3 { animation: arrowUp 1.5s ease-in-out 0.6s infinite; }
17
+ #cloud { animation: cloudBob 3s ease-in-out infinite; transform-origin: 60px 40px; }
18
+ </style>
19
+ </defs>
20
+
21
+ <!-- cloud -->
22
+ <g id="cloud">
23
+ <path d="M35 55 Q35 40 48 38 Q50 28 62 28 Q75 28 77 40 Q88 40 88 52 Q88 60 80 60 L40 60 Q35 60 35 55Z" fill="#3A8FE0" opacity="0.9"/>
24
+ </g>
25
+
26
+ <!-- uploading arrows -->
27
+ <path id="up-arrow1" d="M50 85 L50 70 M45 75 L50 70 L55 75" fill="none" stroke="#2ECC88" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
28
+ <path id="up-arrow2" d="M60 85 L60 70 M55 75 L60 70 L65 75" fill="none" stroke="#FFB833" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
29
+ <path id="up-arrow3" d="M70 85 L70 70 M65 75 L70 70 L75 75" fill="none" stroke="#F07040" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
30
+
31
+ <text x="60" y="105" text-anchor="middle" font-family="system-ui,sans-serif" font-size="10" fill="#888">Exporting...</text>
32
+ </svg>
@@ -0,0 +1,43 @@
1
+ <svg width="80" height="80" viewBox="0 0 80 80" xmlns="http://www.w3.org/2000/svg">
2
+ <title>Connecting</title>
3
+ <defs>
4
+ <style>
5
+ @keyframes wave1 { 0% { r: 10; opacity: 0.8; } 100% { r: 34; opacity: 0; } }
6
+ @keyframes wave2 { 0% { r: 10; opacity: 0.8; } 100% { r: 34; opacity: 0; } }
7
+ @keyframes wave3 { 0% { r: 10; opacity: 0.8; } 100% { r: 34; opacity: 0; } }
8
+ @keyframes headBob {
9
+ 0%, 100% { transform: translateY(0); }
10
+ 50% { transform: translateY(-2px); }
11
+ }
12
+ #wave-1 { animation: wave1 2s ease-out infinite; }
13
+ #wave-2 { animation: wave2 2s ease-out 0.66s infinite; }
14
+ #wave-3 { animation: wave3 2s ease-out 1.33s infinite; }
15
+ #connect-parrot { animation: headBob 1.5s ease-in-out infinite; transform-origin: 40px 40px; }
16
+ </style>
17
+ </defs>
18
+
19
+ <!-- expanding waves -->
20
+ <circle id="wave-1" cx="40" cy="40" r="10" fill="none" stroke="#2ECC88" stroke-width="2"/>
21
+ <circle id="wave-2" cx="40" cy="40" r="10" fill="none" stroke="#3A8FE0" stroke-width="2"/>
22
+ <circle id="wave-3" cx="40" cy="40" r="10" fill="none" stroke="#FFB833" stroke-width="2"/>
23
+
24
+ <!-- parrot head center -->
25
+ <g id="connect-parrot">
26
+ <circle cx="40" cy="40" r="14" fill="#1a1f2e"/>
27
+ <circle cx="40" cy="39" r="9" fill="#2ECC88"/>
28
+ <!-- eyes -->
29
+ <circle cx="37" cy="38" r="2.2" fill="white"/>
30
+ <circle cx="37.4" cy="38.3" r="1.3" fill="#2C2C2A"/>
31
+ <circle cx="43" cy="38" r="2.2" fill="white"/>
32
+ <circle cx="42.6" cy="38.3" r="1.3" fill="#2C2C2A"/>
33
+ <!-- beak -->
34
+ <path d="M38.5 42 Q40 40.5 41.5 42 Q41.5 44 40 44.5 Q38.5 44 38.5 42Z" fill="#E8A020"/>
35
+ <!-- crest -->
36
+ <line x1="38" y1="32" x2="36.5" y2="28" stroke="#FFB833" stroke-width="1.3" stroke-linecap="round"/>
37
+ <line x1="40" y1="31" x2="40" y2="27" stroke="#7BC74A" stroke-width="1.3" stroke-linecap="round"/>
38
+ <line x1="42" y1="32" x2="43.5" y2="28" stroke="#F07040" stroke-width="1.3" stroke-linecap="round"/>
39
+ <circle cx="36.5" cy="27.5" r="1.3" fill="#FFB833"/>
40
+ <circle cx="40" cy="26.5" r="1.3" fill="#7BC74A"/>
41
+ <circle cx="43.5" cy="27.5" r="1.3" fill="#F07040"/>
42
+ </g>
43
+ </svg>
@@ -0,0 +1,75 @@
1
+ <svg width="200" height="160" viewBox="0 0 200 160" xmlns="http://www.w3.org/2000/svg">
2
+ <title>No translations yet</title>
3
+ <defs>
4
+ <style>
5
+ @keyframes parrotWait {
6
+ 0%, 100% { transform: rotate(-2deg); }
7
+ 50% { transform: rotate(2deg); }
8
+ }
9
+ @keyframes questionFloat {
10
+ 0%, 100% { transform: translateY(0); opacity: 0.7; }
11
+ 50% { transform: translateY(-5px); opacity: 1; }
12
+ }
13
+ @keyframes blinkSlow {
14
+ 0%, 90%, 100% { transform: scaleY(1); }
15
+ 94% { transform: scaleY(0.1); }
16
+ }
17
+ #empty-parrot { animation: parrotWait 3s ease-in-out infinite; transform-origin: 100px 90px; }
18
+ #q1 { animation: questionFloat 2.5s ease-in-out infinite; transform-origin: center; }
19
+ #q2 { animation: questionFloat 2.5s ease-in-out 0.8s infinite; transform-origin: center; }
20
+ #q3 { animation: questionFloat 2.5s ease-in-out 1.6s infinite; transform-origin: center; }
21
+ #empty-eyes { animation: blinkSlow 4s ease-in-out infinite; transform-origin: 100px 62px; }
22
+ </style>
23
+ </defs>
24
+
25
+ <!-- empty speech bubble outline (dashed) -->
26
+ <rect x="120" y="20" width="70" height="36" rx="10" fill="none" stroke="#ccc" stroke-width="1.5" stroke-dasharray="4 3"/>
27
+ <polygon points="130,56 125,65 140,56" fill="none" stroke="#ccc" stroke-width="1.5" stroke-dasharray="4 3"/>
28
+
29
+ <!-- question marks floating -->
30
+ <text id="q1" x="138" y="38" font-family="system-ui,sans-serif" font-size="12" fill="#bbb">?</text>
31
+ <text id="q2" x="152" y="42" font-family="system-ui,sans-serif" font-size="14" fill="#aaa">?</text>
32
+ <text id="q3" x="170" y="36" font-family="system-ui,sans-serif" font-size="10" fill="#ccc">?</text>
33
+
34
+ <!-- confused parrot -->
35
+ <g id="empty-parrot">
36
+ <!-- body -->
37
+ <ellipse cx="100" cy="100" rx="22" ry="30" fill="#2ECC88"/>
38
+ <ellipse cx="100" cy="106" rx="13" ry="20" fill="#D4F4B0"/>
39
+
40
+ <!-- wings -->
41
+ <path d="M78 94 Q68 86 70 108 Q76 116 82 113 Q78 104 78 94Z" fill="#3A8FE0"/>
42
+ <path d="M122 94 Q132 86 130 108 Q124 116 118 113 Q122 104 122 94Z" fill="#3A8FE0"/>
43
+
44
+ <!-- head -->
45
+ <circle cx="100" cy="68" r="20" fill="#2ECC88"/>
46
+ <ellipse cx="100" cy="58" rx="11" ry="7" fill="#FFB833"/>
47
+
48
+ <!-- eyes -->
49
+ <g id="empty-eyes">
50
+ <circle cx="93" cy="66" r="5.5" fill="white"/>
51
+ <circle cx="94" cy="67" r="3.5" fill="#2C2C2A"/>
52
+ <circle cx="95" cy="65" r="1.5" fill="white"/>
53
+ <circle cx="107" cy="66" r="5.5" fill="white"/>
54
+ <circle cx="106" cy="67" r="3.5" fill="#2C2C2A"/>
55
+ <circle cx="107" cy="65" r="1.5" fill="white"/>
56
+ </g>
57
+
58
+ <!-- beak (slightly tilted, confused) -->
59
+ <path d="M96 74 Q100 71 104 74 Q104 79 100 81 Q96 79 96 74Z" fill="#E8A020"/>
60
+
61
+ <!-- crest -->
62
+ <line x1="96" y1="50" x2="93" y2="44" stroke="#FFB833" stroke-width="2" stroke-linecap="round"/>
63
+ <line x1="100" y1="49" x2="100" y2="42" stroke="#7BC74A" stroke-width="2" stroke-linecap="round"/>
64
+ <line x1="104" y1="50" x2="107" y2="44" stroke="#F07040" stroke-width="2" stroke-linecap="round"/>
65
+ <circle cx="93" cy="43" r="2.5" fill="#FFB833"/>
66
+ <circle cx="100" cy="41" r="2.5" fill="#7BC74A"/>
67
+ <circle cx="107" cy="43" r="2.5" fill="#F07040"/>
68
+
69
+ <!-- perch -->
70
+ <rect x="80" y="128" width="40" height="4" rx="2" fill="#8B5E20"/>
71
+ </g>
72
+
73
+ <!-- label -->
74
+ <text x="100" y="152" text-anchor="middle" font-family="system-ui,sans-serif" font-size="11" fill="#999">No translations yet</text>
75
+ </svg>
@@ -0,0 +1,28 @@
1
+ <svg width="80" height="80" viewBox="0 0 80 80" xmlns="http://www.w3.org/2000/svg">
2
+ <title>Error</title>
3
+ <defs>
4
+ <style>
5
+ @keyframes shake {
6
+ 0%, 100% { transform: translateX(0); }
7
+ 10%, 50%, 90% { transform: translateX(-2px); }
8
+ 30%, 70% { transform: translateX(2px); }
9
+ }
10
+ @keyframes fadeIn {
11
+ 0% { opacity: 0; transform: scale(0.8); }
12
+ 100% { opacity: 1; transform: scale(1); }
13
+ }
14
+ #error-circle { animation: shake 0.6s ease-in-out infinite 1s; transform-origin: 40px 40px; }
15
+ #error-bg { animation: fadeIn 0.3s ease both; transform-origin: 40px 40px; }
16
+ </style>
17
+ </defs>
18
+
19
+ <g id="error-bg">
20
+ <circle cx="40" cy="40" r="30" fill="#E24B4A"/>
21
+ </g>
22
+
23
+ <g id="error-circle">
24
+ <!-- X mark -->
25
+ <line x1="28" y1="28" x2="52" y2="52" stroke="white" stroke-width="5" stroke-linecap="round"/>
26
+ <line x1="52" y1="28" x2="28" y2="52" stroke="white" stroke-width="5" stroke-linecap="round"/>
27
+ </g>
28
+ </svg>