@studiotitta/studio-editori 0.1.0

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 (69) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +9 -0
  3. package/dist/komponentit/Editori.d.ts +1 -0
  4. package/dist/komponentit/Editori.js +29 -0
  5. package/dist/komponentit/Muokattava.d.ts +10 -0
  6. package/dist/komponentit/Muokattava.js +7 -0
  7. package/dist/komponentit/index.d.ts +2 -0
  8. package/dist/komponentit/index.js +5 -0
  9. package/dist/maarittely.d.ts +215 -0
  10. package/dist/maarittely.js +170 -0
  11. package/dist/palvelin/apurit.d.ts +26 -0
  12. package/dist/palvelin/apurit.js +70 -0
  13. package/dist/palvelin/asetukset.d.ts +26 -0
  14. package/dist/palvelin/asetukset.js +55 -0
  15. package/dist/palvelin/github/avain.d.ts +15 -0
  16. package/dist/palvelin/github/avain.js +121 -0
  17. package/dist/palvelin/github/tiedostot.d.ts +56 -0
  18. package/dist/palvelin/github/tiedostot.js +144 -0
  19. package/dist/palvelin/github/yhteys.d.ts +28 -0
  20. package/dist/palvelin/github/yhteys.js +89 -0
  21. package/dist/palvelin/index.d.ts +15 -0
  22. package/dist/palvelin/index.js +19 -0
  23. package/dist/palvelin/istunto.d.ts +34 -0
  24. package/dist/palvelin/istunto.js +86 -0
  25. package/dist/palvelin/kaannos.d.ts +12 -0
  26. package/dist/palvelin/kaannos.js +102 -0
  27. package/dist/palvelin/kaannosreitti.d.ts +9 -0
  28. package/dist/palvelin/kaannosreitti.js +42 -0
  29. package/dist/palvelin/kirjautuminen.d.ts +25 -0
  30. package/dist/palvelin/kirjautuminen.js +183 -0
  31. package/dist/palvelin/kuvat.d.ts +29 -0
  32. package/dist/palvelin/kuvat.js +130 -0
  33. package/dist/palvelin/kuvateksti.d.ts +15 -0
  34. package/dist/palvelin/kuvateksti.js +95 -0
  35. package/dist/palvelin/lue.d.ts +6 -0
  36. package/dist/palvelin/lue.js +41 -0
  37. package/dist/palvelin/posti.d.ts +9 -0
  38. package/dist/palvelin/posti.js +45 -0
  39. package/dist/palvelin/reitit.d.ts +10 -0
  40. package/dist/palvelin/reitit.js +71 -0
  41. package/dist/palvelin/tallennus.d.ts +18 -0
  42. package/dist/palvelin/tallennus.js +177 -0
  43. package/dist/palvelin/tila.d.ts +21 -0
  44. package/dist/palvelin/tila.js +116 -0
  45. package/dist/palvelin/tunnus.d.ts +30 -0
  46. package/dist/palvelin/tunnus.js +84 -0
  47. package/dist/palvelin/varasto.d.ts +18 -0
  48. package/dist/palvelin/varasto.js +87 -0
  49. package/dist/selain/EditorinPalkki.d.ts +1 -0
  50. package/dist/selain/EditorinPalkki.js +35 -0
  51. package/dist/selain/Muokkaustila.d.ts +3 -0
  52. package/dist/selain/Muokkaustila.js +646 -0
  53. package/dist/selain/PalkkiLataaja.d.ts +1 -0
  54. package/dist/selain/PalkkiLataaja.js +19 -0
  55. package/dist/selain/Paneeli.d.ts +44 -0
  56. package/dist/selain/Paneeli.js +259 -0
  57. package/dist/selain/index.d.ts +4 -0
  58. package/dist/selain/index.js +8 -0
  59. package/dist/selain/kieli.d.ts +10 -0
  60. package/dist/selain/kieli.js +14 -0
  61. package/dist/selain/kuva.d.ts +7 -0
  62. package/dist/selain/kuva.js +45 -0
  63. package/dist/selain/polku.d.ts +21 -0
  64. package/dist/selain/polku.js +108 -0
  65. package/dist/selain/tyypit.d.ts +22 -0
  66. package/dist/selain/tyypit.js +2 -0
  67. package/dist/tarkistus.d.ts +26 -0
  68. package/dist/tarkistus.js +324 -0
  69. package/package.json +59 -0
