diff --git a/rspack.config.js b/rspack.config.js index 4cf1ebf9a..c8e64e72d 100644 --- a/rspack.config.js +++ b/rspack.config.js @@ -94,10 +94,15 @@ module.exports = (env, options) => { resourceQuery: /raw/, type: 'asset/source', }, + { + test: /\.(png|svg|jpg|jpeg|ico|webp)(\?.*)?$/, + resourceQuery: /inline/, + type: 'asset/inline', + }, // Asset files { test: /\.(png|svg|jpg|jpeg|ico|ttf|webp|eot|woff|webm|mp4|wav)(\?.*)?$/, - resourceQuery: { not: [/raw/] }, + resourceQuery: { not: [/raw/, /inline/] }, type: 'asset/resource', }, // Regular CSS/SCSS files diff --git a/src/components/logo/style.scss b/src/components/logo/style.scss index 90f9f8a3c..01568da03 100644 --- a/src/components/logo/style.scss +++ b/src/components/logo/style.scss @@ -6,7 +6,7 @@ margin: 0 auto; &::after { - content: ''; + content: ""; position: absolute; top: 0; left: 0; @@ -19,13 +19,19 @@ } &::before { - content: ''; + content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; - background: radial-gradient(circle, rgb(68, 153, 254, 0.5), rgb(68, 153, 254, 0.1), rgb(68, 153, 254, 0), rgb(68, 153, 254, 0)); + background: radial-gradient( + circle, + rgb(68, 153, 254, 0.5), + rgb(68, 153, 254, 0.1), + rgb(68, 153, 254, 0), + rgb(68, 153, 254, 0) + ); overflow: visible; } -} \ No newline at end of file +} diff --git a/src/dialogs/style.scss b/src/dialogs/style.scss index 2db23f2bb..d6a6f14cd 100644 --- a/src/dialogs/style.scss +++ b/src/dialogs/style.scss @@ -104,12 +104,12 @@ } } - &+.mask { + & + .mask { z-index: 111; background-color: rgb(0, 0, 0); opacity: 0.4; - ~.mask { + ~ .mask { opacity: 0; } } @@ -119,7 +119,7 @@ transform: translate(-50%, -50%) scale(0.95) translateZ(0); opacity: 0; - &+.mask { + & + .mask { opacity: 0; } } @@ -212,7 +212,10 @@ user-select: none; color: var(--popup-text-color, #333); opacity: 0.5; - transition: opacity 0.15s, background-color 0.15s, color 0.15s; + transition: + opacity 0.15s, + background-color 0.15s, + color 0.15s; &:hover { opacity: 0.8; @@ -283,13 +286,13 @@ align-items: center; .loader { - width: 30px; - height: 30px; + width: 24px; + height: 24px; color: rgb(153, 153, 255); - color: var(--primary-color); + color: var(--popup-active-color); display: flex; flex-shrink: 0; - margin: 0 10px; + margin-left: 10px; svg { width: 100%; diff --git a/src/lib/languageModeRecommendations.js b/src/lib/languageModeRecommendations.js index 48143e177..d534e2bf1 100644 --- a/src/lib/languageModeRecommendations.js +++ b/src/lib/languageModeRecommendations.js @@ -11,15 +11,16 @@ function withSupportedEditor(url) { return `${url}${separator}supported_editor=${config.SUPPORTED_EDITOR}`; } -function getSearchKeyword(filename) { - const ext = Path.extname(filename || "") - .replace(/^\./, "") +export function getLanguageModeRecommendationSearchKeyword(filename) { + const basename = Path.basename(filename || "") .trim() .toLowerCase(); + const ext = Path.extname(basename).replace(/^\./, "").trim().toLowerCase(); + const keyword = ext || (basename.startsWith(".") ? basename.slice(1) : ""); - if (!/^[a-z0-9][a-z0-9._+-]*$/.test(ext)) return ""; + if (!/^[a-z0-9][a-z0-9._+-]*$/.test(keyword)) return ""; - return ext; + return keyword; } function getIssueUrl(keyword) { @@ -89,7 +90,7 @@ class LanguageModeRecommendations { const filename = file.filename || ""; if (!hasPlainTextFallback(modeInfo, filename)) return; - const keyword = getSearchKeyword(filename); + const keyword = getLanguageModeRecommendationSearchKeyword(filename); if ( !keyword || this.notifiedKeywords.has(keyword) || diff --git a/src/pages/welcome/welcome.js b/src/pages/welcome/welcome.js index d3958fd1e..6bccb37a5 100644 --- a/src/pages/welcome/welcome.js +++ b/src/pages/welcome/welcome.js @@ -1,5 +1,5 @@ import { getResolvedKeyBindings } from "cm/commandRegistry"; -import Logo from "components/logo"; +import logoSrc from "components/logo/logo.png?inline"; import config from "lib/config"; import EditorFile from "lib/editorFile"; @@ -44,7 +44,7 @@ function createWelcomeContent() {
{/* Hero Section */}
- +

