mirror of
https://github.com/alexandrev/xslt-lab.git
synced 2026-09-18 19:43:16 +00:00
fix pagedev report
This commit is contained in:
+27
-11
@@ -23,18 +23,34 @@
|
||||
<link rel="canonical" href="https://xsltplayground.com/" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<script type="module" src="/env.js"></script>
|
||||
<script>
|
||||
if (window.env && window.env.VITE_ADSENSE_CLIENT) {
|
||||
const s = document.createElement('script');
|
||||
s.async = true;
|
||||
s.src =
|
||||
'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=' +
|
||||
window.env.VITE_ADSENSE_CLIENT;
|
||||
s.crossOrigin = 'anonymous';
|
||||
document.head.appendChild(s);
|
||||
<script>
|
||||
const loadAdsense = () => {
|
||||
const client = window.env && window.env.VITE_ADSENSE_CLIENT;
|
||||
if (!client) return;
|
||||
const s = document.createElement("script");
|
||||
s.async = true;
|
||||
s.src =
|
||||
"https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=" +
|
||||
client;
|
||||
s.crossOrigin = "anonymous";
|
||||
document.head.appendChild(s);
|
||||
};
|
||||
|
||||
const scheduleAdsense = () => {
|
||||
if ("requestIdleCallback" in window) {
|
||||
window.requestIdleCallback(loadAdsense, { timeout: 2500 });
|
||||
} else {
|
||||
window.setTimeout(loadAdsense, 1500);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
};
|
||||
|
||||
if (document.readyState === "complete") {
|
||||
scheduleAdsense();
|
||||
} else {
|
||||
window.addEventListener("load", scheduleAdsense, { once: true });
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.jsx"></script>
|
||||
|
||||
+154
-63
@@ -1,19 +1,7 @@
|
||||
import { useState, useEffect, useCallback, useRef, useMemo } from "react";
|
||||
import GA4React from "ga-4-react";
|
||||
import Editor from "@monaco-editor/react";
|
||||
import formatXML from "xml-formatter";
|
||||
import { initializeApp } from "firebase/app";
|
||||
import {
|
||||
getAuth,
|
||||
GoogleAuthProvider,
|
||||
signInWithPopup,
|
||||
signOut,
|
||||
} from "firebase/auth";
|
||||
import { useState, useEffect, useCallback, useRef, useMemo, lazy, Suspense } from "react";
|
||||
import logo from "./logo.svg";
|
||||
import TabsNav from "./components/TabsNav";
|
||||
import DataPipelineHeader from "./components/DataPipelineHeader";
|
||||
import FeedbackWidget from "./components/FeedbackWidget";
|
||||
import BuyMeACoffee from "./components/BuyMeACoffee";
|
||||
import Icon from "./components/Icon";
|
||||
import {
|
||||
parseErrorLines,
|
||||
@@ -26,6 +14,42 @@ import {
|
||||
|
||||
/* global __APP_VERSION__ */
|
||||
|
||||
const MonacoEditor = lazy(() => import("@monaco-editor/react"));
|
||||
const FeedbackWidget = lazy(() => import("./components/FeedbackWidget"));
|
||||
const BuyMeACoffee = lazy(() => import("./components/BuyMeACoffee"));
|
||||
|
||||
function runWhenIdle(callback, timeout = 2000) {
|
||||
if (typeof window === "undefined") {
|
||||
return () => {};
|
||||
}
|
||||
if ("requestIdleCallback" in window) {
|
||||
const id = window.requestIdleCallback(callback, { timeout });
|
||||
return () => window.cancelIdleCallback?.(id);
|
||||
}
|
||||
const id = window.setTimeout(callback, timeout);
|
||||
return () => window.clearTimeout(id);
|
||||
}
|
||||
|
||||
function Editor({ height, ...props }) {
|
||||
const fallbackStyle = height ? { height } : undefined;
|
||||
return (
|
||||
<Suspense
|
||||
fallback={
|
||||
<div
|
||||
className="editor-loading"
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
style={fallbackStyle}
|
||||
>
|
||||
Loading editor...
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<MonacoEditor height={height} {...props} />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
function debounce(fn, delay) {
|
||||
let t;
|
||||
return (...args) => {
|
||||
@@ -273,6 +297,7 @@ export default function App() {
|
||||
const [viewportWidth, setViewportWidth] = useState(() =>
|
||||
typeof window !== "undefined" ? window.innerWidth : 0,
|
||||
);
|
||||
const [widgetsReady, setWidgetsReady] = useState(false);
|
||||
const ethicalSlotRef = useRef(null);
|
||||
const isLocalhost =
|
||||
typeof window !== "undefined" &&
|
||||
@@ -291,12 +316,32 @@ export default function App() {
|
||||
const ethicalAdVariant = `${isCompactEthicalAd ? "compact" : "wide"}-${ethicalAdType}`;
|
||||
|
||||
const backendBase = (env.VITE_BACKEND_URL || "").replace(/\/$/, "");
|
||||
console.log("Using this URL as backendURL:", backendBase);
|
||||
|
||||
useEffect(() => {
|
||||
const ga4react = new GA4React(env.VITE_GA_ID);
|
||||
ga4react.initialize().catch(err => console.error(err));
|
||||
}, []);
|
||||
const gaId = env.VITE_GA_ID;
|
||||
if (!gaId) return;
|
||||
let cancelled = false;
|
||||
const cancelIdle = runWhenIdle(async () => {
|
||||
if (cancelled) return;
|
||||
try {
|
||||
const { default: GA4React } = await import("ga-4-react");
|
||||
if (cancelled) return;
|
||||
const ga4react = new GA4React(gaId);
|
||||
ga4react.initialize().catch((err) => console.error(err));
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}, 2500);
|
||||
return () => {
|
||||
cancelled = true;
|
||||
cancelIdle?.();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const cancelIdle = runWhenIdle(() => setWidgetsReady(true), 2000);
|
||||
return () => cancelIdle?.();
|
||||
}, []);
|
||||
|
||||
// Persist workspace on change
|
||||
useEffect(() => {
|
||||
@@ -597,16 +642,28 @@ export default function App() {
|
||||
|
||||
useEffect(() => {
|
||||
if (!goPro) return;
|
||||
try {
|
||||
const cfg = env.VITE_FIREBASE_CONFIG;
|
||||
if (cfg) {
|
||||
let cancelled = false;
|
||||
const cancelIdle = runWhenIdle(async () => {
|
||||
if (cancelled) return;
|
||||
try {
|
||||
const cfg = env.VITE_FIREBASE_CONFIG;
|
||||
if (!cfg) return;
|
||||
const [{ initializeApp }, { getAuth }] = await Promise.all([
|
||||
import("firebase/app"),
|
||||
import("firebase/auth"),
|
||||
]);
|
||||
if (cancelled) return;
|
||||
const app = initializeApp(JSON.parse(cfg));
|
||||
const a = getAuth(app);
|
||||
setAuth(a);
|
||||
a.onAuthStateChanged((u) => setUser(u));
|
||||
}
|
||||
} catch {}
|
||||
}, []);
|
||||
} catch {}
|
||||
}, 2500);
|
||||
return () => {
|
||||
cancelled = true;
|
||||
cancelIdle?.();
|
||||
};
|
||||
}, [goPro]);
|
||||
|
||||
useEffect(() => {
|
||||
tabsRef.current = tabs;
|
||||
@@ -1174,11 +1231,14 @@ export default function App() {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (adsenseClient && adsenseSlot && window.adsbygoogle) {
|
||||
if (!adsenseClient || !adsenseSlot) return;
|
||||
const cancelIdle = runWhenIdle(() => {
|
||||
if (!window.adsbygoogle) return;
|
||||
try {
|
||||
window.adsbygoogle.push({});
|
||||
} catch {}
|
||||
}
|
||||
}, 2000);
|
||||
return () => cancelIdle?.();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -1190,25 +1250,36 @@ export default function App() {
|
||||
setEthicalAdsReady(true);
|
||||
return;
|
||||
}
|
||||
const existing = document.querySelector("script[data-ethicalads]");
|
||||
const script = existing || document.createElement("script");
|
||||
if (!existing) {
|
||||
script.src = "https://media.ethicalads.io/media/client/ethicalads.min.js";
|
||||
script.async = true;
|
||||
script.dataset.ethicalads = "true";
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
const onLoad = () => setEthicalAdsReady(Boolean(window.ethicalads));
|
||||
const onError = () => setEthicalAdsReady(false);
|
||||
script.addEventListener("load", onLoad);
|
||||
script.addEventListener("error", onError);
|
||||
const fallback = window.setTimeout(() => {
|
||||
if (!window.ethicalads) setEthicalAdsReady(false);
|
||||
}, 3500);
|
||||
let cancelled = false;
|
||||
let script = null;
|
||||
let fallback = null;
|
||||
let onLoad = null;
|
||||
let onError = null;
|
||||
const loadEthicalAds = () => {
|
||||
if (cancelled) return;
|
||||
const existing = document.querySelector("script[data-ethicalads]");
|
||||
script = existing || document.createElement("script");
|
||||
if (!existing) {
|
||||
script.src = "https://media.ethicalads.io/media/client/ethicalads.min.js";
|
||||
script.async = true;
|
||||
script.dataset.ethicalads = "true";
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
onLoad = () => setEthicalAdsReady(Boolean(window.ethicalads));
|
||||
onError = () => setEthicalAdsReady(false);
|
||||
script.addEventListener("load", onLoad);
|
||||
script.addEventListener("error", onError);
|
||||
fallback = window.setTimeout(() => {
|
||||
if (!window.ethicalads) setEthicalAdsReady(false);
|
||||
}, 3500);
|
||||
};
|
||||
const cancelIdle = runWhenIdle(loadEthicalAds, 2000);
|
||||
return () => {
|
||||
script.removeEventListener("load", onLoad);
|
||||
script.removeEventListener("error", onError);
|
||||
window.clearTimeout(fallback);
|
||||
cancelled = true;
|
||||
cancelIdle?.();
|
||||
if (script && onLoad) script.removeEventListener("load", onLoad);
|
||||
if (script && onError) script.removeEventListener("error", onError);
|
||||
if (fallback) window.clearTimeout(fallback);
|
||||
};
|
||||
}, [ethicalAdsEnabled]);
|
||||
|
||||
@@ -1220,17 +1291,6 @@ export default function App() {
|
||||
} catch {}
|
||||
}, [ethicalAdsEnabled, ethicalAdsReady, ethicalAdVariant]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ethicalAdsPublisher) return;
|
||||
const existing = document.querySelector("script[data-ethicalads]");
|
||||
if (existing) return;
|
||||
const script = document.createElement("script");
|
||||
script.src = "https://media.ethicalads.io/media/client/ethicalads.min.js";
|
||||
script.async = true;
|
||||
script.dataset.ethicalads = "true";
|
||||
document.body.appendChild(script);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="app-container">
|
||||
{ethicalAdsEnabled && (
|
||||
@@ -1284,6 +1344,7 @@ export default function App() {
|
||||
accept="application/json,.json"
|
||||
className="file-input"
|
||||
onChange={handleWorkspaceImport}
|
||||
aria-label="Import workspace file"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1336,6 +1397,7 @@ export default function App() {
|
||||
placeholder="Parameter name"
|
||||
value={p.name}
|
||||
onChange={(e) => updateParam(i, "name", e.target.value)}
|
||||
aria-label="Parameter name"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
@@ -1371,13 +1433,18 @@ export default function App() {
|
||||
/>
|
||||
</div>
|
||||
<div className="param-footer">
|
||||
<label className="icon-button file-label param-upload">
|
||||
<label
|
||||
className="icon-button file-label param-upload"
|
||||
aria-label="Upload parameter value"
|
||||
title="Upload parameter value"
|
||||
>
|
||||
<Icon name="upload" />
|
||||
<input
|
||||
type="file"
|
||||
accept=".xml"
|
||||
className="file-input"
|
||||
onChange={(e) => loadFile(e, (t) => updateParam(i, "value", t))}
|
||||
aria-label="Upload parameter value file"
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
@@ -1425,6 +1492,7 @@ export default function App() {
|
||||
),
|
||||
)
|
||||
}
|
||||
aria-label="XSLT version"
|
||||
>
|
||||
<option value="1.0">XSLT 1.0</option>
|
||||
<option value="2.0">XSLT 2.0</option>
|
||||
@@ -1439,12 +1507,17 @@ export default function App() {
|
||||
<span className="trace-toggle-label">Enable Internal Variables</span>
|
||||
</label>
|
||||
<div className="right-actions">
|
||||
<label className="icon-button file-label">
|
||||
<label
|
||||
className="icon-button file-label"
|
||||
aria-label="Upload stylesheet"
|
||||
title="Upload stylesheet"
|
||||
>
|
||||
<Icon name="upload" />
|
||||
<input
|
||||
type="file"
|
||||
accept=".xsl,.xslt"
|
||||
className="file-input"
|
||||
aria-label="Upload stylesheet file"
|
||||
onChange={(e) =>
|
||||
loadFile(e, (t) =>
|
||||
setTabs((tabs) =>
|
||||
@@ -1460,6 +1533,8 @@ export default function App() {
|
||||
</label>
|
||||
<button
|
||||
className="icon-button"
|
||||
aria-label="Download stylesheet"
|
||||
title="Download stylesheet"
|
||||
onClick={() =>
|
||||
download(
|
||||
injectParamBlock(activeTab.xslt, activeTab.params),
|
||||
@@ -1527,6 +1602,7 @@ export default function App() {
|
||||
onClick={handleCopyAllTrace}
|
||||
type="button"
|
||||
disabled={!traceEntries.length && !traceText}
|
||||
aria-label="Copy all trace variables"
|
||||
>
|
||||
<Icon name="copy" />
|
||||
</button>
|
||||
@@ -1543,6 +1619,7 @@ export default function App() {
|
||||
}
|
||||
}}
|
||||
type="button"
|
||||
aria-label={showRawTrace ? "Hide raw trace output" : "Show raw trace output"}
|
||||
>
|
||||
<Icon name={showRawTrace ? "terminal-off" : "terminal"} />
|
||||
</button>
|
||||
@@ -1639,7 +1716,7 @@ export default function App() {
|
||||
}}
|
||||
>
|
||||
{error && !errorCollapsed && (
|
||||
<div className="error-box">
|
||||
<div className="error-box" role="alert" aria-live="assertive">
|
||||
<div className="error-box-header">
|
||||
<span>Errors</span>
|
||||
<div className="error-box-actions">
|
||||
@@ -1710,7 +1787,9 @@ export default function App() {
|
||||
{showResultPane && (
|
||||
<>
|
||||
{duration !== null && (
|
||||
<div className="success-box">Success in {duration} ms</div>
|
||||
<div className="success-box" role="status" aria-live="polite">
|
||||
Success in {duration} ms
|
||||
</div>
|
||||
)}
|
||||
<div className="result-actions">
|
||||
{canRenderHtml && (
|
||||
@@ -1742,9 +1821,10 @@ export default function App() {
|
||||
<button
|
||||
className="icon-button result-format-button"
|
||||
disabled={effectiveResultView !== "source"}
|
||||
onClick={() => {
|
||||
onClick={async () => {
|
||||
if (effectiveResultView !== "source") return;
|
||||
try {
|
||||
const { default: formatXML } = await import("xml-formatter");
|
||||
const formatted = formatXML(result);
|
||||
if (activeTab) {
|
||||
updateWorkspaceStatus(activeTab.id, (prev) => ({
|
||||
@@ -1776,6 +1856,7 @@ export default function App() {
|
||||
title="Rendered HTML output"
|
||||
srcDoc={result || "<!-- empty -->"}
|
||||
sandbox=""
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
@@ -1800,7 +1881,7 @@ export default function App() {
|
||||
</div>
|
||||
<div className="footer">
|
||||
<div className="footer-left">
|
||||
<img src={logo} alt="logo" className="logo" />
|
||||
<img src={logo} alt="XSLT Playground logo" className="logo" />
|
||||
<strong>xsltplayground.com</strong>
|
||||
<a
|
||||
className="news-link"
|
||||
@@ -1853,15 +1934,25 @@ export default function App() {
|
||||
}}
|
||||
>
|
||||
<div className="trace-hover-actions">
|
||||
<button type="button" className="icon-button" onClick={copyTraceHover} title="Copy value">
|
||||
<button
|
||||
type="button"
|
||||
className="icon-button"
|
||||
onClick={copyTraceHover}
|
||||
title="Copy value"
|
||||
aria-label="Copy value"
|
||||
>
|
||||
<Icon name="copy" />
|
||||
</button>
|
||||
</div>
|
||||
<pre>{traceHover.text}</pre>
|
||||
</div>
|
||||
)}
|
||||
<BuyMeACoffee />
|
||||
<FeedbackWidget />
|
||||
{widgetsReady && (
|
||||
<Suspense fallback={null}>
|
||||
<BuyMeACoffee />
|
||||
<FeedbackWidget />
|
||||
</Suspense>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,32 +9,51 @@ export default function BuyMeACoffee() {
|
||||
if (!containerRef.current) return;
|
||||
if (document.getElementById(SCRIPT_ID)) return;
|
||||
|
||||
const script = document.createElement("script");
|
||||
script.id = SCRIPT_ID;
|
||||
script.setAttribute("data-name", "BMC-Widget");
|
||||
script.src = "https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js";
|
||||
script.setAttribute("data-id", "alexandrev");
|
||||
script.setAttribute("data-description", "Support me on Buy me a coffee!");
|
||||
script.setAttribute(
|
||||
"data-message",
|
||||
"Thanks for using XSLT Playground. If it helped you, feel free to buy me a coffee ☕",
|
||||
);
|
||||
script.setAttribute("data-color", "#FFDD00");
|
||||
script.setAttribute("data-position", "Right");
|
||||
script.setAttribute("data-x_margin", "24");
|
||||
script.setAttribute("data-y_margin", "24");
|
||||
script.async = true;
|
||||
containerRef.current.appendChild(script);
|
||||
let cancelled = false;
|
||||
let script = null;
|
||||
let cancelIdle = null;
|
||||
let handleLoad = null;
|
||||
const loadWidget = () => {
|
||||
if (cancelled || !containerRef.current) return;
|
||||
script = document.createElement("script");
|
||||
script.id = SCRIPT_ID;
|
||||
script.setAttribute("data-name", "BMC-Widget");
|
||||
script.src = "https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js";
|
||||
script.setAttribute("data-id", "alexandrev");
|
||||
script.setAttribute("data-description", "Support me on Buy me a coffee!");
|
||||
script.setAttribute(
|
||||
"data-message",
|
||||
"Thanks for using XSLT Playground. If it helped you, feel free to buy me a coffee ☕",
|
||||
);
|
||||
script.setAttribute("data-color", "#FFDD00");
|
||||
script.setAttribute("data-position", "Right");
|
||||
script.setAttribute("data-x_margin", "24");
|
||||
script.setAttribute("data-y_margin", "24");
|
||||
script.async = true;
|
||||
containerRef.current.appendChild(script);
|
||||
|
||||
const handleLoad = () => {
|
||||
const evt = document.createEvent("Event");
|
||||
evt.initEvent("DOMContentLoaded", false, false);
|
||||
window.dispatchEvent(evt);
|
||||
handleLoad = () => {
|
||||
const evt = document.createEvent("Event");
|
||||
evt.initEvent("DOMContentLoaded", false, false);
|
||||
window.dispatchEvent(evt);
|
||||
};
|
||||
script.addEventListener("load", handleLoad);
|
||||
};
|
||||
|
||||
script.addEventListener("load", handleLoad);
|
||||
if ("requestIdleCallback" in window) {
|
||||
const idleId = window.requestIdleCallback(loadWidget, { timeout: 2500 });
|
||||
cancelIdle = () => window.cancelIdleCallback?.(idleId);
|
||||
} else {
|
||||
const timerId = window.setTimeout(loadWidget, 1800);
|
||||
cancelIdle = () => window.clearTimeout(timerId);
|
||||
}
|
||||
|
||||
return () => {
|
||||
script.removeEventListener("load", handleLoad);
|
||||
cancelled = true;
|
||||
cancelIdle?.();
|
||||
if (script && handleLoad) {
|
||||
script.removeEventListener("load", handleLoad);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -225,8 +225,6 @@ export default function FeedbackWidget() {
|
||||
<div
|
||||
className="feedback-header"
|
||||
onMouseDown={startDrag}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
<span>Feedback</span>
|
||||
<button
|
||||
|
||||
@@ -83,6 +83,7 @@ export default function TabsNav({
|
||||
placeholder={`Workspace ${index + 1}`}
|
||||
onChange={(e) => setDraftName(e.target.value)}
|
||||
onBlur={() => commitEditing(tab)}
|
||||
aria-label="Workspace name"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
|
||||
+50
-2
@@ -7,6 +7,12 @@ body,
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
a:focus-visible {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2px rgba(74, 133, 255, 0.35);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.news-link {
|
||||
color: #007acc;
|
||||
text-decoration: none;
|
||||
@@ -88,6 +94,12 @@ body,
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.tab-button:focus-visible {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2px rgba(74, 133, 255, 0.35);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.tab-name-input {
|
||||
max-width: 160px;
|
||||
padding: 0.35rem 0.6rem;
|
||||
@@ -114,7 +126,7 @@ body,
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
font-size: 0.85rem;
|
||||
color: #777;
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
.tab-close:hover {
|
||||
@@ -594,6 +606,18 @@ body,
|
||||
min-width: 0; /* allow editor to shrink */
|
||||
}
|
||||
|
||||
.editor-loading {
|
||||
height: 100%;
|
||||
min-height: 120px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #4b5563;
|
||||
background: #f0f4ff;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.trace-panel {
|
||||
width: 30%;
|
||||
background: #fff;
|
||||
@@ -919,7 +943,15 @@ body,
|
||||
}
|
||||
|
||||
.file-input {
|
||||
display: none;
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
border: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.file-label {
|
||||
@@ -927,6 +959,12 @@ body,
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.file-label:focus-within {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2px rgba(74, 133, 255, 0.25);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.result-actions {
|
||||
position: absolute;
|
||||
top: 0.35rem;
|
||||
@@ -1210,6 +1248,12 @@ body,
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .editor-loading {
|
||||
background: #111923;
|
||||
color: #c7d2e3;
|
||||
border: 1px solid #2b3645;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .param-footer .icon-button {
|
||||
border-color: #2b3645;
|
||||
background: #1a2330;
|
||||
@@ -1336,6 +1380,10 @@ body,
|
||||
box-shadow: 0 0 0 2px rgba(107, 182, 255, 0.25);
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .file-label:focus-within {
|
||||
box-shadow: 0 0 0 2px rgba(107, 182, 255, 0.35);
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .footer-theme-toggle.active {
|
||||
color: #6bb6ff;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user