pandorga 1.4.2 → 1.4.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/functions/api/studio/[[path]].js +26 -0
- data/functions/api/studio/_lib/github.js +129 -0
- data/lib/pandorga/version.rb +1 -1
- data/scripts/test/test-studio-api-contract.rb +12 -1
- data/studio/assets/index-Cd1mlY_H.css +1 -0
- data/studio/assets/{index-pL2vB_T0.js → index-Cf9OPjQU.js} +100 -100
- data/studio/index.html +2 -2
- data/studio-app/src/api/client.js +6 -0
- data/studio-app/src/main.js +230 -7
- data/studio-app/src/media/browser.js +13 -2
- data/studio-app/src/styles/studio.css +78 -4
- metadata +3 -3
- data/studio/assets/index-BQdNT4zp.css +0 -1
data/studio/index.html
CHANGED
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
rel="stylesheet"
|
|
19
19
|
href="https://cdn.jsdelivr.net/gh/lipis/flag-icons@7.2.3/css/flag-icons.min.css"
|
|
20
20
|
/>
|
|
21
|
-
<script type="module" crossorigin src="/studio/assets/index-
|
|
22
|
-
<link rel="stylesheet" crossorigin href="/studio/assets/index-
|
|
21
|
+
<script type="module" crossorigin src="/studio/assets/index-Cf9OPjQU.js"></script>
|
|
22
|
+
<link rel="stylesheet" crossorigin href="/studio/assets/index-Cd1mlY_H.css">
|
|
23
23
|
</head>
|
|
24
24
|
<body>
|
|
25
25
|
<div id="app"></div>
|
|
@@ -73,4 +73,10 @@ export const studioApi = {
|
|
|
73
73
|
method: "POST",
|
|
74
74
|
body: JSON.stringify(payload),
|
|
75
75
|
}),
|
|
76
|
+
/** Content-pipeline run for a commit SHA (production). */
|
|
77
|
+
pipelineStatus: (sha, workflow = null) => {
|
|
78
|
+
const params = new URLSearchParams({ sha: String(sha || "") });
|
|
79
|
+
if (workflow) params.set("workflow", String(workflow));
|
|
80
|
+
return api(`pipeline-status?${params.toString()}`);
|
|
81
|
+
},
|
|
76
82
|
};
|
data/studio-app/src/main.js
CHANGED
|
@@ -202,6 +202,19 @@ const state = {
|
|
|
202
202
|
navMenuOpen: false,
|
|
203
203
|
/** Theme menu (light / dark / system) in the icon toolbar. */
|
|
204
204
|
themeMenuOpen: false,
|
|
205
|
+
/**
|
|
206
|
+
* Content publish indicator (local Export animation or production Actions).
|
|
207
|
+
* state: idle | syncing | awaiting_run | running | ok | error | stalled | unconfigured
|
|
208
|
+
*/
|
|
209
|
+
pipeline: {
|
|
210
|
+
state: "idle",
|
|
211
|
+
sha: "",
|
|
212
|
+
runUrl: "",
|
|
213
|
+
message: "",
|
|
214
|
+
pollGen: 0,
|
|
215
|
+
},
|
|
216
|
+
/** Local Export button in flight. */
|
|
217
|
+
reexporting: false,
|
|
205
218
|
/** Per-collection list query (session memory). */
|
|
206
219
|
listQueryByCollection: Object.create(null),
|
|
207
220
|
/** Per-collection sort id (session + localStorage). */
|
|
@@ -432,6 +445,7 @@ function mediaOpts() {
|
|
|
432
445
|
captureError,
|
|
433
446
|
clearError,
|
|
434
447
|
goHome,
|
|
448
|
+
onCommitted: (commitSha) => armPipelineWatch(commitSha),
|
|
435
449
|
};
|
|
436
450
|
}
|
|
437
451
|
|
|
@@ -825,6 +839,192 @@ function isLocalDevHost() {
|
|
|
825
839
|
return host === "localhost" || host === "127.0.0.1" || host === "[::1]";
|
|
826
840
|
}
|
|
827
841
|
|
|
842
|
+
function sleep(ms) {
|
|
843
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
function pipelineChipMeta(pipelineState) {
|
|
847
|
+
switch (pipelineState) {
|
|
848
|
+
case "syncing":
|
|
849
|
+
case "running":
|
|
850
|
+
return {
|
|
851
|
+
label: "Exporting…",
|
|
852
|
+
icon: "progress_activity",
|
|
853
|
+
className: "pipeline-chip pipeline-running",
|
|
854
|
+
spinning: true,
|
|
855
|
+
title: "Content export is running",
|
|
856
|
+
};
|
|
857
|
+
case "awaiting_run":
|
|
858
|
+
return {
|
|
859
|
+
label: "Waiting…",
|
|
860
|
+
icon: "schedule",
|
|
861
|
+
className: "pipeline-chip pipeline-awaiting",
|
|
862
|
+
spinning: false,
|
|
863
|
+
title: "Waiting for the content pipeline run",
|
|
864
|
+
};
|
|
865
|
+
case "ok":
|
|
866
|
+
return {
|
|
867
|
+
label: "Live",
|
|
868
|
+
icon: "check_circle",
|
|
869
|
+
className: "pipeline-chip pipeline-ok",
|
|
870
|
+
spinning: false,
|
|
871
|
+
title: "Content pipeline succeeded for this commit",
|
|
872
|
+
};
|
|
873
|
+
case "error":
|
|
874
|
+
return {
|
|
875
|
+
label: "Failed",
|
|
876
|
+
icon: "error",
|
|
877
|
+
className: "pipeline-chip pipeline-error",
|
|
878
|
+
spinning: false,
|
|
879
|
+
title: state.pipeline.message || "Content pipeline failed",
|
|
880
|
+
};
|
|
881
|
+
case "stalled":
|
|
882
|
+
return {
|
|
883
|
+
label: "No run",
|
|
884
|
+
icon: "hourglass_disabled",
|
|
885
|
+
className: "pipeline-chip pipeline-stalled",
|
|
886
|
+
spinning: false,
|
|
887
|
+
title: "No pipeline run appeared for this commit yet",
|
|
888
|
+
};
|
|
889
|
+
case "unconfigured":
|
|
890
|
+
return {
|
|
891
|
+
label: "Pipeline",
|
|
892
|
+
icon: "cloud_off",
|
|
893
|
+
className: "pipeline-chip pipeline-idle",
|
|
894
|
+
spinning: false,
|
|
895
|
+
title: "STUDIO_CONTENT_WORKFLOW is not set on the Studio API",
|
|
896
|
+
};
|
|
897
|
+
default:
|
|
898
|
+
return {
|
|
899
|
+
label: "Pipeline",
|
|
900
|
+
icon: "cloud",
|
|
901
|
+
className: "pipeline-chip pipeline-idle",
|
|
902
|
+
spinning: false,
|
|
903
|
+
title: "Content pipeline status",
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
function renderPipelineChip() {
|
|
909
|
+
const meta = pipelineChipMeta(state.pipeline.state);
|
|
910
|
+
const runUrl = state.pipeline.runUrl;
|
|
911
|
+
const kids = [
|
|
912
|
+
el("span", {
|
|
913
|
+
className:
|
|
914
|
+
"material-symbols-outlined" + (meta.spinning ? " studio-icon-spin" : ""),
|
|
915
|
+
text: meta.icon,
|
|
916
|
+
"aria-hidden": "true",
|
|
917
|
+
}),
|
|
918
|
+
el("span", { className: "btn-label", text: meta.label }),
|
|
919
|
+
];
|
|
920
|
+
return el(
|
|
921
|
+
"button",
|
|
922
|
+
{
|
|
923
|
+
className: `btn btn-tool ${meta.className}`,
|
|
924
|
+
type: "button",
|
|
925
|
+
title: meta.title,
|
|
926
|
+
"aria-label": meta.label,
|
|
927
|
+
role: "status",
|
|
928
|
+
"data-studio-action": "pipeline-status",
|
|
929
|
+
disabled: !runUrl,
|
|
930
|
+
onClick: () => {
|
|
931
|
+
if (!runUrl) return;
|
|
932
|
+
try {
|
|
933
|
+
window.open(runUrl, "_blank", "noopener,noreferrer");
|
|
934
|
+
} catch {
|
|
935
|
+
/* ignore */
|
|
936
|
+
}
|
|
937
|
+
},
|
|
938
|
+
},
|
|
939
|
+
kids
|
|
940
|
+
);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* After a production Save, poll Actions for the content-pipeline run on this SHA.
|
|
945
|
+
*/
|
|
946
|
+
function armPipelineWatch(commitSha) {
|
|
947
|
+
const sha = String(commitSha || "").trim().toLowerCase();
|
|
948
|
+
if (!sha || isLocalDevHost()) return;
|
|
949
|
+
const gen = ++state.pipeline.pollGen;
|
|
950
|
+
state.pipeline.state = "awaiting_run";
|
|
951
|
+
state.pipeline.sha = sha;
|
|
952
|
+
state.pipeline.runUrl = "";
|
|
953
|
+
state.pipeline.message = "";
|
|
954
|
+
renderShell();
|
|
955
|
+
void pollPipelineStatus(gen, sha);
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
async function pollPipelineStatus(gen, sha) {
|
|
959
|
+
const started = Date.now();
|
|
960
|
+
const STALL_MS = 10 * 60 * 1000;
|
|
961
|
+
const MAX_MS = 30 * 60 * 1000;
|
|
962
|
+
let softFails = 0;
|
|
963
|
+
|
|
964
|
+
while (gen === state.pipeline.pollGen) {
|
|
965
|
+
const elapsed = Date.now() - started;
|
|
966
|
+
if (elapsed > MAX_MS) {
|
|
967
|
+
if (state.pipeline.state === "running" || state.pipeline.state === "awaiting_run") {
|
|
968
|
+
state.pipeline.state = "stalled";
|
|
969
|
+
state.pipeline.message = "Timed out waiting for the content pipeline.";
|
|
970
|
+
renderShell();
|
|
971
|
+
}
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
try {
|
|
976
|
+
const data = await studioApi.pipelineStatus(sha);
|
|
977
|
+
if (gen !== state.pipeline.pollGen) return;
|
|
978
|
+
softFails = 0;
|
|
979
|
+
state.pipeline.runUrl = data.run?.html_url || state.pipeline.runUrl || "";
|
|
980
|
+
state.pipeline.message = "";
|
|
981
|
+
|
|
982
|
+
if (data.state === "unconfigured") {
|
|
983
|
+
state.pipeline.state = "unconfigured";
|
|
984
|
+
renderShell();
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
if (data.state === "ok" || data.state === "error") {
|
|
988
|
+
state.pipeline.state = data.state;
|
|
989
|
+
if (data.state === "error") {
|
|
990
|
+
state.pipeline.message = "Content pipeline failed for this commit.";
|
|
991
|
+
}
|
|
992
|
+
renderShell();
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
if (data.state === "running") {
|
|
996
|
+
state.pipeline.state = "running";
|
|
997
|
+
} else if (data.state === "awaiting_run") {
|
|
998
|
+
if (elapsed > STALL_MS) {
|
|
999
|
+
state.pipeline.state = "stalled";
|
|
1000
|
+
renderShell();
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
state.pipeline.state = "awaiting_run";
|
|
1004
|
+
}
|
|
1005
|
+
renderShell();
|
|
1006
|
+
} catch (err) {
|
|
1007
|
+
if (gen !== state.pipeline.pollGen) return;
|
|
1008
|
+
softFails += 1;
|
|
1009
|
+
const code = err?.code || "";
|
|
1010
|
+
if (code === "actions_forbidden" || code === "github_unconfigured") {
|
|
1011
|
+
state.pipeline.state = "error";
|
|
1012
|
+
state.pipeline.message = String(err.message || err);
|
|
1013
|
+
renderShell();
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
if (softFails >= 5) {
|
|
1017
|
+
state.pipeline.state = "error";
|
|
1018
|
+
state.pipeline.message = String(err.message || err);
|
|
1019
|
+
renderShell();
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
await sleep(elapsed < 60_000 ? 2500 : 7000);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
|
|
828
1028
|
function collectionAllowsCreate(col = state.collection) {
|
|
829
1029
|
if (!col || col.type !== "collection") return false;
|
|
830
1030
|
return col.operations?.create !== false;
|
|
@@ -956,17 +1156,28 @@ function renderStudioToolbar({ brand = null, menuToggle = null } = {}) {
|
|
|
956
1156
|
);
|
|
957
1157
|
}
|
|
958
1158
|
if (isLocalDevHost()) {
|
|
1159
|
+
const exportBusy = state.reexporting || state.pipeline.state === "syncing";
|
|
959
1160
|
actions.push(
|
|
960
1161
|
toolbarActionButton({
|
|
961
|
-
className:
|
|
962
|
-
|
|
963
|
-
|
|
1162
|
+
className:
|
|
1163
|
+
"btn btn-tool btn-reexport" +
|
|
1164
|
+
(exportBusy ? " pipeline-running" : "") +
|
|
1165
|
+
(state.pipeline.state === "ok" && !exportBusy ? " pipeline-ok" : "") +
|
|
1166
|
+
(state.pipeline.state === "error" && !exportBusy ? " pipeline-error" : ""),
|
|
1167
|
+
title: exportBusy
|
|
1168
|
+
? "Exporting content JSON locally"
|
|
1169
|
+
: "Export content JSON locally and reload",
|
|
1170
|
+
ariaLabel: exportBusy ? "Exporting locally" : "Export locally",
|
|
964
1171
|
action: "reexport",
|
|
1172
|
+
disabled: exportBusy,
|
|
965
1173
|
onClick: () => reexportLocalContent(),
|
|
966
|
-
icon: "sync",
|
|
967
|
-
label: "Export",
|
|
1174
|
+
icon: exportBusy ? "progress_activity" : "sync",
|
|
1175
|
+
label: exportBusy ? "Exporting…" : "Export",
|
|
1176
|
+
spinning: exportBusy,
|
|
968
1177
|
})
|
|
969
1178
|
);
|
|
1179
|
+
} else if (state.pipeline.state !== "idle") {
|
|
1180
|
+
actions.push(renderPipelineChip());
|
|
970
1181
|
}
|
|
971
1182
|
|
|
972
1183
|
const kids = [
|
|
@@ -3782,6 +3993,10 @@ function discardChanges() {
|
|
|
3782
3993
|
}
|
|
3783
3994
|
|
|
3784
3995
|
async function reexportLocalContent() {
|
|
3996
|
+
if (state.reexporting) return;
|
|
3997
|
+
state.reexporting = true;
|
|
3998
|
+
state.pipeline.state = "syncing";
|
|
3999
|
+
state.pipeline.message = "";
|
|
3785
4000
|
state.status = "Reexporting…";
|
|
3786
4001
|
clearError();
|
|
3787
4002
|
renderShell();
|
|
@@ -3799,6 +4014,7 @@ async function reexportLocalContent() {
|
|
|
3799
4014
|
if (!res.ok || !data.ok) {
|
|
3800
4015
|
throw new Error((data && data.error) || `Export failed: ${res.status}`);
|
|
3801
4016
|
}
|
|
4017
|
+
state.pipeline.state = "ok";
|
|
3802
4018
|
state.status = "Reexported — reloading…";
|
|
3803
4019
|
renderShell();
|
|
3804
4020
|
setTimeout(() => {
|
|
@@ -3811,8 +4027,12 @@ async function reexportLocalContent() {
|
|
|
3811
4027
|
}
|
|
3812
4028
|
}, 200);
|
|
3813
4029
|
} catch (err) {
|
|
4030
|
+
state.pipeline.state = "error";
|
|
4031
|
+
state.pipeline.message = String(err.message || err);
|
|
3814
4032
|
captureError(err);
|
|
3815
4033
|
renderShell();
|
|
4034
|
+
} finally {
|
|
4035
|
+
state.reexporting = false;
|
|
3816
4036
|
}
|
|
3817
4037
|
}
|
|
3818
4038
|
|
|
@@ -3872,7 +4092,7 @@ async function createNewEntry() {
|
|
|
3872
4092
|
}
|
|
3873
4093
|
if (exists) throw new Error(`${path} already exists`);
|
|
3874
4094
|
|
|
3875
|
-
await studioApi.putFile({
|
|
4095
|
+
const created = await studioApi.putFile({
|
|
3876
4096
|
path,
|
|
3877
4097
|
content,
|
|
3878
4098
|
sha: null,
|
|
@@ -3880,6 +4100,7 @@ async function createNewEntry() {
|
|
|
3880
4100
|
});
|
|
3881
4101
|
invalidateTreeCache(col.name);
|
|
3882
4102
|
state.status = `Created ${path}`;
|
|
4103
|
+
armPipelineWatch(created?.commit);
|
|
3883
4104
|
await selectCollection(col);
|
|
3884
4105
|
await openFile(path);
|
|
3885
4106
|
} catch (err) {
|
|
@@ -3904,7 +4125,7 @@ async function deleteEntry(path, sha = null) {
|
|
|
3904
4125
|
const data = await studioApi.getFile(path);
|
|
3905
4126
|
fileSha = data.sha;
|
|
3906
4127
|
}
|
|
3907
|
-
await studioApi.deleteFile({
|
|
4128
|
+
const deleted = await studioApi.deleteFile({
|
|
3908
4129
|
path,
|
|
3909
4130
|
sha: fileSha,
|
|
3910
4131
|
message: `studio: delete ${path}`,
|
|
@@ -3920,6 +4141,7 @@ async function deleteEntry(path, sha = null) {
|
|
|
3920
4141
|
state.body = "";
|
|
3921
4142
|
}
|
|
3922
4143
|
state.status = `Deleted ${path}`;
|
|
4144
|
+
armPipelineWatch(deleted?.commit);
|
|
3923
4145
|
if (col) await selectCollection(col);
|
|
3924
4146
|
else renderShell();
|
|
3925
4147
|
} catch (err) {
|
|
@@ -3999,6 +4221,7 @@ async function saveCurrent() {
|
|
|
3999
4221
|
captureBaseline();
|
|
4000
4222
|
// List thumbs/titles may have changed — drop session tree for this collection.
|
|
4001
4223
|
if (col?.name) invalidateTreeCache(col.name);
|
|
4224
|
+
armPipelineWatch(result?.commit);
|
|
4002
4225
|
} catch (err) {
|
|
4003
4226
|
captureError(err);
|
|
4004
4227
|
} finally {
|
|
@@ -544,13 +544,16 @@ async function deleteMediaFile(item, opts) {
|
|
|
544
544
|
const data = await api.getFile(path);
|
|
545
545
|
sha = data.sha;
|
|
546
546
|
}
|
|
547
|
-
await api.deleteFile({
|
|
547
|
+
const deleted = await api.deleteFile({
|
|
548
548
|
path,
|
|
549
549
|
sha,
|
|
550
550
|
message: `studio: delete ${path}`,
|
|
551
551
|
});
|
|
552
552
|
state.mediaBusy = false;
|
|
553
553
|
state.status = `Deleted ${path}`;
|
|
554
|
+
if (typeof opts.onCommitted === "function") {
|
|
555
|
+
opts.onCommitted(deleted?.commit);
|
|
556
|
+
}
|
|
554
557
|
await openMediaDir(state.mediaPath, opts);
|
|
555
558
|
} catch (err) {
|
|
556
559
|
state.mediaBusy = false;
|
|
@@ -600,12 +603,15 @@ async function createFolder(opts) {
|
|
|
600
603
|
state.status = `Creating ${name}…`;
|
|
601
604
|
render();
|
|
602
605
|
try {
|
|
603
|
-
await api.createMediaFolder({
|
|
606
|
+
const created = await api.createMediaFolder({
|
|
604
607
|
path,
|
|
605
608
|
message: `studio: mkdir ${path}`,
|
|
606
609
|
});
|
|
607
610
|
state.mediaBusy = false;
|
|
608
611
|
state.status = `Created ${toPublicPath(path) || path}`;
|
|
612
|
+
if (typeof opts.onCommitted === "function") {
|
|
613
|
+
opts.onCommitted(created?.commit);
|
|
614
|
+
}
|
|
609
615
|
await openMediaDir(state.mediaPath, opts);
|
|
610
616
|
} catch (err) {
|
|
611
617
|
state.mediaBusy = false;
|
|
@@ -619,6 +625,7 @@ async function uploadFiles(files, opts) {
|
|
|
619
625
|
clearError();
|
|
620
626
|
const dir = state.mediaPath || MEDIA_ROOT;
|
|
621
627
|
let ok = 0;
|
|
628
|
+
let lastCommit = null;
|
|
622
629
|
state.mediaBusy = true;
|
|
623
630
|
|
|
624
631
|
for (const file of files) {
|
|
@@ -643,6 +650,7 @@ async function uploadFiles(files, opts) {
|
|
|
643
650
|
});
|
|
644
651
|
ok += 1;
|
|
645
652
|
state.status = `Uploaded ${result.public_path || toPublicPath(path)}`;
|
|
653
|
+
lastCommit = result?.commit || lastCommit;
|
|
646
654
|
} catch (err) {
|
|
647
655
|
captureError(err);
|
|
648
656
|
state.mediaBusy = false;
|
|
@@ -653,5 +661,8 @@ async function uploadFiles(files, opts) {
|
|
|
653
661
|
|
|
654
662
|
state.mediaBusy = false;
|
|
655
663
|
if (ok) state.status = ok === 1 ? state.status : `Uploaded ${ok} files`;
|
|
664
|
+
if (ok && lastCommit && typeof opts.onCommitted === "function") {
|
|
665
|
+
opts.onCommitted(lastCommit);
|
|
666
|
+
}
|
|
656
667
|
await openMediaDir(dir, opts);
|
|
657
668
|
}
|
|
@@ -719,6 +719,67 @@ button.studio-brand-home.studio-brand-toolbar[aria-current="page"] {
|
|
|
719
719
|
background: color-mix(in srgb, #746f30 45%, var(--panel));
|
|
720
720
|
}
|
|
721
721
|
|
|
722
|
+
/* Content-pipeline status chip (production) / Export sync colors (local). */
|
|
723
|
+
.pipeline-chip {
|
|
724
|
+
cursor: default;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
.pipeline-chip:not(:disabled) {
|
|
728
|
+
cursor: pointer;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
.pipeline-awaiting,
|
|
732
|
+
.btn-reexport.pipeline-running,
|
|
733
|
+
.pipeline-running {
|
|
734
|
+
color: #5c4b00;
|
|
735
|
+
border-color: color-mix(in srgb, #e0a100 55%, var(--outline-variant));
|
|
736
|
+
background: color-mix(in srgb, #f5c84c 50%, var(--background));
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
.pipeline-ok,
|
|
740
|
+
.btn-reexport.pipeline-ok {
|
|
741
|
+
color: #14532d;
|
|
742
|
+
border-color: color-mix(in srgb, #22c55e 50%, var(--outline-variant));
|
|
743
|
+
background: color-mix(in srgb, #86efac 45%, var(--background));
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
.pipeline-error,
|
|
747
|
+
.btn-reexport.pipeline-error,
|
|
748
|
+
.pipeline-stalled {
|
|
749
|
+
color: #7f1d1d;
|
|
750
|
+
border-color: color-mix(in srgb, #ef4444 50%, var(--outline-variant));
|
|
751
|
+
background: color-mix(in srgb, #fca5a5 40%, var(--background));
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
.pipeline-idle {
|
|
755
|
+
color: var(--on-surface-variant);
|
|
756
|
+
border-color: var(--outline-variant);
|
|
757
|
+
background: var(--surface-container);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
[data-theme="dark"] .pipeline-awaiting,
|
|
761
|
+
[data-theme="dark"] .pipeline-running,
|
|
762
|
+
[data-theme="dark"] .btn-reexport.pipeline-running {
|
|
763
|
+
color: #f5e6a3;
|
|
764
|
+
border-color: color-mix(in srgb, #e0a100 45%, var(--outline-variant));
|
|
765
|
+
background: color-mix(in srgb, #746f30 50%, var(--panel));
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
[data-theme="dark"] .pipeline-ok,
|
|
769
|
+
[data-theme="dark"] .btn-reexport.pipeline-ok {
|
|
770
|
+
color: #bbf7d0;
|
|
771
|
+
border-color: color-mix(in srgb, #22c55e 45%, var(--outline-variant));
|
|
772
|
+
background: color-mix(in srgb, #14532d 55%, var(--panel));
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
[data-theme="dark"] .pipeline-error,
|
|
776
|
+
[data-theme="dark"] .btn-reexport.pipeline-error,
|
|
777
|
+
[data-theme="dark"] .pipeline-stalled {
|
|
778
|
+
color: #fecaca;
|
|
779
|
+
border-color: color-mix(in srgb, #ef4444 45%, var(--outline-variant));
|
|
780
|
+
background: color-mix(in srgb, #7f1d1d 55%, var(--panel));
|
|
781
|
+
}
|
|
782
|
+
|
|
722
783
|
.studio-icon-bar .btn-icon {
|
|
723
784
|
width: var(--studio-list-control-height);
|
|
724
785
|
min-width: var(--studio-list-control-height);
|
|
@@ -1915,6 +1976,7 @@ button.studio-brand-home.studio-brand-toolbar[aria-current="page"] {
|
|
|
1915
1976
|
}
|
|
1916
1977
|
|
|
1917
1978
|
.editor-format-toolbar {
|
|
1979
|
+
--editor-tool-size: 2.35rem;
|
|
1918
1980
|
display: flex;
|
|
1919
1981
|
flex-wrap: wrap;
|
|
1920
1982
|
align-items: center;
|
|
@@ -1928,10 +1990,15 @@ button.studio-brand-home.studio-brand-toolbar[aria-current="page"] {
|
|
|
1928
1990
|
display: inline-flex;
|
|
1929
1991
|
align-items: center;
|
|
1930
1992
|
justify-content: center;
|
|
1931
|
-
|
|
1932
|
-
|
|
1993
|
+
box-sizing: border-box;
|
|
1994
|
+
width: var(--editor-tool-size);
|
|
1995
|
+
min-width: var(--editor-tool-size);
|
|
1996
|
+
max-width: var(--editor-tool-size);
|
|
1997
|
+
height: var(--editor-tool-size);
|
|
1998
|
+
min-height: var(--editor-tool-size);
|
|
1999
|
+
max-height: var(--editor-tool-size);
|
|
1933
2000
|
margin: 0;
|
|
1934
|
-
padding: 0
|
|
2001
|
+
padding: 0;
|
|
1935
2002
|
border: 0;
|
|
1936
2003
|
border-radius: 0;
|
|
1937
2004
|
background: transparent;
|
|
@@ -1940,6 +2007,8 @@ button.studio-brand-home.studio-brand-toolbar[aria-current="page"] {
|
|
|
1940
2007
|
font: inherit;
|
|
1941
2008
|
font-size: 0.82rem;
|
|
1942
2009
|
font-weight: 600;
|
|
2010
|
+
line-height: 1;
|
|
2011
|
+
overflow: hidden;
|
|
1943
2012
|
}
|
|
1944
2013
|
|
|
1945
2014
|
.editor-toolbar-btn:hover {
|
|
@@ -1960,10 +2029,15 @@ button.studio-brand-home.studio-brand-toolbar[aria-current="page"] {
|
|
|
1960
2029
|
}
|
|
1961
2030
|
|
|
1962
2031
|
.editor-toolbar-select {
|
|
2032
|
+
box-sizing: border-box;
|
|
2033
|
+
height: var(--editor-tool-size);
|
|
2034
|
+
min-height: var(--editor-tool-size);
|
|
2035
|
+
max-height: var(--editor-tool-size);
|
|
1963
2036
|
border: 1px solid color-mix(in srgb, var(--outline-variant) 70%, transparent);
|
|
1964
2037
|
background: var(--background);
|
|
1965
|
-
padding: 0
|
|
2038
|
+
padding: 0 0.4rem;
|
|
1966
2039
|
font-size: 0.82rem;
|
|
2040
|
+
line-height: 1;
|
|
1967
2041
|
max-width: 8.5rem;
|
|
1968
2042
|
}
|
|
1969
2043
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pandorga
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.4.
|
|
4
|
+
version: 1.4.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- The Pandorga contributors
|
|
@@ -449,8 +449,8 @@ files:
|
|
|
449
449
|
- studio-app/src/preview/render.js
|
|
450
450
|
- studio-app/src/styles/studio.css
|
|
451
451
|
- studio-app/vite.config.js
|
|
452
|
-
- studio/assets/index-
|
|
453
|
-
- studio/assets/index-
|
|
452
|
+
- studio/assets/index-Cd1mlY_H.css
|
|
453
|
+
- studio/assets/index-Cf9OPjQU.js
|
|
454
454
|
- studio/index.html
|
|
455
455
|
- studio/schema.yml
|
|
456
456
|
- templates/articles/README.md
|