diff --git a/apps/idegua/css/style.css b/apps/idegua/css/style.css index a4eeb2b..d81ec8d 100644 --- a/apps/idegua/css/style.css +++ b/apps/idegua/css/style.css @@ -86,6 +86,53 @@ body { white-space: nowrap; } +.file-name { + min-width: 0; + max-width: 260px; + padding: 2px 6px; + overflow: hidden; + border: 1px solid transparent; + border-radius: 6px; + color: var(--c-text-2); + font-family: var(--font-mono); + font-size: 14px; + font-weight: 500; + line-height: 1.4; + letter-spacing: normal; + text-transform: none; + text-overflow: ellipsis; + white-space: nowrap; + cursor: text; + outline: none; +} + +.file-name-control { + display: inline-flex; + align-items: center; + gap: 5px; + min-width: 0; + padding: 2px 7px; + background-color: var(--c-bg); + border: 1px solid var(--c-divider); + border-radius: 6px; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03); +} + +.file-name-control:focus-within { + border-color: rgba(60, 60, 67, 0.24); + box-shadow: 0 0 0 2px rgba(255, 75, 85, 0.12); +} + +.file-name:hover { + background-color: transparent; +} + +.file-name:focus { + background-color: var(--c-bg); + border-color: var(--c-divider); + color: var(--c-text-1); +} + .topbar-actions { display: flex; align-items: center; @@ -97,6 +144,7 @@ body { * alternativo cinza-suave. */ #runBtn, +#exportBtn, #demoSelector { height: 40px; border: 1px solid transparent; @@ -105,7 +153,7 @@ body { font-family: var(--font-sans); font-size: 14px; cursor: pointer; - transition: background-color 0.25s, color 0.25s; + transition: background-color 0.2s, border-color 0.2s, color 0.2s, box-shadow 0.2s; } #runBtn { @@ -114,6 +162,30 @@ body { font-weight: 600; } +#exportBtn { + background-color: var(--c-bg); + border-color: var(--c-divider); + color: var(--c-text-1); + font-weight: 600; +} + +#exportBtn:hover { + background-color: var(--c-gray-soft); + border-color: rgba(60, 60, 67, 0.2); +} + +#exportBtn:active { + background-color: var(--c-gray-soft-hover); +} + +#exportBtn:disabled { + background-color: #eeeeF1; + border-color: rgba(60, 60, 67, 0.08); + color: rgba(60, 60, 67, 0.42); + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.45); +} + + #runBtn:hover { background-color: var(--brand-2); } @@ -140,6 +212,7 @@ body { } #runBtn:focus-visible, +#exportBtn:focus-visible, #demoSelector:focus-visible { outline: 2px solid var(--brand-1); outline-offset: 2px; @@ -170,8 +243,13 @@ body { } .panel-head { + display: flex; + align-items: center; + justify-content: flex-start; + gap: 20px; + height: 36px; flex-shrink: 0; - padding: 10px 16px; + padding: 0 16px; background-color: var(--c-bg-alt); border-bottom: 1px solid var(--c-divider); font-size: 12px; @@ -181,6 +259,11 @@ body { color: var(--brand-1); } +.panel-head h2 { + font-size: inherit; + font-weight: inherit; +} + #editor { position: relative; flex: 1; @@ -297,6 +380,7 @@ body { } #runBtn, + #exportBtn, #demoSelector { height: 44px; } @@ -321,6 +405,11 @@ body { display: none; } + .file-name { + min-width: 0; + max-width: 140px; + } + #demoSelector { padding: 0 32px 0 14px; } diff --git a/apps/idegua/index.html b/apps/idegua/index.html index 0c85cc9..95a8325 100644 --- a/apps/idegua/index.html +++ b/apps/idegua/index.html @@ -28,12 +28,19 @@
+
-

Editor

+
+

Editor

+ + programa.egua + +
diff --git a/apps/idegua/js/index.js b/apps/idegua/js/index.js index 12f0f18..b913c5b 100644 --- a/apps/idegua/js/index.js +++ b/apps/idegua/js/index.js @@ -1,6 +1,8 @@ const outputDiv = document.getElementById("output"); const runButton = document.getElementById("runBtn"); const demoSelector = document.getElementById("demoSelector"); +const exportButton = document.getElementById('exportBtn'); +const fileName = document.getElementById("fileName"); String.prototype.capitalize = function() { return this.charAt(0).toUpperCase() + this.slice(1); @@ -34,13 +36,20 @@ const editor = new CodeFlask("#editor", { defaultTheme: false }); +function updateExportButton() { + exportButton.disabled = editor.getCode().trim().length === 0; +} + +editor.onUpdate(updateExportButton); + createAutocomplete(editor); clearOutput(); const demoKeys = Object.keys(demos); -function loadDemo(name) { +function loadDemo(name, updateName = true) { editor.updateCode(demos[name]); + if (updateName) fileName.textContent = `${name.toLowerCase()}.egua`; } demoKeys.forEach((demo, index) => { @@ -60,10 +69,13 @@ let queryCode = getQueryVariable("code"); if (queryCode !== undefined) { editor.updateCode(decodeURI(queryCode)); demoSelector.value = "custom"; + fileName.textContent = "programa.egua"; } else { - loadDemo(demoKeys[0]); + loadDemo(demoKeys[0], false); } +updateExportButton(); + const runCode = function() { const egua = new Egua.Egua(); @@ -80,3 +92,37 @@ runButton.addEventListener("click", function() { clearOutput(); runCode(); }); + + +function downloadCode() { + const code = editor.getCode(); + + if (code.trim().length === 0) return; + + const blob = new Blob([code], { type: "text/plain;charset=utf-8" }); + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + + link.href = url; + const name = fileName.textContent.trim() || "programa.egua"; + link.download = name.endsWith(".egua") ? name : `${name}.egua`; + document.body.appendChild(link); + link.click(); + link.remove(); + + setTimeout(() => URL.revokeObjectURL(url), 0); +} + +exportButton.addEventListener("click", downloadCode); + +fileName.addEventListener("blur", () => { + const name = fileName.textContent.trim(); + fileName.textContent = name || "programa.egua"; +}); + +fileName.addEventListener("keydown", (event) => { + if (event.key === "Enter") { + event.preventDefault(); + fileName.blur(); + } +});