@@ -0,0 +1,87 @@
1
+ /* ==========================================================================
2
+ MIHIN SISÄLTÖ TALLENNETAAN
3
+ ==========================================================================
4
+ Tuotannossa sisältö on sivuston repossa GitHubissa: git on samalla
5
+ versiohistoria, ja tallennus käynnistää julkaisun.
6
+
7
+ Paikallisessa kehityksessä samaa ei kannata vaatia — kukaan ei halua
8
+ committia GitHubiin jokaisesta kokeilusta. Siksi kehityksessä sisältö
9
+ luetaan ja kirjoitetaan sivuston omiin tiedostoihin, jos GitHub-asetuksia
10
+ ei ole annettu.
11
+
12
+ Tiedostovarasto on **tarkoituksella estetty tuotannossa**: Vercelin
13
+ levy on väliaikainen, joten sinne tallennettu muutos katoaisi hiljaa.
14
+ ========================================================================== */
15
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
16
+ import path from "node:path";
17
+ import { onSallittuKuvapolku, onSallittuPolku } from "../maarittely.js";
18
+ import { lueTiedosto as lueGithubista, lueTiedostonTiedot, lueVersio, tallennaTiedostot, } from "./github/tiedostot.js";
19
+ import { lueGithubAsetukset } from "./github/yhteys.js";
20
+ function githubVarasto(asetukset) {
21
+ return {
22
+ nimi: `GitHub ${asetukset.repo}`,
23
+ lueVersio: () => lueVersio(asetukset),
24
+ lueTiedosto: (polku, versio) => lueGithubista(asetukset, polku, versio),
25
+ lueTiedostonVersio: async (polku, versio) => (await lueTiedostonTiedot(asetukset, polku, versio))?.versio ?? "",
26
+ tallenna: (tallennus) => tallennaTiedostot(asetukset, tallennus),
27
+ };
28
+ }
29
+ function paikallinenVarasto(juuri) {
30
+ const kokoPolku = (polku) => {
31
+ if (!onSallittuPolku(polku) && !onSallittuKuvapolku(polku)) {
32
+ throw new Error(`Polku "${polku}" ei ole sallittu.`);
33
+ }
34
+ return path.join(juuri, polku);
35
+ };
36
+ return {
37
+ nimi: `paikalliset tiedostot (${juuri})`,
38
+ async lueVersio() {
39
+ return "paikallinen";
40
+ },
41
+ async lueTiedosto(polku) {
42
+ try {
43
+ return await readFile(kokoPolku(polku), "utf8");
44
+ }
45
+ catch {
46
+ return undefined;
47
+ }
48
+ },
49
+ async lueTiedostonVersio() {
50
+ /* Kehityksessä muokkaajia on yksi, joten ristiriitoja ei synny. */
51
+ return "paikallinen";
52
+ },
53
+ async tallenna(tallennus) {
54
+ for (const tiedosto of tallennus.tiedostot) {
55
+ const kohde = kokoPolku(tiedosto.polku);
56
+ await mkdir(path.dirname(kohde), { recursive: true });
57
+ if (tiedosto.koodaus === "base64") {
58
+ await writeFile(kohde, Buffer.from(tiedosto.sisalto, "base64"));
59
+ }
60
+ else {
61
+ await writeFile(kohde, tiedosto.sisalto, "utf8");
62
+ }
63
+ }
64
+ return { versio: "paikallinen" };
65
+ },
66
+ };
67
+ }
68
+ let kerrottu = false;
69
+ /**
70
+ * Valitsee varaston: GitHub, jos asetukset ovat, muuten kehityksessä
71
+ * paikalliset tiedostot. Tuotannossa puuttuvat asetukset ovat virhe.
72
+ */
73
+ export function valitseVarasto(yliajot = {}) {
74
+ try {
75
+ return githubVarasto(lueGithubAsetukset(yliajot));
76
+ }
77
+ catch (virhe) {
78
+ if (process.env.NODE_ENV === "production")
79
+ throw virhe;
80
+ if (!kerrottu) {
81
+ kerrottu = true;
82
+ console.warn("[editori] GitHub-asetuksia ei ole, joten muutokset tallennetaan paikallisiin " +
83
+ "tiedostoihin. Tämä toimii vain kehityksessä.");
84
+ }
85
+ return paikallinenVarasto(process.cwd());
86
+ }
87
+ }
@@ -0,0 +1 @@
1
+ export declare function EditorinPalkki(): import("react").ReactPortal | null;
@@ -0,0 +1,35 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ /* ==========================================================================
4
+ PALKIN KOTI: SHADOW DOM
5
+ ==========================================================================
6
+ Editorin käyttöliittymä elää omassa varjossaan, jotta sivuston tyylit
7
+ eivät vaikuta siihen eikä se sivustoon. Tämä on edellytys sille, että
8
+ sama editori toimii jokaisessa asiakassivustossa sen omasta designista
9
+ riippumatta.
10
+
11
+ Tyylit annetaan `adoptedStyleSheets`-rajapinnalla eikä <style>-elementillä,
12
+ jotta sivuston tiukka Content-Security-Policy riittää sellaisenaan.
13
+ ========================================================================== */
14
+ import { useEffect, useState } from "react";
15
+ import { createPortal } from "react-dom";
16
+ import { Muokkaustila, PALKIN_TYYLIT } from "./Muokkaustila.js";
17
+ export function EditorinPalkki() {
18
+ const [juuri, setJuuri] = useState(null);
19
+ useEffect(() => {
20
+ const isanta = document.createElement("div");
21
+ isanta.setAttribute("data-editori-palkki", "");
22
+ document.body.appendChild(isanta);
23
+ const varjo = isanta.attachShadow({ mode: "open" });
24
+ if (typeof CSSStyleSheet !== "undefined" && "adoptedStyleSheets" in varjo) {
25
+ const arkki = new CSSStyleSheet();
26
+ arkki.replaceSync(PALKIN_TYYLIT);
27
+ varjo.adoptedStyleSheets = [arkki];
28
+ }
29
+ setJuuri(varjo);
30
+ return () => isanta.remove();
31
+ }, []);
32
+ if (!juuri)
33
+ return null;
34
+ return createPortal(_jsx(Muokkaustila, {}), juuri);
35
+ }
@@ -0,0 +1,3 @@
1
+ declare const PALKIN_TYYLIT = "\n :host { all: initial; }\n .palkki {\n position: fixed; inset: auto 1rem 1rem auto; z-index: 2147483000;\n display: flex; align-items: center; gap: .75rem;\n padding: .6rem .75rem .6rem 1rem; border-radius: .5rem;\n background: #1d1f1e; color: #fff;\n font: 500 .875rem/1.4 -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n box-shadow: 0 .5rem 1.5rem rgba(0,0,0,.25);\n max-width: calc(100vw - 2rem);\n }\n .tila { opacity: .75; font-weight: 400; }\n .tila[data-virhe=\"1\"] { color: #ffb4a2; opacity: 1; }\n button {\n font: inherit; padding: .45rem .8rem; border-radius: .35rem;\n border: 1px solid rgba(255,255,255,.25); background: transparent; color: inherit;\n cursor: pointer;\n }\n button.ensisijainen { background: #fff; color: #1d1f1e; border-color: #fff; }\n button:disabled { opacity: .5; cursor: default; }\n button:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }\n\n /* Sivupaneeli */\n .paneeli {\n position: fixed; inset: 0 0 0 auto; z-index: 2147482999;\n width: min(23rem, 100vw); overflow-y: auto;\n padding: 1.25rem 1.25rem 6rem;\n background: #fbfaf8; color: #1d1f1e;\n border-left: 1px solid rgba(0,0,0,.12);\n font: 400 .875rem/1.5 -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n box-shadow: -.5rem 0 1.5rem rgba(0,0,0,.08);\n }\n .paneeli h2 { margin: 0 0 .75rem; font-size: .8125rem; text-transform: uppercase; letter-spacing: .06em; opacity: .6; }\n .paneeli section + section { margin-top: 1.5rem; padding-top: 1.25rem; border-top: 1px solid rgba(0,0,0,.1); }\n .kentta { margin-bottom: 1rem; }\n .kentta label { display: flex; gap: .5rem; align-items: baseline; margin-bottom: .25rem; font-weight: 600; }\n .kieli { font-weight: 400; font-size: .75rem; padding: 0 .3rem; border-radius: .2rem; background: rgba(0,0,0,.08); text-transform: uppercase; }\n .kentta input[type=text], .kentta input[type=number], .kentta input[type=date],\n .kentta input[type=datetime-local], .kentta select, .kentta textarea {\n width: 100%; padding: .45rem .55rem; border: 1px solid rgba(0,0,0,.25);\n border-radius: .25rem; background: #fff; font: inherit; color: inherit;\n }\n .kentta textarea { resize: vertical; }\n .kytkin { display: flex; gap: .5rem; align-items: center; font-weight: 400; }\n .kielivalinta { display: grid; gap: .35rem; }\n .kaannos button { color: inherit; border-color: rgba(0,0,0,.25); }\n .ohje { margin: .25rem 0 0; font-size: .8125rem; opacity: .65; }\n .laskuri { margin: .3rem 0 0; font-size: .8125rem; font-weight: 600; }\n .virheet { padding: .75rem .9rem; border-radius: .3rem; background: #f6e8e3; color: #6d2b20; }\n .virheet h2 { margin: 0 0 .4rem; opacity: 1; color: inherit; }\n .virheet ul { margin: 0; padding-left: 1.1rem; display: grid; gap: .25rem; }\n .kuva img { display: block; width: 100%; height: auto; border-radius: .25rem; margin-bottom: .4rem; }\n .kuva input[type=text] { width: 100%; padding: .45rem .55rem; border: 1px solid rgba(0,0,0,.25); border-radius: .25rem; font: inherit; }\n /* Kuvan tekstikentt\u00E4 on oma lohkonsa: label on .kentta-tasolla flex,\n ja ilman t\u00E4t\u00E4 otsikko ja kentt\u00E4 asettuisivat vierekk\u00E4in. */\n .kentta label.alt, .kuva label.alt { display: block; font-weight: 600; margin-top: .5rem; }\n .alt input { margin-top: .25rem; width: 100%; }\n .huomio {\n margin: .4rem 0 0; padding: .5rem .6rem; border-radius: .25rem;\n background: #fdf3e7; color: #6b4a1f; font-size: .8125rem;\n }\n .huomio p { margin: 0 0 .4rem; }\n .huomio button { color: inherit; border-color: rgba(107,74,31,.35); padding: .3rem .6rem; }\n .lataus { display: inline-flex; margin: 0 0 .5rem; }\n .lataus span {\n padding: .45rem .8rem; border: 1px solid rgba(0,0,0,.25); border-radius: .35rem;\n cursor: pointer; font-weight: 600;\n }\n .lataus input[type=file] { position: absolute; width: 1px; height: 1px; opacity: 0; }\n .virheviesti { margin: 0 0 .5rem; color: #8c3b2e; font-size: .8125rem; }\n .tyhja { margin: 0; opacity: .6; }\n .kohteet { list-style: none; margin: 0 0 .75rem; padding: 0; display: grid; gap: .25rem; }\n .kohteet button {\n width: 100%; text-align: left; color: inherit; border-color: rgba(0,0,0,.15);\n display: flex; justify-content: space-between; gap: .5rem; align-items: center;\n }\n .kohteet button.valittu { background: #1d1f1e; color: #fff; border-color: #1d1f1e; }\n .merkki { font-size: .75rem; opacity: .7; white-space: nowrap; }\n /* Taitos n\u00E4ytt\u00E4\u00E4 painikkeelta ja nuoli osoittaa sinne, minne sis\u00E4lt\u00F6\n aukeaa: alas kiinni ollessa, yl\u00F6s auki ollessa. */\n .ryhma { margin: 0 0 1rem; padding: .75rem .8rem; border-radius: .3rem; background: rgba(0,0,0,.035); }\n .ryhma h3 { margin: 0 0 .5rem; font-size: .8125rem; text-transform: uppercase; letter-spacing: .05em; opacity: .65; }\n .ryhma .kentta:last-child { margin-bottom: 0; }\n .lisatiedot { margin: .25rem 0 1rem; border-top: 1px solid rgba(0,0,0,.1); }\n .lisatiedot summary {\n cursor: pointer; font-weight: 600; padding: .7rem 0; list-style: none;\n display: flex; align-items: center; gap: .5rem;\n }\n .lisatiedot summary::-webkit-details-marker { display: none; }\n .lisatiedot summary::after {\n content: \"\u25BE\"; font-size: 1.1rem; line-height: 1; margin-left: auto;\n }\n .lisatiedot[open] summary::after { content: \"\u25B4\"; }\n .lisatiedot summary:hover { text-decoration: underline; }\n .lisatiedot summary:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }\n .kaannos { margin: 0 0 1rem; padding: .6rem .7rem; border-radius: .25rem; background: #eef1ee; }\n .kaannos p { margin: 0 0 .5rem; }\n /* Kenttien nimet omalle rivilleen: lause pysyy luettavana ja nimet erottuvat. */\n .kaannos strong { display: block; margin-top: .15rem; }\n .kaannos button { color: inherit; border-color: rgba(0,0,0,.25); }\n .napit { display: flex; gap: .5rem; margin-bottom: 1rem; }\n .napit button { color: inherit; border-color: rgba(0,0,0,.25); }\n .napit button.vaarallinen { color: #8c3b2e; border-color: rgba(140,59,46,.4); }\n";
2
+ export declare function Muokkaustila(): import("react").JSX.Element | null;
3
+ export { PALKIN_TYYLIT };