Welcome to Acode

Powerful code editor for Android

diff --git a/src/pages/welcome/welcome.scss b/src/pages/welcome/welcome.scss index 5a1a95840..36e7f2c98 100644 --- a/src/pages/welcome/welcome.scss +++ b/src/pages/welcome/welcome.scss @@ -1,232 +1,242 @@ #welcome-tab { + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + min-height: 100%; + height: auto; + padding: 32px 24px; + overflow-y: auto; + overflow-x: hidden; + background-color: var(--secondary-color); + + // Hero Header + .welcome-header { + display: flex; + align-items: center; + gap: 16px; + margin-bottom: 48px; + + .logo { + width: 48px; + height: auto; + max-height: 48px; + flex-shrink: 0; + } + + .welcome-header-text { + h1 { + font-size: 20px; + font-weight: 600; + color: var(--primary-text-color); + margin: 0 0 4px 0; + letter-spacing: -0.3px; + } + + .tagline { + font-size: 13px; + color: color-mix(in srgb, var(--secondary-text-color) 60%, transparent); + margin: 0; + } + } + } + + // Section Styles + .welcome-section { + width: 100%; + max-width: 400px; + margin-bottom: 32px; + + .section-label { + font-size: 11px; + font-weight: 600; + letter-spacing: 1px; + color: color-mix(in srgb, var(--secondary-text-color) 50%, transparent); + margin: 0 0 12px 0; + padding-left: 4px; + } + } + + // Action List + .action-list { display: flex; flex-direction: column; + gap: 2px; + } + + .action-row { + display: flex; align-items: center; - justify-content: flex-start; - min-height: 100%; - height: auto; - padding: 32px 24px; - overflow-y: auto; - overflow-x: hidden; - background-color: var(--secondary-color); - - // Hero Header - .welcome-header { - display: flex; - align-items: center; - gap: 16px; - margin-bottom: 48px; - - .logo { - width: 64px; - height: 64px; - flex-shrink: 0; - - &::after { - background-size: 48px; - } - - &::before { - background: radial-gradient(circle, - color-mix(in srgb, var(--button-background-color) 30%, transparent) 0%, - transparent 70%); - } - } - - .welcome-header-text { - h1 { - font-size: 20px; - font-weight: 600; - color: var(--primary-text-color); - margin: 0 0 4px 0; - letter-spacing: -0.3px; - } - - .tagline { - font-size: 13px; - color: color-mix(in srgb, var(--secondary-text-color) 60%, transparent); - margin: 0; - } - } + gap: 12px; + padding: 10px 12px; + border-radius: 6px; + cursor: pointer; + transition: background-color 0.15s ease; + + &:hover, + &:active { + background-color: color-mix( + in srgb, + var(--popup-background-color) 40%, + transparent + ); } - // Section Styles - .welcome-section { - width: 100%; - max-width: 400px; - margin-bottom: 32px; - - .section-label { - font-size: 11px; - font-weight: 600; - letter-spacing: 1px; - color: color-mix(in srgb, var(--secondary-text-color) 50%, transparent); - margin: 0 0 12px 0; - padding-left: 4px; - } + .icon { + font-size: 16px; + color: color-mix(in srgb, var(--secondary-text-color) 70%, transparent); + width: 20px; + text-align: center; } - // Action List - .action-list { - display: flex; - flex-direction: column; - gap: 2px; + .action-label { + flex: 1; + font-size: 14px; + color: var(--secondary-text-color); } - .action-row { - display: flex; - align-items: center; - gap: 12px; - padding: 10px 12px; - border-radius: 6px; - cursor: pointer; - transition: background-color 0.15s ease; - - &:hover, - &:active { - background-color: color-mix(in srgb, var(--popup-background-color) 40%, transparent); - } - - .icon { - font-size: 16px; - color: color-mix(in srgb, var(--secondary-text-color) 70%, transparent); - width: 20px; - text-align: center; - } - - .action-label { - flex: 1; - font-size: 14px; - color: var(--secondary-text-color); - } - - .action-shortcut { - font-size: 12px; - font-family: 'Roboto Mono', monospace; - color: color-mix(in srgb, var(--secondary-text-color) 40%, transparent); - letter-spacing: 0.5px; - } + .action-shortcut { + font-size: 12px; + font-family: "Roboto Mono", monospace; + color: color-mix(in srgb, var(--secondary-text-color) 40%, transparent); + letter-spacing: 0.5px; + } + } + + // Links Section + .welcome-links { + margin-top: 16px; + + .link-row { + display: flex; + flex-wrap: wrap; + gap: 8px; + justify-content: flex-start; } - // Links Section - .welcome-links { - margin-top: 16px; - - .link-row { - display: flex; - flex-wrap: wrap; - gap: 8px; - justify-content: flex-start; - } - - .link-item { - display: inline-flex; - align-items: center; - gap: 8px; - padding: 10px 16px; - border-radius: 8px; - text-decoration: none; - color: var(--secondary-text-color); - font-size: 13px; - font-weight: 500; - transition: all 0.15s ease; - background-color: color-mix(in srgb, var(--popup-background-color) 25%, transparent); - border: 1px solid color-mix(in srgb, var(--border-color) 20%, transparent); - - &:hover, - &:active { - background-color: color-mix(in srgb, var(--popup-background-color) 50%, transparent); - border-color: color-mix(in srgb, var(--border-color) 40%, transparent); - transform: translateY(-1px); - } - - .icon { - font-size: 16px; - color: color-mix(in srgb, var(--secondary-text-color) 80%, transparent); - } - } + .link-item { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 10px 16px; + border-radius: 8px; + text-decoration: none; + color: var(--secondary-text-color); + font-size: 13px; + font-weight: 500; + transition: all 0.15s ease; + background-color: color-mix( + in srgb, + var(--popup-background-color) 25%, + transparent + ); + border: 1px solid color-mix(in srgb, var(--border-color) 20%, transparent); + + &:hover, + &:active { + background-color: color-mix( + in srgb, + var(--popup-background-color) 50%, + transparent + ); + border-color: color-mix(in srgb, var(--border-color) 40%, transparent); + transform: translateY(-1px); + } + + .icon { + font-size: 16px; + color: color-mix(in srgb, var(--secondary-text-color) 80%, transparent); + } } + } } - @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; } +@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 { - padding: 24px 16px; - - .welcome-header { - flex-direction: column; - text-align: center; - margin-bottom: 36px; - - .logo { - width: 56px; - height: 56px; - - &::after { - background-size: 40px; - } - } - - .welcome-header-text h1 { - font-size: 18px; - } - } - - .welcome-section { - margin-bottom: 24px; - } - - .action-row { - padding: 8px 10px; - - .action-label { - font-size: 13px; - } - - .action-shortcut { - font-size: 11px; - } - } - - .welcome-links .link-row { - justify-content: center; - } + #welcome-tab { + padding: 24px 16px; + + .welcome-header { + flex-direction: column; + text-align: center; + margin-bottom: 36px; + + .logo { + width: 40px; + max-height: 40px; + } + + .welcome-header-text h1 { + font-size: 18px; + } + } + + .welcome-section { + margin-bottom: 24px; + } + + .action-row { + padding: 8px 10px; + + .action-label { + font-size: 13px; + } + + .action-shortcut { + font-size: 11px; + } } + + .welcome-links .link-row { + justify-content: center; + } + } } // Larger screens - center content better @media (min-width: 600px) { - #welcome-tab { - .welcome-section { - max-width: 480px; - } - - .action-row { - padding: 12px 16px; - } + #welcome-tab { + .welcome-section { + max-width: 480px; } + + .action-row { + padding: 12px 16px; + } + } } // Discord icon .icon.discord { - position: relative; - - &::before { - content: ''; - display: block; - width: 16px; - height: 16px; - background-image: url(../../pages/about/discord.svg); - background-size: contain; - background-repeat: no-repeat; - background-position: center; - } -} \ No newline at end of file + position: relative; + + &::before { + content: ""; + display: block; + width: 16px; + height: 16px; + background-image: url(../../pages/about/discord.svg); + background-size: contain; + background-repeat: no-repeat; + background-position: center; + } +} diff --git a/src/test/sanity.tests.js b/src/test/sanity.tests.js index 6b5938475..61971c8d9 100644 --- a/src/test/sanity.tests.js +++ b/src/test/sanity.tests.js @@ -1,3 +1,4 @@ +import { getLanguageModeRecommendationSearchKeyword } from "../lib/languageModeRecommendations"; import { TestRunner } from "./tester"; export async function runSanityTests(writeOutput) { @@ -63,6 +64,24 @@ export async function runSanityTests(writeOutput) { test.assert(!(value < 5), "Negation should work"); }); + runner.test("Language mode recommendation keywords", (test) => { + test.assertEqual( + getLanguageModeRecommendationSearchKeyword(".gitignore"), + "gitignore", + "Dotfiles without extensions should use the dotfile name", + ); + test.assertEqual( + getLanguageModeRecommendationSearchKeyword("src/main.js"), + "js", + "Normal files should use the file extension", + ); + test.assertEqual( + getLanguageModeRecommendationSearchKeyword("README"), + "", + "Extensionless non-dotfiles should not request plugin recommendations", + ); + }); + // Run all tests return await runner.run(writeOutput); }