diff --git a/config.xml b/config.xml index 236eea5e7..8c3ef4d9d 100644 --- a/config.xml +++ b/config.xml @@ -38,6 +38,7 @@ + { syntax: 'typescript', tsx: false, }, - transform: { - // react: { - // pragma: 'tag', - // pragmaFrag: 'Array', - // throwIfNamespace: false, - // development: false, - // useBuiltins: false, - // runtime: 'classic', - // }, - }, target: 'es2015', }, }, diff --git a/src/components/audioPlayer/style.scss b/src/components/audioPlayer/style.scss index 18f71d72c..c28a4d275 100644 --- a/src/components/audioPlayer/style.scss +++ b/src/components/audioPlayer/style.scss @@ -1,3 +1,8 @@ +@supports not (gap: 1px) { + .audio-player > * + * { margin-left: 15px; } + .volume-control > * + * { margin-left: 8px; } +} + .audio-player { background: var(--primary-color, #1e1e1e); border-radius: 10px; diff --git a/src/components/lspInfoDialog/styles.scss b/src/components/lspInfoDialog/styles.scss index be11bbfef..f2415240a 100644 --- a/src/components/lspInfoDialog/styles.scss +++ b/src/components/lspInfoDialog/styles.scss @@ -454,4 +454,20 @@ font-weight: 600; color: var(--popup-text-color); font-family: monospace; +} + +@supports not (gap: 1px) { + .lsp-list-actions > * + * { margin-left: 8px; } + .lsp-action-btn > * + * { margin-left: 6px; } + .lsp-server-item > * + * { margin-left: 12px; } + .lsp-server-info > * + * { margin-top: 2px; } + .lsp-details-header > * + * { margin-left: 8px; } + .lsp-header-actions > * + * { margin-left: 4px; } + .lsp-details-title > * + * { margin-left: 10px; } + .lsp-chip-container > * { margin-right: 5px; margin-bottom: 5px; } + .lsp-logs-actions > * + * { margin-left: 2px; } + .lsp-log > * + * { margin-left: 6px; } + .lsp-logs-title > * + * { margin-left: 4px; } + .lsp-stats-container > * + * { margin-left: 16px; } + .lsp-stat > * + * { margin-left: 6px; } } \ No newline at end of file diff --git a/src/components/lspStatusBar/style.scss b/src/components/lspStatusBar/style.scss index ac0a78e63..0872b3fba 100644 --- a/src/components/lspStatusBar/style.scss +++ b/src/components/lspStatusBar/style.scss @@ -163,6 +163,14 @@ wc-page:not([footer-height]) #lsp-status-bar { bottom: 10px; } +@supports not (gap: 1px) { + #lsp-status-bar { + .lsp-status-content > * + * { margin-left: 10px; } + .lsp-status-text > * + * { margin-top: 2px; } + .lsp-status-progress > * + * { margin-left: 8px; } + } +} + @keyframes lspStatusSlideUp { from { transform: translateY(100%); diff --git a/src/components/referencesPanel/styles.scss b/src/components/referencesPanel/styles.scss index b2c8a124b..b73fa2e0a 100644 --- a/src/components/referencesPanel/styles.scss +++ b/src/components/referencesPanel/styles.scss @@ -298,6 +298,21 @@ } } +@supports not (gap: 1px) { + .references-panel { + .header-content > * + * { margin-top: 2px; } + .header-title > * + * { margin-left: 8px; } + .header-actions > * + * { margin-left: 4px; } + .loading-state > * + * { margin-left: 12px; } + } + .ref-file-header > * + * { margin-left: 8px; } + .ref-item > * + * { margin-left: 10px; } + .references-tab-container { + .header-info > * + * { margin-left: 10px; } + .loading-state > * + * { margin-left: 12px; } + } +} + .references-tab-container { display: flex; flex-direction: column; diff --git a/src/components/settingsPage.scss b/src/components/settingsPage.scss index aba4f617f..4990981d1 100644 --- a/src/components/settingsPage.scss +++ b/src/components/settingsPage.scss @@ -2,19 +2,20 @@ #{$list-selector} { display: flex; flex-direction: column; - gap: 1.2rem; width: 100%; max-width: 48rem; margin: 0 auto; padding: 0.5rem 0 5.5rem; box-sizing: border-box; background: var(--secondary-color); + + > *:not(:first-child) { + margin-top: 1.2rem; + } } .settings-section { - display: flex; - flex-direction: column; - gap: 0; + display: block; width: 100%; } @@ -37,13 +38,13 @@ .settings-section-card { width: 100%; - overflow: hidden; box-sizing: border-box; } } @mixin settings-icon-reset { .icon { + &:active, &.active { transform: none; @@ -56,8 +57,8 @@ wc-page.main-settings-page { background: var(--secondary-color); @include settings-page-shell(".main-settings-list"); - .main-settings-list > .list-item, - .settings-section-card > .list-item { + .main-settings-list>.list-item, + .settings-section-card>.list-item { display: flex; width: 100%; min-height: 64px; @@ -65,12 +66,17 @@ wc-page.main-settings-page { padding: 0.75rem 1rem; box-sizing: border-box; align-items: center; - gap: 0.85rem; background: transparent; cursor: pointer; + > *:not(:first-child) { + margin-left: 0.85rem; + } + &.no-leading-icon { - gap: 0; + > *:not(:first-child) { + margin-left: 0; + } } &:not(:last-of-type) { @@ -84,14 +90,14 @@ wc-page.main-settings-page { background: color-mix(in srgb, var(--secondary-color), var(--popup-text-color) 4%); } - > .icon.no-icon { + >.icon.no-icon { width: 0; min-width: 0; height: 0; margin: 0; } - > .icon:first-child:not(.no-icon) { + >.icon:first-child:not(.no-icon) { display: flex; align-items: center; justify-content: center; @@ -103,15 +109,18 @@ wc-page.main-settings-page { color: color-mix(in srgb, var(--secondary-text-color), transparent 18%); } - > .container { + >.container { flex: 1; display: flex; flex-direction: column; min-width: 0; overflow: visible; - gap: 0.2rem; - > .text { + > *:not(:first-child) { + margin-top: 0.2rem; + } + + >.text { display: block; flex: none; min-width: 0; @@ -121,7 +130,7 @@ wc-page.main-settings-page { color: var(--popup-text-color); } - > .value { + >.value { flex: none; font-size: 0.82rem; line-height: 1.35; @@ -154,40 +163,52 @@ wc-page.main-settings-page { } .settings-search-section .list-item { - > .container { + >.container { padding-right: 0.35rem; - gap: 0.18rem; + + > *:not(:first-child) { + margin-top: 0.18rem; + } } - > .setting-tail { + >.setting-tail { display: flex; align-items: center; justify-content: flex-end; flex-shrink: 0; min-height: 1.65rem; - gap: 0.32rem; margin-left: 0.9rem; align-self: center; + + > *:not(:first-child) { + margin-left: 0.32rem; + } } - &.has-subtitle > .container { - gap: 0.24rem; + &.has-subtitle>.container { padding-top: 0.14rem; padding-right: 0.6rem; + + > *:not(:first-child) { + margin-top: 0.24rem; + } } - &.has-subtitle.has-tail-select > .container { + &.has-subtitle.has-tail-select>.container { padding-right: 0.95rem; } - &.compact > .container { + &.compact>.container { align-self: center; justify-content: center; - gap: 0; padding-top: 0; + + > *:not(:first-child) { + margin-top: 0; + } } - &.compact > .setting-tail { + &.compact>.setting-tail { align-self: center; } } @@ -195,7 +216,6 @@ wc-page.main-settings-page { .settings-search-section .setting-value-display { display: inline-flex; align-items: center; - gap: 0.15rem; min-height: auto; padding: 0; border: none; @@ -205,24 +225,29 @@ wc-page.main-settings-page { color: color-mix(in srgb, var(--secondary-text-color), transparent 18%); box-sizing: border-box; + > *:not(:first-child) { + margin-left: 0.15rem; + } + &.is-select { min-width: clamp(6.75rem, 30vw, 8.5rem); max-width: min(45vw, 11.5rem); min-height: 2.35rem; padding: 0 0.8rem 0 0.95rem; - gap: 0.55rem; justify-content: space-between; border: 1px solid var(--border-color); border: 1px solid color-mix(in srgb, var(--border-color), transparent 12%); border-radius: 0.56rem; - background: color-mix( - in srgb, - var(--secondary-color), - var(--popup-background-color) 42% - ); + background: color-mix(in srgb, + var(--secondary-color), + var(--popup-background-color) 42%); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--border-color), transparent 44%), 0 1px 2px rgba(0, 0, 0, 0.12); + + > *:not(:first-child) { + margin-left: 0.55rem; + } } } @@ -298,11 +323,9 @@ wc-page.main-settings-page { border: 1px solid color-mix(in srgb, var(--border-color), transparent 6%); border-radius: 999px; background: var(--popup-background-color); - background: color-mix( - in srgb, - var(--secondary-color), - var(--popup-background-color) 30% - ); + background: color-mix(in srgb, + var(--secondary-color), + var(--popup-background-color) 30%); transition: background-color 160ms ease, border-color 160ms ease, @@ -314,11 +337,9 @@ wc-page.main-settings-page { margin: 0.14rem; border-radius: 999px; background: var(--popup-text-color); - background: color-mix( - in srgb, - var(--popup-text-color), - var(--popup-background-color) 18% - ); + background: color-mix(in srgb, + var(--popup-text-color), + var(--popup-background-color) 18%); opacity: 1; box-shadow: 0 0 0 1px color-mix(in srgb, var(--border-color), transparent 34%), @@ -330,37 +351,30 @@ wc-page.main-settings-page { } } - input:checked + .box { + input:checked+.box { background: var(--button-background-color); border-color: color-mix(in srgb, var(--button-background-color), transparent 10%); - box-shadow: inset 0 0 0 1px - color-mix(in srgb, var(--button-background-color), transparent 12%); + box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--button-background-color), transparent 12%); } - input:checked + .box::after { + input:checked+.box::after { transform: translateX(1.12rem); background: var(--button-text-color); opacity: 1; box-shadow: 0 2px 8px color-mix(in srgb, var(--button-background-color), transparent 55%); } - input:not(:checked) + .box::after { + input:not(:checked)+.box::after { opacity: 1; } } - .settings-search-section - .list-item.has-tail-select:focus - .setting-value-display.is-select, - .settings-search-section - .list-item.has-tail-select:active - .setting-value-display.is-select { + .settings-search-section .list-item.has-tail-select:focus .setting-value-display.is-select, + .settings-search-section .list-item.has-tail-select:active .setting-value-display.is-select { border-color: color-mix(in srgb, var(--active-color), transparent 48%); - background: color-mix( - in srgb, - var(--popup-background-color), - var(--active-color) 9% - ); + background: color-mix(in srgb, + var(--popup-background-color), + var(--active-color) 9%); } @media screen and (min-width: 768px) { @@ -392,8 +406,8 @@ wc-page.detail-settings-page { background: var(--secondary-color); @include settings-page-shell(".detail-settings-list"); - .detail-settings-list > .list-item, - .settings-section-card > .list-item { + .detail-settings-list>.list-item, + .settings-section-card>.list-item { display: flex; width: 100%; margin: 0; @@ -401,17 +415,22 @@ wc-page.detail-settings-page { min-height: 3.2rem; box-sizing: border-box; align-items: center; - gap: 0.85rem; background: transparent; cursor: pointer; transition: background-color 140ms ease; + > *:not(:first-child) { + margin-left: 0.85rem; + } + &.compact { align-items: center; } &.no-leading-icon { - gap: 0; + > *:not(:first-child) { + margin-left: 0; + } } &:not(:last-of-type) { @@ -425,14 +444,14 @@ wc-page.detail-settings-page { background: color-mix(in srgb, var(--secondary-color), var(--popup-text-color) 4%); } - > .icon.no-icon { + >.icon.no-icon { width: 0; min-width: 0; height: 0; margin: 0; } - > .icon:first-child:not(.no-icon) { + >.icon:first-child:not(.no-icon) { display: flex; align-items: center; justify-content: center; @@ -444,16 +463,19 @@ wc-page.detail-settings-page { color: color-mix(in srgb, var(--secondary-text-color), transparent 18%); } - > .container { + >.container { flex: 1; display: flex; flex-direction: column; min-width: 0; overflow: visible; - gap: 0.18rem; padding-right: 0.35rem; - > .text { + > *:not(:first-child) { + margin-top: 0.18rem; + } + + >.text { display: flex; align-items: center; flex: none; @@ -464,7 +486,7 @@ wc-page.detail-settings-page { color: var(--popup-text-color); } - > .value { + >.value { flex: none; font-size: 0.82rem; line-height: 1.35; @@ -478,47 +500,55 @@ wc-page.detail-settings-page { } } - > .setting-tail { + >.setting-tail { display: flex; align-items: center; justify-content: flex-end; flex-shrink: 0; min-height: 1.65rem; - gap: 0.32rem; margin-left: 0.9rem; align-self: center; + + > *:not(:first-child) { + margin-left: 0.32rem; + } } } - .detail-settings-list > .list-item.has-subtitle > .container, - .settings-section-card > .list-item.has-subtitle > .container { - gap: 0.24rem; + .detail-settings-list>.list-item.has-subtitle>.container, + .settings-section-card>.list-item.has-subtitle>.container { padding-top: 0.14rem; padding-right: 0.6rem; + + > *:not(:first-child) { + margin-top: 0.24rem; + } } - .detail-settings-list > .list-item.has-subtitle.has-tail-select > .container, - .settings-section-card > .list-item.has-subtitle.has-tail-select > .container { + .detail-settings-list>.list-item.has-subtitle.has-tail-select>.container, + .settings-section-card>.list-item.has-subtitle.has-tail-select>.container { padding-right: 0.95rem; } - .detail-settings-list > .list-item.compact > .container, - .settings-section-card > .list-item.compact > .container { + .detail-settings-list>.list-item.compact>.container, + .settings-section-card>.list-item.compact>.container { align-self: center; justify-content: center; - gap: 0; padding-top: 0; + + > *:not(:first-child) { + margin-top: 0; + } } - .detail-settings-list > .list-item.compact > .setting-tail, - .settings-section-card > .list-item.compact > .setting-tail { + .detail-settings-list>.list-item.compact>.setting-tail, + .settings-section-card>.list-item.compact>.setting-tail { align-self: center; } .setting-value-display { display: inline-flex; align-items: center; - gap: 0.15rem; min-height: auto; padding: 0; border: none; @@ -528,24 +558,29 @@ wc-page.detail-settings-page { color: color-mix(in srgb, var(--secondary-text-color), transparent 18%); box-sizing: border-box; + > *:not(:first-child) { + margin-left: 0.15rem; + } + &.is-select { min-width: clamp(6.75rem, 30vw, 8.5rem); max-width: min(45vw, 11.5rem); min-height: 2.35rem; padding: 0 0.8rem 0 0.95rem; - gap: 0.55rem; justify-content: space-between; border: 1px solid var(--border-color); border: 1px solid color-mix(in srgb, var(--border-color), transparent 12%); border-radius: 0.56rem; - background: color-mix( - in srgb, - var(--secondary-color), - var(--popup-background-color) 42% - ); + background: color-mix(in srgb, + var(--secondary-color), + var(--popup-background-color) 42%); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--border-color), transparent 44%), 0 1px 2px rgba(0, 0, 0, 0.12); + + > *:not(:first-child) { + margin-left: 0.55rem; + } } } @@ -619,11 +654,9 @@ wc-page.detail-settings-page { border: 1px solid color-mix(in srgb, var(--border-color), transparent 6%); border-radius: 999px; background: var(--popup-background-color); - background: color-mix( - in srgb, - var(--secondary-color), - var(--popup-background-color) 30% - ); + background: color-mix(in srgb, + var(--secondary-color), + var(--popup-background-color) 30%); transition: background-color 160ms ease, border-color 160ms ease, @@ -635,11 +668,9 @@ wc-page.detail-settings-page { margin: 0.14rem; border-radius: 999px; background: var(--popup-text-color); - background: color-mix( - in srgb, - var(--popup-text-color), - var(--popup-background-color) 18% - ); + background: color-mix(in srgb, + var(--popup-text-color), + var(--popup-background-color) 18%); opacity: 1; box-shadow: 0 0 0 1px var(--border-color), @@ -654,16 +685,15 @@ wc-page.detail-settings-page { } } - input:checked + .box { + input:checked+.box { background: var(--button-background-color); border-color: var(--button-background-color); border-color: color-mix(in srgb, var(--button-background-color), transparent 10%); box-shadow: inset 0 0 0 1px var(--button-background-color); - box-shadow: inset 0 0 0 1px - color-mix(in srgb, var(--button-background-color), transparent 12%); + box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--button-background-color), transparent 12%); } - input:checked + .box::after { + input:checked+.box::after { transform: translateX(1.12rem); background: var(--button-text-color); opacity: 1; @@ -671,7 +701,7 @@ wc-page.detail-settings-page { box-shadow: 0 2px 8px color-mix(in srgb, var(--button-background-color), transparent 55%); } - input:not(:checked) + .box::after { + input:not(:checked)+.box::after { opacity: 1; } } @@ -679,7 +709,6 @@ wc-page.detail-settings-page { .note { display: flex; align-items: flex-start; - gap: 0.6rem; width: auto; box-sizing: border-box; margin: 0.25rem 0.75rem; @@ -690,6 +719,10 @@ wc-page.detail-settings-page { background: var(--popup-background-color); background: color-mix(in srgb, var(--popup-background-color), var(--active-color) 8%); + > *:not(:first-child) { + margin-left: 0.6rem; + } + .note-title { display: flex; align-items: center; @@ -700,7 +733,7 @@ wc-page.detail-settings-page { background: transparent; text-transform: none; - > .icon { + >.icon { display: inline-flex; align-items: center; justify-content: center; @@ -714,7 +747,7 @@ wc-page.detail-settings-page { margin-top: 0.12rem; } - > span:last-child { + >span:last-child { display: none; } } @@ -744,28 +777,23 @@ wc-page.detail-settings-page { } } - .detail-settings-list > .list-item.has-tail-select:focus .setting-value-display.is-select, - .detail-settings-list > .list-item.has-tail-select:active .setting-value-display.is-select, - .settings-section-card - > .list-item.has-tail-select:focus - .setting-value-display.is-select, - .settings-section-card - > .list-item.has-tail-select:active - .setting-value-display.is-select { + .detail-settings-list>.list-item.has-tail-select:focus .setting-value-display.is-select, + .detail-settings-list>.list-item.has-tail-select:active .setting-value-display.is-select, + .settings-section-card>.list-item.has-tail-select:focus .setting-value-display.is-select, + .settings-section-card>.list-item.has-tail-select:active .setting-value-display.is-select { border-color: color-mix(in srgb, var(--active-color), transparent 48%); - background: color-mix( - in srgb, - var(--popup-background-color), - var(--active-color) 9% - ); + background: color-mix(in srgb, + var(--popup-background-color), + var(--active-color) 9%); } @include settings-icon-reset; } wc-page.detail-settings-page.formatter-settings-page { - .detail-settings-list > .list-item, - .settings-section-card > .list-item { + + .detail-settings-list>.list-item, + .settings-section-card>.list-item { padding-top: 0.5rem; padding-bottom: 0.5rem; @@ -781,7 +809,7 @@ wc-page.detail-settings-page.formatter-settings-page { padding-bottom: 0.74rem; } - > .icon:first-child:not(.no-icon) { + >.icon:first-child:not(.no-icon) { width: 1.1rem; min-width: 1.1rem; height: 1.1rem; @@ -789,19 +817,21 @@ wc-page.detail-settings-page.formatter-settings-page { font-size: 1rem; } - > .container { - gap: 0.2rem; + >.container { + > *:not(:first-child) { + margin-top: 0.2rem; + } } - > .container > .value { + >.container>.value { -webkit-line-clamp: unset; } } - .detail-settings-list > .list-item.compact > .container, - .settings-section-card > .list-item.compact > .container, - .detail-settings-list > .list-item.compact > .setting-tail, - .settings-section-card > .list-item.compact > .setting-tail { + .detail-settings-list>.list-item.compact>.container, + .settings-section-card>.list-item.compact>.container, + .detail-settings-list>.list-item.compact>.setting-tail, + .settings-section-card>.list-item.compact>.setting-tail { align-self: center; } -} +} \ No newline at end of file diff --git a/src/components/sideButton/style.scss b/src/components/sideButton/style.scss index efd92878f..79a85796d 100644 --- a/src/components/sideButton/style.scss +++ b/src/components/sideButton/style.scss @@ -32,4 +32,8 @@ display: flex; flex-direction: column; gap: 5px; + + @supports not (gap: 1px) { + > * + * { margin-top: 5px; } + } } \ No newline at end of file diff --git a/src/components/sidebar/style.scss b/src/components/sidebar/style.scss index 4a9b71c63..4ac877ecb 100644 --- a/src/components/sidebar/style.scss +++ b/src/components/sidebar/style.scss @@ -74,6 +74,11 @@ body.no-animation { flex-direction: column; align-items: center; gap: 4px; + + @supports not (gap: 1px) { + > * + * { margin-top: 4px; } + } + scrollbar-width: none; -ms-overflow-style: none; @@ -410,4 +415,8 @@ body.no-animation { background-color: var(--border-color); margin: 4px 0; } +} + +@supports not (gap: 1px) { + .user-menu-item > * + * { margin-left: 8px; } } \ No newline at end of file diff --git a/src/components/symbolsPanel/styles.scss b/src/components/symbolsPanel/styles.scss index e08b42c7d..b710725a1 100644 --- a/src/components/symbolsPanel/styles.scss +++ b/src/components/symbolsPanel/styles.scss @@ -406,4 +406,14 @@ flex-shrink: 0; opacity: 0.7; } +} + +@supports not (gap: 1px) { + .symbols-panel { + .header-content > * + * { margin-top: 2px; } + .header-title > * + * { margin-left: 8px; } + .header-actions > * + * { margin-left: 4px; } + .loading-state > * + * { margin-left: 12px; } + } + .symbol-item > * + * { margin-left: 10px; } } \ No newline at end of file diff --git a/src/components/terminal/terminal.js b/src/components/terminal/terminal.js index 0271b4a40..b1a82a9fa 100644 --- a/src/components/terminal/terminal.js +++ b/src/components/terminal/terminal.js @@ -702,23 +702,25 @@ export default class TerminalComponent { rows: this.terminal.rows, }; - const response = await fetch( - `http://localhost:${this.options.port}/terminals`, - { - method: "POST", - headers: { - "Content-Type": "application/json", + const response = await new Promise((resolve, reject) => { + cordova.plugin.http.sendRequest( + `http://localhost:${this.options.port}/terminals`, + { + method: "POST", + responseType: "text", + serializer: "json", + data: requestBody, }, - body: JSON.stringify(requestBody), - }, - ); + (res) => resolve(res), + (err) => reject(new Error(err.error || `HTTP error!`)), + ); + }); - if (!response.ok) { + if (response.status < 200 || response.status >= 300) { throw new Error(`HTTP error! status: ${response.status}`); } - const data = await response.text(); - this.pid = data.trim(); + this.pid = response.data.trim(); return this.pid; } catch (error) { console.error("Failed to create terminal session:", error); @@ -847,16 +849,18 @@ export default class TerminalComponent { if (!this.pid || !this.serverMode) return; try { - await fetch( - `http://localhost:${this.options.port}/terminals/${this.pid}/resize`, - { - method: "POST", - headers: { - "Content-Type": "application/json", + await new Promise((resolve, reject) => { + cordova.plugin.http.sendRequest( + `http://localhost:${this.options.port}/terminals/${this.pid}/resize`, + { + method: "POST", + serializer: "json", + data: { cols, rows }, }, - body: JSON.stringify({ cols, rows }), - }, - ); + (res) => resolve(res), + (err) => reject(err), + ); + }); } catch (error) { console.error("Failed to resize terminal:", error); } @@ -1131,12 +1135,16 @@ export default class TerminalComponent { if (this.pid && this.serverMode) { try { - await fetch( - `http://localhost:${this.options.port}/terminals/${this.pid}/terminate`, - { - method: "POST", - }, - ); + await new Promise((resolve, reject) => { + cordova.plugin.http.sendRequest( + `http://localhost:${this.options.port}/terminals/${this.pid}/terminate`, + { + method: "POST", + }, + (res) => resolve(res), + (err) => reject(err), + ); + }); } catch (error) { console.error("Failed to terminate terminal:", error); } @@ -1189,7 +1197,7 @@ export default class TerminalComponent { // Internal helpers for WebGL renderer lifecycle TerminalComponent.prototype._handleWebglContextLoss = function () { try { - console.warn("WebGL context lost; falling back to canvas renderer"); + console.warn("WebGL context lost; terminal rendering will be degraded"); try { this.webglAddon?.dispose?.(); } catch {} diff --git a/src/components/terminal/terminalManager.js b/src/components/terminal/terminalManager.js index f9d22dd2d..820565e59 100644 --- a/src/components/terminal/terminalManager.js +++ b/src/components/terminal/terminalManager.js @@ -3,18 +3,18 @@ * Handles terminal session creation and management */ -import EditorFile from "lib/editorFile"; -import TerminalComponent from "./terminal"; -import TerminalTouchSelection from "./terminalTouchSelection"; import "@xterm/xterm/css/xterm.css"; import quickTools from "components/quickTools"; import toast from "components/toast"; import alert from "dialogs/alert"; import confirm from "dialogs/confirm"; +import EditorFile from "lib/editorFile"; import openFile from "lib/openFile"; import openFolder from "lib/openFolder"; import appSettings from "lib/settings"; import helpers from "utils/helpers"; +import TerminalComponent from "./terminal"; +import TerminalTouchSelection from "./terminalTouchSelection"; const TERMINAL_SESSION_STORAGE_KEY = "acodeTerminalSessions"; @@ -581,26 +581,34 @@ class TerminalManager { const textarea = terminalComponent.terminal?.textarea; if (textarea) { const onFocus = () => { - const { $toggler } = quickTools; - $toggler.classList.add("hide"); - clearTimeout(this.togglerTimeout); - this.togglerTimeout = setTimeout(() => { - $toggler.style.display = "none"; - }, 300); + clearTimeout(this.onBlurTimeout); + this.onFocusTimeout = setTimeout(() => { + const { $toggler } = quickTools; + $toggler.classList.add("hide"); + clearTimeout(this.quickToolsTogglerTimeout); + this.quickToolsTogglerTimeout = setTimeout(() => { + $toggler.style.display = "none"; + }, 300); + }, 100); }; const onBlur = () => { - const { $toggler } = quickTools; - clearTimeout(this.togglerTimeout); - $toggler.style.display = ""; - setTimeout(() => { - $toggler.classList.remove("hide"); - }, 10); + clearTimeout(this.onFocusTimeout); + this.onBlurTimeout = setTimeout(() => { + const { $toggler } = quickTools; + $toggler.style.display = ""; + clearTimeout(this.quickToolsTogglerTimeout); + requestAnimationFrame(() => $toggler.classList.remove("hide")); + }, 100); }; textarea.addEventListener("focus", onFocus); textarea.addEventListener("blur", onBlur); + if (textarea === document.activeElement) { + onFocus(); + } + terminalComponent.cleanupFocusHandlers = () => { textarea.removeEventListener("focus", onFocus); textarea.removeEventListener("blur", onBlur); diff --git a/src/handlers/keyboard.js b/src/handlers/keyboard.js index 7dba9e920..145bc9dc5 100644 --- a/src/handlers/keyboard.js +++ b/src/handlers/keyboard.js @@ -1,3 +1,4 @@ +import { bannerAd } from "lib/startAd"; import { getSystemConfiguration, HARDKEYBOARDHIDDEN_NO, @@ -115,11 +116,13 @@ document.addEventListener("deviceready", () => { softKeyboardHeight = keyboardHeight > MIN_KEYBOARD_HEIGHT ? keyboardHeight : 0; if (!externalKeyboard && softKeyboardHeight) { + toggleBannerAd(false); emit("keyboardShowStart"); } } else if (currentWindowHeight < window.innerHeight) { // height increasing if (!externalKeyboard && softKeyboardHeight) { + toggleBannerAd(true); emit("keyboardHideStart"); } } @@ -148,7 +151,6 @@ document.addEventListener("deviceready", () => { } focusBlurEditor(keyboardHiddenYes); - showHideAd(keyboardHiddenYes); }); }); @@ -199,16 +201,16 @@ function focusBlurEditor(keyboardHidden) { * Show ad if keyboard is hidden and ad is active, hide ad otherwise. * @param {boolean} keyboardHidden */ -function showHideAd(keyboardHidden) { - const bannerIsActive = !!window.ad?.active; +function toggleBannerAd(keyboardHidden) { + const bannerIsActive = !!bannerAd?.active; if ( !keyboardHidden && bannerIsActive && - typeof window.ad?.hide === "function" + typeof bannerAd?.hide === "function" ) { - window.ad.hide(); - } else if (bannerIsActive && typeof window.ad?.show === "function") { - window.ad.show(); + bannerAd.hide(); + } else if (bannerIsActive && typeof bannerAd?.show === "function") { + bannerAd.show(); } } diff --git a/src/lib/adRewards.js b/src/lib/adRewards.js index ef3d94420..3fc6aff68 100644 --- a/src/lib/adRewards.js +++ b/src/lib/adRewards.js @@ -2,6 +2,7 @@ import toast from "components/toast"; import auth from "./auth"; import config from "./config"; import secureAdRewardState from "./secureAdRewardState"; +import { adUnitIdRewarded, bannerAd } from "./startAd"; const ONE_HOUR = 60 * 60 * 1000; const MAX_TIMEOUT = 2_147_483_647; @@ -67,10 +68,6 @@ function formatDurationRange(minDurationMs, maxDurationMs) { return `${minHours}-${maxHours} hours`; } -function getRewardedUnitId() { - return window.adRewardedUnitId || ""; -} - function getExpiryDate() { return state.adFreeUntil ? new Date(state.adFreeUntil) : null; } @@ -90,9 +87,9 @@ function emitChange() { } function hideActiveBanner() { - if (window.ad?.active) { - window.ad.active = false; - window.ad.hide?.(); + if (bannerAd?.active) { + bannerAd.active = false; + bannerAd.hide?.(); } } @@ -187,8 +184,7 @@ async function getRewardIdentity() { } async function createRewardedAd(offer, step, sessionId) { - const rewardedUnitId = getRewardedUnitId(); - if (!rewardedUnitId || !admob?.RewardedAd) { + if (!admob?.RewardedAd) { throw new Error("Rewarded ads are not available in this build."); } @@ -201,7 +197,7 @@ async function createRewardedAd(offer, step, sessionId) { ].join("&"); return new admob.RewardedAd({ - adUnitId: rewardedUnitId, + adUnitId: adUnitIdRewarded, serverSideVerification: { userId, customData, @@ -319,7 +315,7 @@ export default { return Boolean(!config.HAS_PRO && !this.isAdFreeActive()); }, isRewardedSupported() { - return Boolean(!config.HAS_PRO && admob?.RewardedAd && getRewardedUnitId()); + return Boolean(!config.HAS_PRO && admob?.RewardedAd && adUnitIdRewarded); }, getRewardedUnavailableReason() { if (config.HAS_PRO) { @@ -328,9 +324,6 @@ export default { if (!admob?.RewardedAd) { return "Rewarded ads are unavailable on this device."; } - if (!getRewardedUnitId()) { - return "Rewarded ads are not configured for production yet."; - } return ""; }, canRedeemNow() { diff --git a/src/lib/fonts.js b/src/lib/fonts.js index 14d8b2197..fbd8c2e8b 100644 --- a/src/lib/fonts.js +++ b/src/lib/fonts.js @@ -294,9 +294,10 @@ async function loadFont(name) { // Replace any pre-injected @font-face block (from injectFontFace) // with the locally-cached version, or append if not yet present if ($style.textContent.includes(`font-family: '${name}'`)) { + let escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); $style.textContent = $style.textContent.replace( new RegExp( - `@font-face\\s*\\{[^}]*font-family:\\s*'${name}'[^}]*\\}`, + `@font-face\\s*\\{[^}]*font-family:\\s*'${escapedName}'[^}]*\\}`, "g", ), css, diff --git a/src/lib/polyfill.js b/src/lib/polyfill.js index 3ed91597b..d8cab0bbb 100644 --- a/src/lib/polyfill.js +++ b/src/lib/polyfill.js @@ -102,6 +102,36 @@ }); })([Element.prototype, CharacterData.prototype, DocumentType.prototype]); +// polyfill for replaceChildren + +(function (arr) { + arr.forEach(function (item) { + if (item.hasOwnProperty("replaceChildren")) { + return; + } + Object.defineProperty(item, "replaceChildren", { + configurable: true, + enumerable: false, + writable: true, + value: function replaceChildren() { + while (this.firstChild) { + this.removeChild(this.firstChild); + } + // biome-ignore lint/style/useForOf: ES5 polyfill cannot use for...of + for (var i = 0; i < arguments.length; i++) { + var node = arguments[i]; + if (typeof node !== "object") { + node = this.ownerDocument.createTextNode(String(node)); + } else if (node.parentNode) { + node.parentNode.removeChild(node); + } + this.appendChild(node); + } + }, + }); + }); +})([Element.prototype, Document.prototype, DocumentFragment.prototype]); + // polyfill for toggleAttribute (function (arr) { diff --git a/src/lib/remoteStorage.js b/src/lib/remoteStorage.js index acfdd00d5..5185de0ce 100644 --- a/src/lib/remoteStorage.js +++ b/src/lib/remoteStorage.js @@ -6,6 +6,7 @@ import multiPrompt from "dialogs/multiPrompt"; import URLParse from "url-parse"; import helpers from "utils/helpers"; import Url from "utils/Url"; +import { interstitialAd } from "./startAd"; export default { /** @@ -426,9 +427,9 @@ export default { async function loadAd() { if (!helpers.canShowAds()) return; try { - if (!(await window.iad?.isLoaded())) { + if (!(await interstitialAd?.isLoaded())) { toast(strings.loading); - await window.iad.load(); + await interstitialAd?.load(); } } catch (error) { console.warn("Failed to load interstitial ad.", error); diff --git a/src/lib/startAd.js b/src/lib/startAd.js index dadbee960..c0e58a958 100644 --- a/src/lib/startAd.js +++ b/src/lib/startAd.js @@ -1,65 +1,81 @@ -import tag from "html-tag-js"; +import { BannerAd, InterstitialAd } from "plugins/admob/esm"; import config from "./config"; -let adUnitIdBanner = "ca-app-pub-5911839694379275/9157899592"; // Production -let adUnitIdInterstitial = "ca-app-pub-5911839694379275/9570937608"; // Production -let adUnitIdRewarded = "ca-app-pub-5911839694379275/1633667633"; // Production -let initialized = false; +export let adUnitIdBanner = "ca-app-pub-5911839694379275/9157899592"; // Production +export let adUnitIdInterstitial = "ca-app-pub-5911839694379275/9570937608"; // Production +export let adUnitIdRewarded = "ca-app-pub-5911839694379275/1633667633"; // Production +export let initialized = false; + +/** @type {BannerAd} */ +export let bannerAd = null; +/** @type {InterstitialAd} */ +export let interstitialAd = null; export default async function startAd() { if (config.HAS_PRO || typeof admob === "undefined") return; - if (!initialized) { - initialized = true; - - if (BuildInfo.buildType === "debug") { - console.info("!!! Using test ads"); - adUnitIdBanner = "ca-app-pub-3940256099942544/6300978111"; // Test - adUnitIdInterstitial = "ca-app-pub-3940256099942544/1033173712"; // Test - adUnitIdRewarded = "ca-app-pub-3940256099942544/5224354917"; // Test - } + if (window.ANDROID_SDK_INT < 29) { + console.warn("AdMob not supported on this Android version, skipping ads"); + return; } - const consentStatus = await consent.getConsentStatus(); - if (consentStatus === consent.ConsentStatus.Required) { - await consent.requestInfoUpdate(); - } + try { + if (!initialized) { + initialized = true; - const formStatus = await consent.getFormStatus(); - if (formStatus === consent.FormStatus.Available) { - const form = await consent.loadForm(); - form.show(); - } + if (BuildInfo.buildType === "debug") { + console.info("!!! Using test ads"); + adUnitIdBanner = "ca-app-pub-3940256099942544/6300978111"; // Test + adUnitIdInterstitial = "ca-app-pub-3940256099942544/1033173712"; // Test + adUnitIdRewarded = "ca-app-pub-3940256099942544/5224354917"; // Test + } + } - await admob.start(); + const consentStatus = await consent.getConsentStatus(); + if (consentStatus === consent.ConsentStatus.Required) { + await consent.requestInfoUpdate(); + } - const currentHour = new Date().getHours(); - //currentHour >= 22: Covers 10:00 PM to 11:59 PM. - //currentHour < 4: Covers 12:00 AM to 3:59 AM. - const isQuietHours = currentHour >= 22 || currentHour < 4; + const formStatus = await consent.getFormStatus(); + if (formStatus === consent.FormStatus.Available) { + const form = await consent.loadForm(); + form.show(); + } - await admob.configure({ - appMuted: isQuietHours, - appVolume: isQuietHours ? 0.0 : 1.0, - }); + await admob.start(); - const banner = new admob.BannerAd({ - adUnitId: adUnitIdBanner, - position: "bottom", - }); + const currentHour = new Date().getHours(); + const isQuietHours = currentHour >= 22 || currentHour < 4; - const interstitial = new admob.InterstitialAd({ - adUnitId: adUnitIdInterstitial, - }); + await admob.configure({ + appMuted: isQuietHours, + appVolume: isQuietHours ? 0.0 : 1.0, + }); - interstitial.load(); + const banner = new admob.BannerAd({ + adUnitId: adUnitIdBanner, + position: "bottom", + }); + + const interstitial = new admob.InterstitialAd({ + adUnitId: adUnitIdInterstitial, + }); - interstitial.on("dismiss", () => { interstitial.load(); - }); - window.ad = banner; - window.iad = interstitial; - window.adRewardedUnitId = adUnitIdRewarded; + + interstitial.on("dismiss", () => { + interstitial.load(); + }); + + bannerAd = banner; + interstitialAd = interstitial; + window.ad = banner; + window.iad = interstitial; + window.adRewardedUnitId = adUnitIdRewarded; + } catch (error) { + console.error("Failed to initialize ads:", error); + initialized = false; + } } /** @@ -67,14 +83,13 @@ export default async function startAd() { * @param {Boolean} [force=false] */ export function hideAd(force = false) { - const { ad } = window; - if (ad?.active && typeof ad.hide === "function") { - const $pages = tag.getAll(".page-replacement"); - const hide = $pages.length === 1; - - if (force || hide) { - ad.active = false; - ad.hide(); - } + if (!bannerAd?.active || typeof bannerAd.hide !== "function") return; + + const $pages = tag.getAll(".page-replacement"); + const hide = $pages.length === 1; + + if (force || hide) { + bannerAd.active = false; + bannerAd.hide(); } } diff --git a/src/main.js b/src/main.js index 3f0fcf543..33b2fab5f 100644 --- a/src/main.js +++ b/src/main.js @@ -217,6 +217,7 @@ async function onDeviceReady() { const { versionCode } = BuildInfo; if ( + previousVersionCode != null && !Number.isNaN(previousVersionCode) && previousVersionCode !== versionCode ) { diff --git a/src/main.scss b/src/main.scss index eab98f5d9..1e1216240 100644 --- a/src/main.scss +++ b/src/main.scss @@ -792,6 +792,13 @@ input[type="search"]::-webkit-search-results-decoration { } } + @supports not (gap: 1px) { + > * + * { margin-top: 8px; } + .notification-toast { + > * + * { margin-left: 12px; } + } + } + @media (max-width: 768px) { align-items: stretch; diff --git a/src/pages/about/about.scss b/src/pages/about/about.scss index 6b66771e0..8b19263a7 100644 --- a/src/pages/about/about.scss +++ b/src/pages/about/about.scss @@ -114,6 +114,11 @@ } } + @supports not (gap: 1px) { + > * + * { margin-top: 24px; } + .social-links > * { margin-right: 12px; margin-bottom: 12px; } + } + .icon { height: 100%; width: 100%; diff --git a/src/pages/adRewards/adRewards.scss b/src/pages/adRewards/adRewards.scss index 977d5c551..caadfa1f6 100644 --- a/src/pages/adRewards/adRewards.scss +++ b/src/pages/adRewards/adRewards.scss @@ -242,6 +242,14 @@ } } + @supports not (gap: 1px) { + .reward-status > * + * { margin-left: 12px; } + .reward-grid > * { margin-right: 10px; margin-bottom: 10px; } + .reward-offer > * + * { margin-top: 8px; } + .offer-header > * + * { margin-left: 8px; } + .reward-notes > * + * { margin-top: 10px; } + } + @media (max-width: 400px) { #ad-rewards-page .reward-grid { grid-template-columns: 1fr; diff --git a/src/pages/changelog/style.scss b/src/pages/changelog/style.scss index e5bc0ddf8..a7827d3ce 100644 --- a/src/pages/changelog/style.scss +++ b/src/pages/changelog/style.scss @@ -23,7 +23,11 @@ } } -.status-indicator { + @supports not (gap: 1px) { + .changelog-version-selector > * + * { margin-left: 8px; } + } + + .status-indicator { display: inline-block; width: 8px; height: 8px; diff --git a/src/pages/fileBrowser/fileBrowser.scss b/src/pages/fileBrowser/fileBrowser.scss index 2812d035c..8e64a9622 100644 --- a/src/pages/fileBrowser/fileBrowser.scss +++ b/src/pages/fileBrowser/fileBrowser.scss @@ -120,6 +120,10 @@ z-index: 1; gap: 10px; + @supports not (gap: 1px) { + > * + * { margin-left: 10px; } + } + .selection-count { font-size: 0.9em; } diff --git a/src/pages/fontManager/style.scss b/src/pages/fontManager/style.scss index d67e1b0ab..b3f25a635 100644 --- a/src/pages/fontManager/style.scss +++ b/src/pages/fontManager/style.scss @@ -112,7 +112,15 @@ wc-page.font-manager-page { font-weight: 700; } - @media screen and (min-width: 768px) { + @supports not (gap: 1px) { + .font-manager-list > .list-item { + > * + * { margin-left: 0.85rem; } + > .container > * + * { margin-top: 0.24rem; } + > .setting-tail > * + * { margin-left: 0.65rem; } + } + } + + @media screen and (min-width: 768px) { .font-manager-list { padding-left: 0.5rem; padding-right: 0.5rem; diff --git a/src/pages/markdownPreview/style.scss b/src/pages/markdownPreview/style.scss index 53dfd9a99..4e666c17f 100644 --- a/src/pages/markdownPreview/style.scss +++ b/src/pages/markdownPreview/style.scss @@ -108,6 +108,10 @@ color: var(--primary-text-color) !important; } + @supports not (gap: 1px) { + section.eqno > * + * { margin-left: 12px; } + } + .mermaid-error { border: 1px solid var(--danger-color); border-radius: 8px; diff --git a/src/pages/plugin/plugin.js b/src/pages/plugin/plugin.js index 165460284..bbb32ad8c 100644 --- a/src/pages/plugin/plugin.js +++ b/src/pages/plugin/plugin.js @@ -12,7 +12,7 @@ import customTab from "lib/customTab"; import installPlugin from "lib/installPlugin"; import InstallState from "lib/installState"; import settings from "lib/settings"; -import { hideAd } from "lib/startAd"; +import { hideAd, interstitialAd } from "lib/startAd"; import markdownIt from "markdown-it"; import anchor from "markdown-it-anchor"; import markdownItFootnote from "markdown-it-footnote"; @@ -563,10 +563,10 @@ export default async function PluginInclude( async function loadAd(el) { if (!helpers.canShowAds()) return; try { - if (!(await window.iad?.isLoaded())) { + if (!(await interstitialAd?.isLoaded())) { const oldText = el.textContent; el.textContent = strings["loading..."]; - await window.iad.load(); + await interstitialAd?.load(); el.textContent = oldText; } } catch (error) { diff --git a/src/pages/plugin/plugin.scss b/src/pages/plugin/plugin.scss index 2b6c2656b..84abb2aa1 100644 --- a/src/pages/plugin/plugin.scss +++ b/src/pages/plugin/plugin.scss @@ -357,6 +357,28 @@ } } + @supports not (gap: 1px) { + .plugin-header > * { + margin-right: 20px; + margin-bottom: 20px; + } + .plugin-header > *:last-child { + margin-right: 0; + margin-bottom: 0; + } + .title-wrapper > * + * { margin-left: 16px; } + .source-indicator > * + * { margin-left: 6px; } + .plugin-meta > * + * { margin-left: 16px; } + .meta-item > * + * { margin-left: 4px; } + .metrics-row > * + * { margin-left: 16px; } + .metric > * + * { margin-left: 4px; } + .keywords > * + * { margin-left: 6px; } + .action-buttons > * + * { margin-left: 8px; } + .info:not(.icon) > * + * { margin-left: 5px; } + .btn > * + * { margin-left: 6px; } + .contributor > * + * { margin-left: 12px; } + } + @media (max-width: 768px) { .plugin-header { grid-template-columns: 1fr; diff --git a/src/pages/plugin/plugin.view.js b/src/pages/plugin/plugin.view.js index b02f1a05a..658cee44f 100644 --- a/src/pages/plugin/plugin.view.js +++ b/src/pages/plugin/plugin.view.js @@ -157,7 +157,7 @@ export default (props) => {
= 80 ? "rating-high" : rating.replace("%", "") >= 50 ? "" : "rating-low"}`} + className={`rating-value ${rating === "unrated" ? "" : rating.replace("%", "") >= 80 ? "rating-high" : rating.replace("%", "") >= 50 ? "rating-medium" : "rating-low"}`} > {rating} diff --git a/src/pages/plugins/plugins.scss b/src/pages/plugins/plugins.scss index d8b3635aa..37860ddbb 100644 --- a/src/pages/plugins/plugins.scss +++ b/src/pages/plugins/plugins.scss @@ -293,6 +293,15 @@ box-shadow 180ms ease; } + @supports not (gap: 1px) { + .plugin-header > * + * { margin-left: 0.75rem; } + .plugin-info > * + * { margin-left: 0.75rem; } + .plugin-title > * + * { margin-left: 0.75rem; } + .plugin-meta > * + * { margin-left: 0.5rem; } + .plugin-stats > * + * { margin-left: 0.375rem; } + .plugin-price > * + * { margin-left: 0.25rem; } + } + .plugin-toggle-switch[data-enabled="true"] .plugin-toggle-thumb, .plugin-toggle-track[data-enabled="true"] .plugin-toggle-thumb { transform: translateX(1.12rem); diff --git a/src/pages/quickTools/style.scss b/src/pages/quickTools/style.scss index 674a19326..4503198c4 100644 --- a/src/pages/quickTools/style.scss +++ b/src/pages/quickTools/style.scss @@ -128,6 +128,10 @@ } } + @supports not (gap: 1px) { + .quicktools-grid > * { margin-right: 8px; margin-bottom: 8px; } + } + .tool-ghost { position: fixed; top: 0; diff --git a/src/pages/sponsor/style.scss b/src/pages/sponsor/style.scss index b1e538c38..dc2c16f7d 100644 --- a/src/pages/sponsor/style.scss +++ b/src/pages/sponsor/style.scss @@ -106,6 +106,10 @@ line-height: 1.4; } + @supports not (gap: 1px) { + .tier-header > * + * { margin-left: 0.5rem; } + } + .purchase-btn { background: var(--button-background-color); color: var(--button-text-color); diff --git a/src/pages/sponsors/style.scss b/src/pages/sponsors/style.scss index eb5f6ab89..60d778430 100644 --- a/src/pages/sponsors/style.scss +++ b/src/pages/sponsors/style.scss @@ -95,6 +95,10 @@ } } + @supports not (gap: 1px) { + .sponsors > * { margin-right: 1rem; margin-bottom: 1rem; } + } + .sponsor-card { flex-grow: 1; min-width: 150px; diff --git a/src/pages/themeSetting/themeSetting.scss b/src/pages/themeSetting/themeSetting.scss index d89b7ad7e..789edbb5b 100644 --- a/src/pages/themeSetting/themeSetting.scss +++ b/src/pages/themeSetting/themeSetting.scss @@ -31,6 +31,7 @@ display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 0.72fr); grid-template-rows: repeat(2, minmax(0, 1fr)); + gap: 1px; width: 1.5rem; min-width: 1.5rem; height: 1.5rem; @@ -52,4 +53,17 @@ .theme-swatch-main { grid-row: 1 / 3; } + + @supports not (gap: 1px) { + .theme-swatch-main { + margin-right: 1px; + } + .theme-swatch:nth-child(2) { + margin-left: 1px; + margin-bottom: 1px; + } + .theme-swatch:nth-child(3) { + margin-left: 1px; + } + } } diff --git a/src/pages/welcome/welcome.scss b/src/pages/welcome/welcome.scss index ae94a415d..5a1a95840 100644 --- a/src/pages/welcome/welcome.scss +++ b/src/pages/welcome/welcome.scss @@ -148,6 +148,14 @@ } } + @supports not (gap: 1px) { + .welcome-header > * + * { margin-left: 16px; } + .action-list > * + * { margin-top: 2px; } + .action-row > * + * { margin-left: 12px; } + .link-row > * { margin-right: 8px; margin-bottom: 8px; } + .link-item > * + * { margin-left: 8px; } + } + // Responsive adjustments for smaller screens @media (max-width: 360px) { #welcome-tab { diff --git a/src/plugins/admob/src/android/cordova/ads/Banner.kt b/src/plugins/admob/src/android/cordova/ads/Banner.kt index aea50f96b..57460f2b8 100644 --- a/src/plugins/admob/src/android/cordova/ads/Banner.kt +++ b/src/plugins/admob/src/android/cordova/ads/Banner.kt @@ -4,7 +4,6 @@ import admob.plus.cordova.Events import admob.plus.cordova.ExecuteContext import admob.plus.core.buildAdSize import admob.plus.core.pxToDp -import android.annotation.SuppressLint import android.content.res.Configuration import android.util.Log import android.view.Gravity @@ -12,7 +11,6 @@ import android.view.View import android.view.ViewGroup import android.view.ViewTreeObserver import android.widget.FrameLayout -import android.widget.LinearLayout import android.widget.RelativeLayout import com.google.android.gms.ads.AdListener import com.google.android.gms.ads.AdSize @@ -24,6 +22,7 @@ enum class AdSizeType { BANNER, LARGE_BANNER, MEDIUM_RECTANGLE, FULL_BANNER, LEADERBOARD, SMART_BANNER; companion object { + @Suppress("DEPRECATION") fun getAdSize(adSize: Int): AdSize? { return when (values()[adSize]) { BANNER -> AdSize.BANNER @@ -32,7 +31,6 @@ enum class AdSizeType { FULL_BANNER -> AdSize.FULL_BANNER LEADERBOARD -> AdSize.LEADERBOARD SMART_BANNER -> AdSize.SMART_BANNER - else -> null } } } @@ -131,12 +129,9 @@ class Banner(ctx: ExecuteContext) : AdBase(ctx) { } else if (mAdView!!.visibility == View.GONE) { mAdView!!.resume() mAdView!!.visibility = View.VISIBLE - } else { + // Re-apply bottom margin in case it was reset by hide() val wvParentView = getParentView(webView) - if (rootLinearLayout !== wvParentView && webViewWrapper !== wvParentView) { - removeFromParentView(rootLinearLayout) - addBannerView() - } + setBottomMargin(wvParentView) } ctx.resolve() } @@ -145,6 +140,8 @@ class Banner(ctx: ExecuteContext) : AdBase(ctx) { if (mAdView != null) { mAdView!!.pause() mAdView!!.visibility = View.GONE + val wvParentView = getParentView(webView) + resetBottomMargin(wvParentView) } ctx.resolve() } @@ -215,63 +212,34 @@ class Banner(ctx: ExecuteContext) : AdBase(ctx) { private fun addBannerView() { if (mAdView == null) return if (offset == null) { - if (getParentView(mAdView) === rootLinearLayout && rootLinearLayout != null) return + if (getParentView(mAdView) === plugin.contentView && plugin.contentView != null) return addBannerViewWithLinearLayout() } else { if (getParentView(mAdView) === mRelativeLayout && mRelativeLayout != null) return addBannerViewWithRelativeLayout() } plugin.contentView?.let { - it.bringToFront() it.requestLayout() - it.requestFocus() } } private fun addBannerViewWithLinearLayout() { val wvParentView = getParentView(webView) - if (rootLinearLayout == null) { - rootLinearLayout = LinearLayout(plugin.activity) - } - if (wvParentView != null && wvParentView !== rootLinearLayout && wvParentView !== webViewWrapper) { - if (webViewWrapper == null) { - webViewWrapper = FrameLayout(plugin.activity) - } else { - removeFromParentView(webViewWrapper) - } - wvParentView.removeView(webView) - val content = rootLinearLayout as LinearLayout? - content!!.orientation = LinearLayout.VERTICAL - rootLinearLayout!!.layoutParams = LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT, - 0.0f - ) - webViewWrapper!!.layoutParams = LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, + if (wvParentView == null) return + // Keep the WebView in its original parent. Add the banner to + // contentView as a bottom-aligned sibling and push the WebView's + // parent up via bottom margin — no removeView/reparent needed. + removeFromParentView(mAdView) + val content = plugin.contentView + if (content is FrameLayout) { + val bannerParams = FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, - 1.0f + ViewGroup.LayoutParams.WRAP_CONTENT, + Gravity.BOTTOM ) - webViewWrapper!!.addView(webView) - rootLinearLayout!!.addView(webViewWrapper) - val view = getParentView(rootLinearLayout) - if (view !== wvParentView) { - removeFromParentView(rootLinearLayout) - wvParentView.addView(rootLinearLayout) - } - } - removeFromParentView(mAdView) - if (isPositionTop) { - rootLinearLayout!!.addView(mAdView, 0) - } else { - rootLinearLayout!!.addView(mAdView) - } - plugin.contentView?.let { - for (i in 0 until it.childCount) { - val view = it.getChildAt(i) - (view as? RelativeLayout)?.bringToFront() - } + content.addView(mAdView, bannerParams) } + setBottomMargin(wvParentView) } private fun addBannerViewWithRelativeLayout() { @@ -302,24 +270,25 @@ class Banner(ctx: ExecuteContext) : AdBase(ctx) { private val isPositionTop: Boolean get() = gravity == Gravity.TOP + private fun setBottomMargin(view: View?) { + val lp = view?.layoutParams as? FrameLayout.LayoutParams ?: return + lp.bottomMargin = adSize.getHeightInPixels(plugin.activity) + view.layoutParams = lp + } + + private fun resetBottomMargin(view: View?) { + val lp = view?.layoutParams as? FrameLayout.LayoutParams ?: return + if (lp.bottomMargin > 0) { + lp.bottomMargin = 0 + view.layoutParams = lp + } + } + companion object { private const val TAG = "AdMobPlus.Banner" - @SuppressLint("StaticFieldLeak") - private var rootLinearLayout: ViewGroup? = null - @SuppressLint("StaticFieldLeak") - private var webViewWrapper: FrameLayout? = null private var screenWidth = 0 - fun destroyParentView() { - try { - webViewWrapper?.removeAllViews() - webViewWrapper = null - val vg = getParentView(rootLinearLayout) - vg?.removeAllViews() - } finally { - rootLinearLayout = null - } - } + fun destroyParentView() {} private fun runJustBeforeBeingDrawn(view: View, runnable: Runnable) { val preDrawListener: ViewTreeObserver.OnPreDrawListener = diff --git a/src/plugins/admob/src/android/core/util.kt b/src/plugins/admob/src/android/core/util.kt index 10c616431..3b912dd7d 100644 --- a/src/plugins/admob/src/android/core/util.kt +++ b/src/plugins/admob/src/android/core/util.kt @@ -22,11 +22,11 @@ import kotlin.math.roundToInt fun buildAdRequest(opts: JSONObject): AdRequest { val builder = AdRequest.Builder() - opts.optString("contentUrl", null)?.let { + opts.optString("contentUrl", null as String?)?.let { builder.setContentUrl(it) } val extras = Bundle().apply { - opts.optString("npa", null)?.let { npa -> + opts.optString("npa", null as String?)?.let { npa -> putString("npa", npa) } } @@ -36,11 +36,13 @@ fun buildAdRequest(opts: JSONObject): AdRequest { fun buildAdSize(opts: JSONObject, activity: Activity): AdSize { val name = "size" if (!opts.has(name)) { + @Suppress("DEPRECATION") return AdSize.SMART_BANNER } val adSizeObj = opts.optJSONObject(name) val adSize = AdSizeType.getAdSize(opts.optInt(name)) if (adSizeObj == null) { + @Suppress("DEPRECATION") return adSize ?: AdSize.SMART_BANNER } val adaptive = adSizeObj.optString("adaptive") @@ -84,7 +86,7 @@ fun optFloat(opts: JSONObject, name: String): Float? { fun buildRequestConfiguration(opts: JSONObject): RequestConfiguration { val builder = RequestConfiguration.Builder() - opts.optString("maxAdContentRating", null)?.let { + opts.optString("maxAdContentRating", null as String?)?.let { builder.setMaxAdContentRating(it) } optBooleanToInt( diff --git a/src/plugins/system/www/plugin.js b/src/plugins/system/www/plugin.js index 519b4f988..e5b26da07 100644 --- a/src/plugins/system/www/plugin.js +++ b/src/plugins/system/www/plugin.js @@ -222,7 +222,7 @@ module.exports = { onFail, 'System', 'set-native-context-menu-disabled', - [String(!!disabled)], + [String(!!disabled)] ); }, getGlobalSetting: function (key, onSuccess, onFail) { diff --git a/src/sidebarApps/extensions/index.js b/src/sidebarApps/extensions/index.js index c59d9063c..07e14cc8a 100644 --- a/src/sidebarApps/extensions/index.js +++ b/src/sidebarApps/extensions/index.js @@ -11,6 +11,7 @@ import config from "lib/config"; import InstallState from "lib/installState"; import loadPlugin from "lib/loadPlugin"; import settings from "lib/settings"; +import { interstitialAd } from "lib/startAd"; import FileBrowser from "pages/fileBrowser"; import plugin from "pages/plugin"; import helpers from "utils/helpers"; @@ -861,10 +862,10 @@ function ListItem({ async function loadAd(el) { if (!helpers.canShowAds()) return; try { - if (!(await window.iad?.isLoaded())) { + if (!(await interstitialAd?.isLoaded())) { const oldText = el.textContent; el.textContent = strings["loading..."]; - await window.iad.load(); + await interstitialAd?.load(); el.textContent = oldText; } } catch (error) { diff --git a/src/sidebarApps/extensions/style.scss b/src/sidebarApps/extensions/style.scss index 18d79cfde..c123b8dc1 100644 --- a/src/sidebarApps/extensions/style.scss +++ b/src/sidebarApps/extensions/style.scss @@ -1,7 +1,33 @@ @use "../../styles/mixins.scss"; .container.extensions { + display: flex; + flex-direction: column; + overflow: hidden; + + .list.collapsible { + display: flex; + flex-direction: column; + overflow: hidden; + + &:not(.hidden) { + flex: 1; + min-height: 0; + } + + &.hidden { + flex-shrink: 0; + } + + >ul { + flex: 1; + min-height: 0; + overflow-y: auto; + } + } + .header { + flex-shrink: 0; padding: 10px; display: flex; flex-direction: column; @@ -67,7 +93,12 @@ } .list.search-result { - min-height: 0; + flex-shrink: 0; + overflow-y: auto; + + &:empty { + display: none + } &.loading { @include mixins.loader(20px); diff --git a/src/sidebarApps/notification/style.scss b/src/sidebarApps/notification/style.scss index 1ca2e0866..fa2a4db4b 100644 --- a/src/sidebarApps/notification/style.scss +++ b/src/sidebarApps/notification/style.scss @@ -154,6 +154,13 @@ } +@supports not (gap: 1px) { + .title > * + * { margin-left: 4px; } + .notifications-container > * + * { margin-top: 8px; } + .notification-item > * + * { margin-left: 10px; } + .action-button > * + * { margin-left: 4px; } +} + @keyframes slideIn { from { transform: translateX(100%); diff --git a/src/styles/codemirror.scss b/src/styles/codemirror.scss index 972b38cf9..f0321b160 100644 --- a/src/styles/codemirror.scss +++ b/src/styles/codemirror.scss @@ -92,6 +92,13 @@ overflow: auto; } +@supports not (gap: 1px) { + .cm-tooltip.cm-tooltip-autocomplete { + > * + * { margin-left: 0.4rem; } + > ul > li > * + * { margin-left: 0.12rem; } + } +} + @media (max-width: 480px) { .cm-tooltip { font-size: 0.9rem; diff --git a/src/styles/fileInfo.scss b/src/styles/fileInfo.scss index 9b3bc2397..c03f9343e 100644 --- a/src/styles/fileInfo.scss +++ b/src/styles/fileInfo.scss @@ -83,6 +83,12 @@ } } + @supports not (gap: 1px) { + .file-name > * + * { margin-left: 0.5rem; } + .info-grid > * { margin-right: 1.5rem; margin-bottom: 1.5rem; } + .info-item > * + * { margin-top: 0.5rem; } + } + @media (max-width: 480px) { .file-card { padding: 1.5rem; diff --git a/src/styles/wideScreen.scss b/src/styles/wideScreen.scss index ea12e7844..5d07be586 100644 --- a/src/styles/wideScreen.scss +++ b/src/styles/wideScreen.scss @@ -161,6 +161,15 @@ } #plugin { + @supports not (gap: 1px) { + .plugin-header > * { margin-right: 1.25rem; margin-bottom: 1.25rem; } + .plugin-header > *:last-child { margin-right: 0; margin-bottom: 0; } + .plugin-info > * + * { margin-left: 1.25rem; } + .plugin-title > * + * { margin-left: 1rem; } + .plugin-meta > * + * { margin-left: 0.75rem; } + .plugin-stats > * + * { margin-left: 0.5rem; } + } + .list-item { margin: 0 1rem 0.75rem 1rem; padding: 1.25rem; diff --git a/src/utils/helpers.js b/src/utils/helpers.js index ddea27fb4..d3175b225 100644 --- a/src/utils/helpers.js +++ b/src/utils/helpers.js @@ -4,6 +4,7 @@ import alert from "dialogs/alert"; import escapeStringRegexp from "escape-string-regexp"; import adRewards from "lib/adRewards"; import config from "lib/config"; +import { bannerAd, interstitialAd } from "lib/startAd"; import path from "./Path"; import Uri from "./Uri"; import Url from "./Url"; @@ -293,11 +294,11 @@ export default { async showInterstitialIfReady() { if (!this.canShowAds()) return false; if ( - typeof window.iad?.isLoaded === "function" && - typeof window.iad?.show === "function" && - (await window.iad.isLoaded()) + typeof interstitialAd?.isLoaded === "function" && + typeof interstitialAd?.show === "function" && + (await interstitialAd?.isLoaded()) ) { - window.iad.show(); + interstitialAd.show(); return true; } return false; @@ -306,17 +307,14 @@ export default { * Displays ad on the current page */ showAd() { - const { ad } = window; - if ( - this.canShowAds() && - innerHeight * devicePixelRatio > 600 && - typeof ad?.show === "function" - ) { - const $page = tag.getAll("wc-page:not(#root)").pop(); - if ($page) { - ad.active = true; - ad.show(); - } + if (!this.canShowAds()) return; + if (innerHeight * devicePixelRatio <= 600) return; + if (!bannerAd || typeof bannerAd.show !== "function") return; + + const $page = tag.getAll("wc-page:not(#root)").pop(); + if ($page) { + bannerAd.active = true; + bannerAd.show(); } }, async toInternalUri(uri) { diff --git a/www/index.html b/www/index.html index 7802e3a00..07f170909 100644 --- a/www/index.html +++ b/www/index.html @@ -1,195 +1,207 @@ - - - - - - + + + + window.addEventListener("error", handleStartupError); + window.addEventListener("unhandledrejection", handleStartupRejection); + })(); + - - + + - + - Acode - + Acode + - -
-
-
-
+ +
+
+
+
- + - - + }); + + +