diff --git a/package-lock.json b/package-lock.json index b4e819d156..74a494b85b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "phoenix", - "version": "5.5.3-0", + "version": "5.5.4-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "phoenix", - "version": "5.5.3-0", + "version": "5.5.4-0", "hasInstallScript": true, "dependencies": { "@bugsnag/js": "^7.18.0", @@ -1278,6 +1278,7 @@ "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", "dev": true, + "peer": true, "dependencies": { "@types/linkify-it": "^5", "@types/mdurl": "^2" @@ -1299,7 +1300,8 @@ "version": "17.0.8", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.8.tgz", "integrity": "sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", @@ -1368,6 +1370,7 @@ "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-6.1.0-beta.304.tgz", "integrity": "sha512-Wq9d4qFYslYQBIan+riXotdyurtREc6v+HWdAwV6Y2JSDI9eJ1dkWm/fzYb2rCGgGnM3baiYuSK4Z6OLNKLzDw==", "license": "MIT", + "peer": true, "workspaces": [ "addons/*" ] @@ -1390,6 +1393,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4452,6 +4456,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz", "integrity": "sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==", "dev": true, + "peer": true, "dependencies": { "@eslint/eslintrc": "^1.3.0", "@humanwhocodes/config-array": "^0.9.2", @@ -6151,6 +6156,7 @@ "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", "dev": true, + "peer": true, "dependencies": { "glob-watcher": "^5.0.3", "gulp-cli": "^2.2.0", @@ -10401,6 +10407,7 @@ "version": "3.2.5", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -12495,6 +12502,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -14200,6 +14208,7 @@ "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", "dev": true, + "peer": true, "requires": { "@types/linkify-it": "^5", "@types/mdurl": "^2" @@ -14221,7 +14230,8 @@ "version": "17.0.8", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.8.tgz", "integrity": "sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg==", - "dev": true + "dev": true, + "peer": true }, "@types/normalize-package-data": { "version": "2.4.4", @@ -14273,7 +14283,8 @@ "@xterm/xterm": { "version": "6.1.0-beta.304", "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-6.1.0-beta.304.tgz", - "integrity": "sha512-Wq9d4qFYslYQBIan+riXotdyurtREc6v+HWdAwV6Y2JSDI9eJ1dkWm/fzYb2rCGgGnM3baiYuSK4Z6OLNKLzDw==" + "integrity": "sha512-Wq9d4qFYslYQBIan+riXotdyurtREc6v+HWdAwV6Y2JSDI9eJ1dkWm/fzYb2rCGgGnM3baiYuSK4Z6OLNKLzDw==", + "peer": true }, "accepts": { "version": "1.3.7", @@ -14289,7 +14300,8 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true + "dev": true, + "peer": true }, "acorn-jsx": { "version": "5.3.2", @@ -16736,6 +16748,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz", "integrity": "sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==", "dev": true, + "peer": true, "requires": { "@eslint/eslintrc": "^1.3.0", "@humanwhocodes/config-array": "^0.9.2", @@ -18089,6 +18102,7 @@ "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", "dev": true, + "peer": true, "requires": { "glob-watcher": "^5.0.3", "gulp-cli": "^2.2.0", @@ -21545,7 +21559,8 @@ "prettier": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==" + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "peer": true }, "pretty-hrtime": { "version": "1.0.3", @@ -23226,7 +23241,8 @@ "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true + "dev": true, + "peer": true }, "typical": { "version": "7.3.0", diff --git a/phoenix-builder-mcp/package-lock.json b/phoenix-builder-mcp/package-lock.json index e19671cbc0..64359b6072 100644 --- a/phoenix-builder-mcp/package-lock.json +++ b/phoenix-builder-mcp/package-lock.json @@ -370,6 +370,7 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", + "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -574,6 +575,7 @@ "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.9.tgz", "integrity": "sha512-Eaw2YTGM6WOxA6CXbckaEvslr2Ne4NFsKrvc0v97JD5awbmeBLO5w9Ho9L9kmKonrwF9RJlW6BxT1PVv/agBHQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=16.9.0" } @@ -1144,6 +1146,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/src-mdviewer/package-lock.json b/src-mdviewer/package-lock.json index de8bd05c37..83a12e084e 100644 --- a/src-mdviewer/package-lock.json +++ b/src-mdviewer/package-lock.json @@ -1533,6 +1533,7 @@ "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.2.tgz", "integrity": "sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@chevrotain/cst-dts-gen": "11.1.2", "@chevrotain/gast": "11.1.2", @@ -1596,6 +1597,7 @@ "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10" } @@ -1996,6 +1998,7 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -2731,6 +2734,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -2913,7 +2917,8 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tapable": { "version": "2.3.0", @@ -3011,6 +3016,7 @@ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", diff --git a/src/JSUtils/ModalBuilder.js b/src/JSUtils/ModalBuilder.js new file mode 100644 index 0000000000..6f8f2b7b6b --- /dev/null +++ b/src/JSUtils/ModalBuilder.js @@ -0,0 +1,81 @@ +define(function() { + const Item = Object.freeze({ + modal: "modal", + modalContent: "content", + buttonsContainer: "buttons" + }); + + class ModalBuilder { + constructor(document) { + this.document = document; + this.modal = this.document.createElement('div'); + this.modalContent = this.document.createElement('div'); + this.buttonsContainer = this.document.createElement('div'); + } + + addStyle(item, style) { + switch (item) { + case Item.modal: + Object.assign(this.modal.style, style); + break; + case Item.modalContent: + Object.assign(this.modalContent.style, style); + break; + case Item.buttonsContainer: + Object.assign(this.buttonsContainer.style, style); + break; + + default: + break; + } + return this; + } + + addTitle(title, color) { + this.title = this.document.createElement('h2'); + this.title.textContent = title; + this.title.style.color = color; + return this; + } + + addMessage(message) { + this.modalMessage = document.createElement('p'); + message.split('\n').forEach((part, index, array) => { + this.modalMessage.appendChild(document.createTextNode(part)); + if (index < array.length - 1) { // Don't add a break on the last element + this.modalMessage.appendChild(document.createElement('br')); + } + }); + return this; + } + + addButton(title) { + const button = this.document.createElement('button'); + button.textContent = title; + this.buttonsContainer.appendChild(button); + return button; + } + + addButton(title, style) { + const button = this.addButton(title); + Object.assign(button.style, style); + return button; + } + + addButton(title, style, onclick) { + const button = this.addButton(title, style); + button.onclick = onclick; + return button; + } + + build() { + this.modalContent.appendChild(this.title); + this.modalContent.appendChild(this.message); + this.modalContent.appendChild(this.buttonsContainer); + this.modal.appendChild(this.modalContent); + return this.modal; + } + } + + return ModalBuilder; +}); diff --git a/src/JSUtils/SelectorStrategy.js b/src/JSUtils/SelectorStrategy.js new file mode 100644 index 0000000000..59a17aeb45 --- /dev/null +++ b/src/JSUtils/SelectorStrategy.js @@ -0,0 +1,70 @@ +define(function (require) { + const Strings = require('strings'); + const HTMLUtils = require('language/HTMLUtils'); + + const strategies = []; + + const TagSelectorStrategy = { + isMatch: (tokenType) => + tokenType === HTMLUtils.TAG_NAME || tokenType === HTMLUtils.CLOSING_TAG, + + resolve: (tagInfo) => ({ + selectorName: tagInfo.tagName, + reason: null + }) + }; + + const ClassSelectorStrategy = { + isMatch: (tokenType, attrName) => + (tokenType === HTMLUtils.ATTR_NAME || tokenType === HTMLUtils.ATTR_VALUE) && attrName === "class", + + resolve: (tagInfo) => { + var attributeValue = tagInfo.attr.value; + if (!/\S/.test(attributeValue)) { + return { selectorName: "", reason: Strings.ERROR_CSSQUICKEDIT_CLASSNOTFOUND }; + } + + var startIndex = attributeValue.substr(0, tagInfo.position.offset).lastIndexOf(" "); + var endIndex = attributeValue.indexOf(" ", tagInfo.position.offset); + let selectorName = "." + + attributeValue.substring( + startIndex === -1 ? 0 : startIndex + 1, + endIndex === -1 ? attributeValue.length : endIndex + ); + + if (selectorName === ".") { + return { selectorName: "", reason: Strings.ERROR_CSSQUICKEDIT_BETWEENCLASSES }; + } + return { selectorName, reason: null }; + } + }; + const IdSelectorStrategy = { + isMatch: (tokenType, attrName) => + (tokenType === HTMLUtils.ATTR_NAME || tokenType === HTMLUtils.ATTR_VALUE) && attrName === "id", + + resolve: (tagInfo) => { + var trimmedVal = tagInfo.attr.value.trim(); + if (trimmedVal) { + return { selectorName: "#" + trimmedVal, reason: null}; + } + return { selectorName: "", reason: Strings.ERROR_CSSQUICKEDIT_IDNOTFOUND }; + } + }; + + const ErrorSelectorStrategy = { + isMatch: () => true, + resolve: () => { return { selectorName: "", reason: Strings.ERROR_CSSQUICKEDIT_UNSUPPORTEDATTR }; } + }; + + strategies.push(TagSelectorStrategy); + strategies.push(ClassSelectorStrategy); + strategies.push(IdSelectorStrategy); + strategies.push(ErrorSelectorStrategy); + + function getStrategy(tagInfo) { + const strategy = strategies.find(s => s.isMatch(tagInfo.position.tokenType, tagInfo.attr.name)); + return strategy ? strategy : null; + } + + return getStrategy; +}); diff --git a/src/LiveDevelopment/main.js b/src/LiveDevelopment/main.js index 203e41845e..ca424a2bbc 100644 --- a/src/LiveDevelopment/main.js +++ b/src/LiveDevelopment/main.js @@ -324,12 +324,29 @@ define(function main(require, exports, module) { MultiBrowserLiveDev.updateConfig(config); } + // Adapter - Refactoring + const ElementHighlightPreferenceAdapter = { + toLivePreviewConfig() { + const prefValue = PreferencesManager.get( + CONSTANTS.PREFERENCE_PROJECT_ELEMENT_HIGHLIGHT + ); + + return { + elemHighlights: prefValue || CONSTANTS.HIGHLIGHT_HOVER + }; + } + }; + // this function is responsible to update element highlight config // called from live preview extension when preference changes function updateElementHighlightConfig() { - const prefValue = PreferencesManager.get(CONSTANTS.PREFERENCE_PROJECT_ELEMENT_HIGHLIGHT); const config = MultiBrowserLiveDev.getConfig(); - config.elemHighlights = prefValue || CONSTANTS.HIGHLIGHT_HOVER; + + Object.assign( + config, + ElementHighlightPreferenceAdapter.toLivePreviewConfig() + ); + MultiBrowserLiveDev.updateConfig(config); } diff --git a/src/editor/CSSInlineEditor.js b/src/editor/CSSInlineEditor.js index ba9614b01a..15b2de2880 100644 --- a/src/editor/CSSInlineEditor.js +++ b/src/editor/CSSInlineEditor.js @@ -56,56 +56,12 @@ define(function (require, exports, module) { * @private */ function _getSelectorName(editor, pos) { - var tagInfo = HTMLUtils.getTagInfo(editor, pos), - selectorName = "", - reason; - - if (tagInfo.position.tokenType === HTMLUtils.TAG_NAME || tagInfo.position.tokenType === HTMLUtils.CLOSING_TAG) { - // Type selector - selectorName = tagInfo.tagName; - } else if (tagInfo.position.tokenType === HTMLUtils.ATTR_NAME || - tagInfo.position.tokenType === HTMLUtils.ATTR_VALUE) { - if (tagInfo.attr.name === "class") { - // Class selector. We only look for the class name - // that includes the insertion point. For example, if - // the attribute is: - // class="error-dialog modal hide" - // and the insertion point is inside "modal", we want ".modal" - var attributeValue = tagInfo.attr.value; - if (/\S/.test(attributeValue)) { - var startIndex = attributeValue.substr(0, tagInfo.position.offset).lastIndexOf(" "); - var endIndex = attributeValue.indexOf(" ", tagInfo.position.offset); - selectorName = "." + - attributeValue.substring( - startIndex === -1 ? 0 : startIndex + 1, - endIndex === -1 ? attributeValue.length : endIndex - ); - - // If the insertion point is surrounded by space between two classnames, selectorName is "." - if (selectorName === ".") { - selectorName = ""; - reason = Strings.ERROR_CSSQUICKEDIT_BETWEENCLASSES; - } - } else { - reason = Strings.ERROR_CSSQUICKEDIT_CLASSNOTFOUND; - } - } else if (tagInfo.attr.name === "id") { - // ID selector - var trimmedVal = tagInfo.attr.value.trim(); - if (trimmedVal) { - selectorName = "#" + trimmedVal; - } else { - reason = Strings.ERROR_CSSQUICKEDIT_IDNOTFOUND; - } - } else { - reason = Strings.ERROR_CSSQUICKEDIT_UNSUPPORTEDATTR; - } - } + var tagInfo = HTMLUtils.getTagInfo(editor, pos); + + const strategies = require('../JSUtils/SelectorStrategy.js'); + const activeStrategy = strategies.find(s => s.isMatch(tagInfo.position.tokenType, tagInfo.attr.name)); - return { - selectorName: selectorName, - reason: reason - }; + return activeStrategy.extract(tagInfo); } /** diff --git a/src/editor/EditorOptionHandlers.js b/src/editor/EditorOptionHandlers.js index bbdf3609b5..1aa48e2d46 100644 --- a/src/editor/EditorOptionHandlers.js +++ b/src/editor/EditorOptionHandlers.js @@ -104,32 +104,46 @@ define(function (require, exports, module) { }; } + // Factory - Refactoring + const RulerOptionsFactory = { + create: function (rulerColumns, rulerColors, defaultColor) { + return rulerColumns.map(function (column, index) { + return { + color: rulerColors[index] ? rulerColors[index] : defaultColor, + column: column, + lineStyle: "solid !important" + }; + }); + } + }; + function _createRulers(editor) { const rulerColumns = PreferencesManager.get(PREFERENCES_EDITOR_RULERS) || []; const rulerColors = PreferencesManager.get(PREFERENCES_EDITOR_RULER_COLORS) || []; const rulersEnabled = PreferencesManager.get(PREFERENCES_EDITOR_RULERS_ENABLED); - if( !rulersEnabled || !rulerColumns.length || !editor){ + + if (!rulersEnabled || !rulerColumns.length || !editor) { return; } - if(!_currentTheme){ + if (!_currentTheme) { _currentTheme = ThemeManager.getCurrentTheme(); } - if(!_currentTheme){ - // theme manager can return a null current theme at startup before themes load! + + if (!_currentTheme) { + // O tema pode ainda não estar carregado na inicialização. return; } - const defaultColor = (_currentTheme && _currentTheme.dark) ? "#333333" : "#e0e0e0"; - - if(!editor._codeMirror.getOption("rulers")){ - let rulerOptions = []; - for(let i=0; i { - modalMessage.appendChild(document.createTextNode(part)); - if (index < array.length - 1) { // Don't add a break on the last element - modalMessage.appendChild(document.createElement('br')); - } - }); - copyButton.textContent = 'Copy Error'; - getHelpButton.textContent = 'Get Help'; - // In native apps, we can't reload because AES trust ring won't survive - must quit and restart manually - reloadButton.textContent = Phoenix.isNativeApp ? 'Quit App' : 'Restart App'; - // Styling for visibility - // Define common styles for buttons const buttonStyles = { padding: '10px 20px', marginRight: '10px', // Space between buttons @@ -243,8 +225,30 @@ function confirmReload(title, message) { const getHelpButtonStyles = {backgroundColor: '#4CAF50'}; const reloadButtonStyles = {backgroundColor: '#4CAF50'}; - modalTitle.style.color = 'red'; - applyStyles(modal, { + modalBuilder.addButton( + 'Copy Error', + {...buttonStyles, ...copyButtonStyles}, + function() { + navigator.clipboard.writeText(message).then(() => { + alert('Error Message copied!'); + }, (err) => { + console.error('Failed to copy text: ', err); + }); + } + ); + modalBuilder.addButton( + 'Get Help', + {...buttonStyles, ...getHelpButtonStyles}, + function() { + Phoenix.app.openURLInDefaultBrowser("https://github.com/phcode-dev/phoenix/discussions"); + } + ); + const reloadButton = modalBuilder.addButton( + Phoenix.isNativeApp ? 'Quit App' : 'Restart App', + {...buttonStyles, ...reloadButtonStyles} + ); + + modalBuilder.addStyle('modal', { color: 'black', position: 'fixed', top: '0', @@ -258,7 +262,7 @@ function confirmReload(title, message) { alignItems: 'center' }); - applyStyles(modalContent, { + modalBuilder.addStyle('content', { backgroundColor: 'white', padding: '20px', borderRadius: '10px', @@ -266,37 +270,13 @@ function confirmReload(title, message) { boxShadow: '0 4px 8px rgba(0,0,0,0.2)' }); - applyStyles(buttonsContainer, { + modalBuilder.addStyle('buttons', { marginTop: '20px', display: 'flex', justifyContent: 'space-around' }); - // Apply styles to buttons - applyStyles(copyButton, {...buttonStyles, ...copyButtonStyles}); - applyStyles(getHelpButton, {...buttonStyles, ...getHelpButtonStyles}); - applyStyles(reloadButton, {...buttonStyles, ...reloadButtonStyles}); - - // Event listeners for buttons - copyButton.onclick = function() { - navigator.clipboard.writeText(message).then(() => { - alert('Error Message copied!'); - }, (err) => { - console.error('Failed to copy text: ', err); - }); - }; - getHelpButton.onclick = function() { - Phoenix.app.openURLInDefaultBrowser("https://github.com/phcode-dev/phoenix/discussions"); - }; - - // Append children - modalContent.appendChild(modalTitle); - modalContent.appendChild(modalMessage); - buttonsContainer.appendChild(copyButton); - buttonsContainer.appendChild(getHelpButton); - buttonsContainer.appendChild(reloadButton); - modalContent.appendChild(buttonsContainer); - modal.appendChild(modalContent); + const modal = modalBuilder.build(); // Append modal to the body document.body.appendChild(modal);