From ce69fc22a9efc824f53eb821fd695b751512f5a1 Mon Sep 17 00:00:00 2001 From: v0 Date: Thu, 10 Sep 2026 23:10:21 +0000 Subject: [PATCH 01/12] Refresh Shipyard visual system and dashboard surfaces --- src/components/LinkItems/Collapsable.vue | 5 +-- src/components/LinkItems/Item.vue | 9 ++--- src/components/LinkItems/ItemIcon.vue | 2 +- src/components/PageStrcture/Header.vue | 10 +++++- src/styles/color-palette.scss | 8 +++++ src/styles/dimensions.scss | 9 ++++- src/styles/global-styles.scss | 44 ++++++++++++++++++----- src/views/Home.vue | 11 ++++-- tests/unit/healthcheck.test.js | 28 +++++++-------- vue.config.js | 46 ++++++++++++------------ 10 files changed, 115 insertions(+), 57 deletions(-) diff --git a/src/components/LinkItems/Collapsable.vue b/src/components/LinkItems/Collapsable.vue index 91131ba..a7341ea 100644 --- a/src/components/LinkItems/Collapsable.vue +++ b/src/components/LinkItems/Collapsable.vue @@ -167,9 +167,10 @@ export default { width: 100%; width: stretch; height: fit-content; - margin: 10px; + margin: 0; padding: var(--item-group-padding); - border-radius: var(--curve-factor); + border-radius: var(--radius-panel, var(--curve-factor)); + border: 1px solid var(--border-subtle, var(--outline-color)); box-shadow: var(--item-group-shadow); background: var(--item-group-outer-background); diff --git a/src/components/LinkItems/Item.vue b/src/components/LinkItems/Item.vue index 5ddc8d8..ec300df 100644 --- a/src/components/LinkItems/Item.vue +++ b/src/components/LinkItems/Item.vue @@ -240,14 +240,15 @@ export default { flex-grow: 1; color: var(--item-text-color); vertical-align: middle; - margin: 0.5rem; + margin: 0; background: var(--item-background); text-align: center; - padding: 2px; + padding: .75rem; outline: 2px solid transparent; border: 1px solid var(--outline-color); - border-radius: var(--curve-factor); - box-shadow: var(--item-shadow); + border-radius: var(--radius-panel, var(--curve-factor)); + border-color: var(--border-subtle, var(--outline-color)); + box-shadow: 0 8px 24px rgba(0, 0, 0, .14); cursor: pointer; text-decoration: none; position: relative; diff --git a/src/components/LinkItems/ItemIcon.vue b/src/components/LinkItems/ItemIcon.vue index 331c408..72396dd 100644 --- a/src/components/LinkItems/ItemIcon.vue +++ b/src/components/LinkItems/ItemIcon.vue @@ -9,4 +9,4 @@ export default { \ No newline at end of file + diff --git a/src/components/PageStrcture/Header.vue b/src/components/PageStrcture/Header.vue index f0d3f96..55378f6 100644 --- a/src/components/PageStrcture/Header.vue +++ b/src/components/PageStrcture/Header.vue @@ -47,14 +47,22 @@ export default { header { margin: 0; - padding: 0.5rem; + min-height: var(--topbar-height); + padding: .75rem var(--space-page); display: flex; justify-content: space-between; + gap: 1rem; background: var(--background-darker); + border-bottom: 1px solid var(--border-subtle, var(--outline-color)); align-items: center; align-content: flex-start; + position: relative; + z-index: 5; @include phone { + min-height: auto; + padding: .75rem 1rem; flex-direction: column-reverse; + align-items: stretch; } } diff --git a/src/styles/color-palette.scss b/src/styles/color-palette.scss index d7c3878..cd6fce3 100644 --- a/src/styles/color-palette.scss +++ b/src/styles/color-palette.scss @@ -5,6 +5,14 @@ --primary: #5cabca; // Main accent color --background: #0b1021; // Page background --background-darker: #05070e; // Used for navigation bar, footer and fills + --surface-1: #11182b; + --surface-2: #17213a; + --surface-3: #202c48; + --text-primary: #eef4ff; + --text-secondary: #9eabc4; + --text-muted: #6f7d98; + --border-subtle: #2a3858; + --focus-ring: #8ce7f2; /* Action Colors */ --info: #04e4f4; diff --git a/src/styles/dimensions.scss b/src/styles/dimensions.scss index f380aaa..99141ea 100644 --- a/src/styles/dimensions.scss +++ b/src/styles/dimensions.scss @@ -4,7 +4,14 @@ --outline-color: none; --curve-factor: 5px; // Border radius for most components --curve-factor-navbar: 16px; // Border radius for header - --curve-factor-small: 2px; // Subtle border radius for util components + --curve-factor-small: 2px; // Subtle border radius for util components + --radius-panel: 12px; + --radius-control: 7px; + --space-page: clamp(1rem, 2vw, 2rem); + --content-max-width: 1440px; + --sidebar-width: 15rem; + --topbar-height: 4.25rem; + --dimming-factor: 0.7; // Opacity for semi-transparent components /* Basic Page Components */ diff --git a/src/styles/global-styles.scss b/src/styles/global-styles.scss index 7b899fc..10fe11d 100644 --- a/src/styles/global-styles.scss +++ b/src/styles/global-styles.scss @@ -3,10 +3,13 @@ @import '@/styles/media-queries.scss'; /* Essential global page layout styles */ -html { - padding: 0; - margin: -3px 0 0 0; - transition: all 1s; +html { + padding: 0; + margin: -3px 0 0 0; + color: var(--text-primary, var(--primary)); + background: var(--background); + transition: background-color .2s ease, color .2s ease; + @extend .scroll-bar; @extend .highlight; box-sizing: border-box; @@ -22,10 +25,35 @@ html { } } -#shipyard { - position: relative; - min-height: 100vh; -} +#shipyard { + position: relative; + min-height: 100vh; + color: var(--text-primary, var(--primary)); +} + +:focus-visible { + outline: 2px solid var(--focus-ring, var(--primary)); + outline-offset: 3px; +} + +::selection { + color: var(--highlight-color, var(--background)); + background: var(--highlight-background, var(--primary)); +} + +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + scroll-behavior: auto !important; + transition-duration: .01ms !important; + animation-duration: .01ms !important; + animation-iteration-count: 1 !important; + } +} + +@media (max-width: 640px) { + html { font-size: .9375rem; } +} + /* Hide text, and show 'Loading...' while Vue is initializing tags */ [v-cloak] > * { display:none } diff --git a/src/views/Home.vue b/src/views/Home.vue index ca73a8b..798c2ec 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -204,11 +204,16 @@ export default { @import '@/styles/style-helpers.scss'; .home { - padding-bottom: 1px; + padding: 0 var(--space-page) 3rem; background: var(--background); min-height: calc(99.9vh - var(--footer-height)); } +.home :deep(.settings-outer) { + max-width: var(--content-max-width); + margin: 0 auto 1.25rem; +} + .back-to-all-link { display: flex; align-items: center; @@ -222,9 +227,9 @@ export default { /* Outside container wrapping the item groups*/ .item-group-container { display: grid; - gap: 0.5rem; + gap: 1rem; margin: 0 auto; - max-width: 90%; + max-width: var(--content-max-width); overflow: auto; @extend .scroll-bar; @include monitor-up { diff --git a/tests/unit/healthcheck.test.js b/tests/unit/healthcheck.test.js index 189230e..0a73716 100644 --- a/tests/unit/healthcheck.test.js +++ b/tests/unit/healthcheck.test.js @@ -1,24 +1,24 @@ -import { describe, it, expect } from 'vitest' -import fs from 'fs' -import path from 'path' -import { fileURLToPath } from 'url' +import { describe, it, expect } from 'vitest'; +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; -const __dirname = path.dirname(__filename) +const __dirname = path.dirname(__filename); describe('Healthcheck Service', () => { const healthcheckPath = path.resolve( __dirname, - '../../services/healthcheck.js' - ) + '../../services/healthcheck.js', + ); it('healthcheck script exists', () => { - expect(fs.existsSync(healthcheckPath)).toBe(true) - }) + expect(fs.existsSync(healthcheckPath)).toBe(true); + }); it('healthcheck file has correct structure', () => { - const content = fs.readFileSync(healthcheckPath, 'utf8') + const content = fs.readFileSync(healthcheckPath, 'utf8'); - expect(content).toContain('healthCheck') - expect(content).toContain('http.request') - }) -}) + expect(content).toContain('healthCheck'); + expect(content).toContain('http.request'); + }); +}); diff --git a/vue.config.js b/vue.config.js index d13a754..45c41d2 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,23 +1,23 @@ -const path = require('path') -const CopyWebpackPlugin = require('copy-webpack-plugin') +const path = require('path'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); -const mode = process.env.NODE_ENV || 'production' +const mode = process.env.NODE_ENV || 'production'; -process.env.VUE_APP_VERSION = require('./package.json').version +process.env.VUE_APP_VERSION = require('./package.json').version; -const { pwa } = require('./src/utils/defaults') +const { pwa } = require('./src/utils/defaults'); -const publicPath = process.env.BASE_URL || '/' -const integrity = process.env.INTEGRITY === 'true' -const isServer = process.env.IS_DOCKER || process.env.IS_SERVER || false +const publicPath = process.env.BASE_URL || '/'; +const integrity = process.env.INTEGRITY === 'true'; +const isServer = process.env.IS_DOCKER || process.env.IS_SERVER || false; const plugins = !isServer ? [ - new CopyWebpackPlugin({ - patterns: [{ from: './user-data', to: './' }], - }), - ] - : [] + new CopyWebpackPlugin({ + patterns: [{ from: './user-data', to: './' }], + }), + ] + : []; const configureWebpack = { devtool: 'source-map', @@ -47,12 +47,12 @@ const configureWebpack = { maxEntrypointSize: 10000000, maxAssetSize: 10000000, }, -} +}; const userDataDir = path.join( __dirname, - process.env.USER_DATA_DIR || 'user-data' -) + process.env.USER_DATA_DIR || 'user-data', +); const devServer = { static: { @@ -61,14 +61,14 @@ const devServer = { watchFiles: { paths: [userDataDir], }, -} +}; const pages = { index: { entry: 'src/main.js', filename: 'index.html', }, -} +}; module.exports = { publicPath, @@ -81,13 +81,13 @@ module.exports = { chainWebpack: config => { config.plugin('eslint').tap(options => { if (options[0] && typeof options[0] === 'object' && options[0].extensions) { - delete options[0].extensions + delete options[0].extensions; } - return options - }) + return options; + }); config.cache({ type: 'filesystem', - }) + }); }, -} +}; From b82972847f542a8a8964c4c88408c6572516d053 Mon Sep 17 00:00:00 2001 From: v0 Date: Thu, 10 Sep 2026 23:11:36 +0000 Subject: [PATCH 02/12] Complete responsive surface refinements --- src/components/PageStrcture/Nav.vue | 8 +++++--- src/components/Settings/SearchBar.vue | 3 ++- src/components/Settings/SettingsContainer.vue | 3 ++- src/views/Minimal.vue | 5 ++--- src/views/Workspace.vue | 4 ++-- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/components/PageStrcture/Nav.vue b/src/components/PageStrcture/Nav.vue index 496cea4..7db1188 100644 --- a/src/components/PageStrcture/Nav.vue +++ b/src/components/PageStrcture/Nav.vue @@ -85,12 +85,14 @@ export default { .nav-outer { nav { - display: flex; + display: flex; align-items: center; + gap: .5rem; .nav-item { display: inline-block; - padding: 0.75rem 0.5rem; - margin: 0.5rem; + padding: 0.625rem 0.75rem; + margin: 0; + min-width: 5rem; text-align: center; outline: none; diff --git a/src/components/Settings/SearchBar.vue b/src/components/Settings/SearchBar.vue index 036243e..046a975 100644 --- a/src/components/Settings/SearchBar.vue +++ b/src/components/Settings/SearchBar.vue @@ -175,8 +175,9 @@ export default { display: flex; align-items: center; border-radius: 0 0 var(--curve-factor-navbar) 0; - padding: 0 0.2rem 0.2rem 0; + padding: .5rem var(--space-page) .5rem 0; background: var(--search-container-background); + border-bottom: 1px solid var(--border-subtle, var(--outline-color)); .search-wrap { display: flex; flex-direction: column; diff --git a/src/components/Settings/SettingsContainer.vue b/src/components/Settings/SettingsContainer.vue index de4ed91..9184423 100644 --- a/src/components/Settings/SettingsContainer.vue +++ b/src/components/Settings/SettingsContainer.vue @@ -139,7 +139,8 @@ export default { display: flex; align-items: center; align-items: stretch; - background: linear-gradient(0deg, var(--background) 0%, var(--background-darker) 100%); + background: var(--background-darker); + border-bottom: 1px solid var(--border-subtle, var(--outline-color)); box-shadow: var(--settings-container-shadow); } .options-outer { diff --git a/src/views/Minimal.vue b/src/views/Minimal.vue index 9ec125f..bbacdd8 100644 --- a/src/views/Minimal.vue +++ b/src/views/Minimal.vue @@ -126,9 +126,8 @@ export default { .minimal-home { display: flex; flex-direction: column; - margin: 1rem auto; - padding-bottom: 1px; - padding-top: 10vh; + margin: 0 auto; + padding: 10vh 1rem 2rem; min-height: calc(99vh - var(--footer-height)); width: 90%; max-width: 1000px; diff --git a/src/views/Workspace.vue b/src/views/Workspace.vue index 3cafc2d..117ea4e 100644 --- a/src/views/Workspace.vue +++ b/src/views/Workspace.vue @@ -18,7 +18,6 @@ import SideBar from '@/components/Workspace/SideBar'; import WebContent from '@/components/Workspace/WebContent'; import WidgetView from '@/components/Workspace/WidgetView'; import MultiTaskingWebContent from '@/components/Workspace/MultiTaskingWebContent'; -import Defaults from '@/utils/defaults'; export default { name: 'Workspace', @@ -87,10 +86,11 @@ export default { - diff --git a/src/components/LinkItems/StatusIndicator.vue b/src/components/LinkItems/StatusIndicator.vue index c4d6b2d..bdaab9a 100644 --- a/src/components/LinkItems/StatusIndicator.vue +++ b/src/components/LinkItems/StatusIndicator.vue @@ -2,17 +2,14 @@
-
- -
+
+ diff --git a/src/components/PageStrcture/Nav.vue b/src/components/PageStrcture/Nav.vue index 347823d..f1aad6a 100644 --- a/src/components/PageStrcture/Nav.vue +++ b/src/components/PageStrcture/Nav.vue @@ -1,70 +1,98 @@ diff --git a/src/components/Settings/SearchBar.vue b/src/components/Settings/SearchBar.vue index 046a975..d97136e 100644 --- a/src/components/Settings/SearchBar.vue +++ b/src/components/Settings/SearchBar.vue @@ -1,22 +1,30 @@ @@ -27,31 +35,21 @@ import ErrorHandler from '@/utils/ErrorHandler'; import { getCustomKeyShortcuts } from '@/utils/ConfigHelpers'; import { getSearchEngineFromBang, findUrlForSearchEngine, stripBangs } from '@/utils/Search'; import { - searchEngineUrls, - defaultSearchEngine, - defaultSearchOpeningMethod, - searchBangs as defaultSearchBangs, + searchEngineUrls, defaultSearchEngine, + defaultSearchOpeningMethod, searchBangs as defaultSearchBangs, } from '@/utils/defaults'; export default { name: 'FilterTile', - props: { - minimalSearch: Boolean, // If true, then keep it simple - }, - data() { - return { - input: '', // Users current search term - akn: new ArrowKeyNavigation(), // Class that manages arrow key naviagtion - getCustomKeyShortcuts, - }; - }, + props: { minimalSearch: Boolean }, + data: () => ({ + input: '', + akn: new ArrowKeyNavigation(), + getCustomKeyShortcuts, + }), computed: { - active() { - return !this.$store.state.modalOpen; - }, - searchPrefs() { - return this.$store.getters.webSearch || {}; - }, + active() { return !this.$store.state.modalOpen; }, + searchPrefs() { return this.$store.getters.webSearch || {}; }, urlDetected() { return this.searchPrefs.openUrlsDirectly && this.isUrlLike(this.input.trim()); }, @@ -68,40 +66,31 @@ export default { window.removeEventListener('keydown', this.handleKeyPress); }, methods: { - /* Call correct function dependending on which key is pressed */ handleKeyPress(event) { const currentElem = document.activeElement.id; const { key, keyCode } = event; const notAlreadySearching = currentElem !== 'filter-tiles'; - // If a modal is open, then do nothing if (!this.active) return; if (/^[/:!a-zA-Z]$/.test(key) && notAlreadySearching) { - // Letter or bang key pressed - start searching if (this.$refs.filter) this.$refs.filter.focus(); this.userIsTypingSomething(); } else if (/^[0-9]$/.test(key)) { - // Number key pressed, check if user has a custom binding this.handleHotKey(key); } else if (keyCode >= 37 && keyCode <= 40) { - // Arrow key pressed - start navigation this.akn.arrowNavigation(keyCode); } else if (keyCode === 27) { - // Esc key pressed - reset form this.clearFilterInput(); } }, - /* Emmits users's search term up to parent */ userIsTypingSomething() { this.$emit('user-is-searchin', this.input); }, - /* Resets everything to initial state, when user is finished */ clearFilterInput() { - this.input = ''; // Clear input model - this.userIsTypingSomething(); // Emmit new empty value - document.activeElement.blur(); // Remove focus - this.akn.resetIndex(); // Reset current element index + this.input = ''; + this.userIsTypingSomething(); + document.activeElement.blur(); + this.akn.resetIndex(); }, - /* If configured, launch specific app when hotkey pressed */ handleHotKey(key) { const sections = this.$store.getters.sections || []; const usersHotKeys = this.getCustomKeyShortcuts(sections); @@ -111,55 +100,44 @@ export default { } }); }, - /* Launch search results, with users desired opening method */ launchWebSearch(url, method) { switch (method) { - case 'newtab': - window.open(url, '_blank'); - break; - case 'sametab': - window.open(url, '_self'); - break; - case 'workspace': - router.push({ name: 'workspace', query: { url } }); - break; - default: - ErrorHandler(`Unknown opening method: ${method}`); - window.open(url, '_blank'); + case 'newtab': window.open(url, '_blank'); break; + case 'sametab': window.open(url, '_self'); break; + case 'workspace': router.push({ name: 'workspace', query: { url } }); break; + default: ErrorHandler(`Unknown opening method: ${method}`); window.open(url, '_blank'); } }, - - /* Launch web search, to correct search engine, passing in users query */ searchSubmitted() { - // Get search preferences from appConfig const { searchPrefs } = this; - if (!searchPrefs.disableWebSearch) { // Only proceed if user hasn't disabled web search + if (!searchPrefs.disableWebSearch) { const input = this.input.trim(); const openingMethod = searchPrefs.openingMethod || defaultSearchOpeningMethod; - // If openUrlsDirectly enabled and input looks like a URL, navigate directly if (searchPrefs.openUrlsDirectly && input && this.isUrlLike(input)) { const url = /^https?:\/\//.test(input) ? input : `https://${input}`; this.launchWebSearch(url, openingMethod); this.clearFilterInput(); return; } - const bangList = { ...defaultSearchBangs, ...(searchPrefs.searchBangs || {}) }; + const bangList = { + ...defaultSearchBangs, + ...(searchPrefs.searchBangs || {}), + }; const searchBang = getSearchEngineFromBang(this.input, bangList); const searchEngine = searchPrefs.searchEngine || defaultSearchEngine; - // Use either search bang, or preffered search engine const desiredSearchEngine = searchBang || searchEngine; - const isCustomSearch = (searchPrefs.searchEngine === 'custom' && searchPrefs.customSearchEngine); + const isCustomSearch = (searchPrefs.searchEngine === 'custom' + && searchPrefs.customSearchEngine); let searchUrl = isCustomSearch ? searchPrefs.customSearchEngine : findUrlForSearchEngine(desiredSearchEngine, searchEngineUrls); - if (searchUrl) { // Append search query to URL, and launch + if (searchUrl) { searchUrl += encodeURIComponent(stripBangs(this.input, bangList)); this.launchWebSearch(searchUrl, openingMethod); this.clearFilterInput(); } } }, - /* Detect if input looks like a URL (has TLD, no spaces) */ isUrlLike(input) { return /^(https?:\/\/)?([\w-]+\.)+[a-zA-Z]{2,}(\/\S*)?$/.test(input.trim()); }, @@ -168,135 +146,108 @@ export default { diff --git a/src/components/Settings/SettingsContainer.vue b/src/components/Settings/SettingsContainer.vue index 9184423..47c696d 100644 --- a/src/components/Settings/SettingsContainer.vue +++ b/src/components/Settings/SettingsContainer.vue @@ -132,103 +132,59 @@ export default { diff --git a/src/styles/color-palette.scss b/src/styles/color-palette.scss index 82e23d6..06eab13 100644 --- a/src/styles/color-palette.scss +++ b/src/styles/color-palette.scss @@ -1,139 +1,175 @@ @import '@/styles/media-queries.scss'; :root { - /* Basic*/ - --primary: #56a8ff; // Main accent color - --background: #06101f; // Page background - --background-darker: #030914; // Used for navigation bar, footer and fills - --surface-1: #091a2e; - --surface-2: #0d2742; - --surface-3: #12385a; - --text-primary: #edf6ff; - --text-secondary: #9eb6d0; - --text-muted: #718aa4; - --border-subtle: #1b5a8a; - --focus-ring: #8de8ff; + /* Core Palette - Dark Premium Developer Dashboard */ + --primary: #3b82f6; // Electric blue + --background: #060b1a; // Deep navy/graphite + --background-darker: #030710; // Near-black navy + --surface-1: #0a1628; // Dark blue-black + --surface-2: #0f1f3a; // Slightly brighter navy + --surface-3: #152d52; // Blue surface + --surface-elevated: #1a2f55; // Elevated surface + --text-primary: #e8f0fe; // Near-white + --text-secondary: #8ba3c7; // Cool blue-gray + --text-muted: #5a7a9e; // Muted blue-gray + --border-subtle: #1e3a5f; // Subtle blue border + --border-active: #3b82f6; // Active blue border + --focus-ring: #60a5fa; // Focus ring + --accent-glow: rgba(59, 130, 246, 0.15); // Subtle blue ambient glow /* Action Colors */ - --info: #04e4f4; - --success: #20e253; - --warning: #f6f000; - --error: #fca016; - --danger: #f80363; - --neutral: #272f4d; + --info: #06d6e0; + --success: #22c55e; + --warning: #eab308; + --error: #f97316; + --danger: #ef4444; + --neutral: #2a3a56; --white: #fff; --black: #000; /* Modified Colors */ - --item-group-background: #0b1021cc; - --medium-grey: #5e6474; - --item-background: #607d8b33; - --item-background-hover: #607d8b4d; + --item-group-background: #0a1628dd; + --medium-grey: #5a6a82; + --item-background: #1e3a5f33; + --item-background-hover: #1e3a5f55; - /* Semi-Transparent Black*/ + /* Semi-Transparent Black */ --transparent-70: #000000b3; --transparent-50: #00000080; --transparent-30: #0000004d; - /* Semi-Transparent White*/ + /* Semi-Transparent White */ --transparent-white-70: #ffffffb3; --transparent-white-50: #ffffff80; --transparent-white-30: #ffffff4d; --transparent-white-10: #ffffff0f; - /* Color variables for specific components - * all variables are optional, since they inherit initial values from above* - * Using specific variables makes overriding for custom themes really easy */ - --heading-text-color: var(--primary); - // Nav-bar links - --nav-link-text-color: var(--primary); - --nav-link-background-color: #607d8b33; + /* Color variables for specific components */ + --heading-text-color: var(--text-primary); + --nav-link-text-color: var(--text-secondary); + --nav-link-background-color: #0a162899; --nav-link-text-color-hover: var(--primary); - --nav-link-background-color-hover: #607d8b33; + --nav-link-background-color-hover: #1e3a5f88; --nav-link-border-color: transparent; --nav-link-border-color-hover: var(--primary); - --nav-link-shadow: 1px 1px 2px #232323; - --nav-link-shadow-hover: 1px 1px 2px #232323; + --nav-link-shadow: 1px 1px 2px #00000040; + --nav-link-shadow-hover: 1px 1px 2px #00000060; + // Link items and sections - --item-text-color: var(--primary); - --item-text-color-hover: var(--item-text-color); - --item-group-outer-background: var(--primary); - --item-group-heading-text-color: var(--item-group-background); - --item-group-heading-text-color-hover: var(--background); + --item-text-color: var(--text-primary); + --item-text-color-hover: var(--primary); + --item-group-outer-background: var(--surface-1); + --item-group-heading-text-color: var(--text-secondary); + --item-group-heading-text-color-hover: var(--primary); + // Homepage settings - --settings-text-color: var(--primary); - --settings-background: var(--background); + --settings-text-color: var(--text-secondary); + --settings-background: var(--surface-1); + // Config menu - --config-settings-color: var(--primary); + --config-settings-color: var(--text-secondary); --config-settings-background: var(--background-darker); - --config-code-color: var(--background); - --config-code-background: var(--white); - --code-editor-color: var(--black); - --code-editor-background: var(--white); + --config-code-color: var(--text-primary); + --config-code-background: var(--surface-1); + --code-editor-color: var(--text-primary); + --code-editor-background: var(--surface-1); + // Widgets - --widget-text-color: var(--primary); - --widget-background-color: var(--background-darker); - --widget-accent-color: var(--background); + --widget-text-color: var(--text-secondary); + --widget-background-color: var(--surface-1); + --widget-accent-color: var(--primary); --widget-base-background: transparent; + // Interactive editor --interactive-editor-color: var(--primary); - --interactive-editor-background: var(--background); + --interactive-editor-background: var(--surface-1); --interactive-editor-background-darker: var(--background-darker); - // Cloud backup/ restore menu + + // Cloud backup/restore menu --cloud-backup-color: var(--config-settings-color); --cloud-backup-background: var(--config-settings-background); - // Search bar (on homepage) + + // Search bar --search-container-background: var(--background-darker); - --search-field-background: var(--background); - --search-label-color: var(--settings-text-color); + --search-field-background: var(--surface-1); + --search-label-color: var(--text-muted); + --search-border-color: var(--border-subtle); + --search-focus-border-color: var(--primary); + // Page footer - --footer-text-color: var(--medium-grey); - --footer-text-color-link: var(--primary); + --footer-text-color: var(--text-muted); + --footer-text-color-link: var(--primary); --footer-background: var(--background-darker); + // Right-click context menu - --context-menu-background: var(--background); - --context-menu-color: var(--primary); - --context-menu-secondary-color: var(--background-darker); + --context-menu-background: var(--surface-2); + --context-menu-color: var(--text-primary); + --context-menu-secondary-color: var(--surface-1); + --context-menu-border: var(--border-subtle); + // Workspace view --side-bar-background: var(--background-darker); - --side-bar-background-lighter: var(--background); - --side-bar-color: var(--primary); + --side-bar-background-lighter: var(--surface-1); + --side-bar-color: var(--text-secondary); --side-bar-item-background: var(--side-bar-background); --side-bar-item-color: var(--side-bar-color); --workspace-web-content-background: var(--background); + // Minimal view --minimal-view-background-color: var(--background); - --minimal-view-title-color: var(--primary); + --minimal-view-title-color: var(--text-primary); --minimal-view-settings-color: var(--primary); - --minimal-view-section-heading-color: var(--primary); - --minimal-view-section-heading-background: var(--background-darker); - --minimal-view-search-background: var(--background-darker); - --minimal-view-search-color: var(--primary); - --minimal-view-group-color: var(--primary); - --minimal-view-group-background: var(--background-darker); + --minimal-view-section-heading-color: var(--text-secondary); + --minimal-view-section-heading-background: var(--surface-1); + --minimal-view-search-background: var(--surface-1); + --minimal-view-search-color: var(--text-primary); + --minimal-view-group-color: var(--text-secondary); + --minimal-view-group-background: var(--surface-1); + // Login page - --login-form-color: var(--primary); + --login-form-color: var(--text-primary); --login-form-background: var(--background); - --login-form-background-secondary: var(--background-darker); + --login-form-background-secondary: var(--surface-1); + // About page - --about-page-color: var(--white); + --about-page-color: var(--text-primary); --about-page-background: var(--background); --about-page-accent: var(--primary); - // Webpage colors, highlight, scrollbar - --scroll-bar-color: var(--primary); + + // Scrollbar + --scroll-bar-color: rgba(59, 130, 246, 0.35); --scroll-bar-background: var(--background-darker); - --highlight-color: var(--background); + --scroll-bar-track: rgba(59, 130, 246, 0.1); + + // Highlight + --highlight-color: var(--text-primary); --highlight-background: var(--primary); --progress-bar: var(--primary); + // Misc components --loading-screen-color: var(--primary); --loading-screen-background: var(--background); - --status-check-tooltip-background: var(--background-darker); - --status-check-tooltip-color: var(--primary); - --welcome-popup-background: var(--background-darker); - --welcome-popup-text-color: var(--primary); + --status-check-tooltip-background: var(--surface-2); + --status-check-tooltip-color: var(--text-primary); + --welcome-popup-background: var(--surface-2); + --welcome-popup-text-color: var(--text-primary); --toast-background: var(--primary); --toast-color: var(--background); - --description-tooltip-background: var(--background-darker); - --description-tooltip-color: var(--primary); + --description-tooltip-background: var(--surface-2); + --description-tooltip-color: var(--text-primary); + + // Card accent colors (deterministic per section) + --card-accent-blue: #3b82f6; + --card-accent-cyan: #06d6e0; + --card-accent-green: #22c55e; + --card-accent-purple: #a855f7; + --card-accent-orange: #f97316; + --card-accent-pink: #ec4899; + --card-accent-red: #ef4444; + + // Design Mode + --design-mode-border: var(--primary); + --design-mode-glow: rgba(59, 130, 246, 0.4); + --design-mode-toolbar-bg: var(--surface-2); + --design-mode-inspector-bg: var(--surface-1); } diff --git a/src/styles/dimensions.scss b/src/styles/dimensions.scss index 99141ea..a576450 100644 --- a/src/styles/dimensions.scss +++ b/src/styles/dimensions.scss @@ -1,41 +1,54 @@ -:root { + :root { /* General Variables */ --outline-color: none; - --curve-factor: 5px; // Border radius for most components - --curve-factor-navbar: 16px; // Border radius for header - --curve-factor-small: 2px; // Subtle border radius for util components - --radius-panel: 12px; - --radius-control: 7px; - --space-page: clamp(1rem, 2vw, 2rem); - --content-max-width: 1440px; - --sidebar-width: 15rem; - --topbar-height: 4.25rem; - - --dimming-factor: 0.7; // Opacity for semi-transparent components + --curve-factor: 6px; // Border radius for most components + --curve-factor-navbar: 12px; // Border radius for header + --curve-factor-small: 3px; // Subtle border radius for util components + --curve-factor-panel: 8px; + --radius-panel: 8px; + --radius-control: 6px; + --space-page: clamp(0.75rem, 1.5vw, 1.5rem); + --content-max-width: 1440px; + --sidebar-width: 14rem; + --topbar-height: 3.5rem; + + --dimming-factor: 0.65; // Opacity for semi-transparent components /* Basic Page Components */ - --scroll-bar-width: 8px; - --header-height: 6.3rem; - --footer-height: 128px; + --scroll-bar-width: 6px; + --header-height: 3.5rem; + --footer-height: 2.5rem; /* Section & Item dimensions */ - --item-group-padding: 5px; // Determines width of item-group outline - --item-shadow: 1px 1px 2px #130f23; - --item-hover-shadow: 1px 2px 4px #373737; - --item-icon-transform: drop-shadow(2px 4px 6px var(--transparent-50)) saturate(0.95); - --item-icon-transform-hover: drop-shadow(4px 8px 3px var(--transparent-50)) saturate(2); + --item-group-padding: 4px; // Determines width of item-group outline + --item-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); + --item-hover-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); + --item-icon-transform: drop-shadow(1px 2px 4px rgba(0, 0, 0, 0.3)) saturate(0.9); + --item-icon-transform-hover: drop-shadow(2px 4px 6px rgba(59, 130, 246, 0.3)) saturate(1.1); --item-group-shadow: var(--item-shadow); --context-menu-shadow: var(--item-shadow); --section-max-height: 3000px; /* Settings and config menu */ - --settings-container-shadow: none; + --settings-container-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); /* Workspace View */ - --side-bar-width: 3.5rem; // The width of the sidebar + --side-bar-width: 3rem; + + --tooltip-arrow-size: 5px; + --tooltip-width: 220px; + --tooltip-padding: 0.15rem; + + /* Card dimensions */ + --card-height: auto; + --card-padding: 0.5rem 0.75rem; + --card-gap: 0.5rem; + --card-border-radius: 8px; + --card-border-width: 1px; + --card-accent-width: 2px; - --tooltip-arrow-size: 6px; - --tooltip-width: 250px; - --tooltip-padding: 0.2rem; -} + /* Design Mode */ + --design-mode-inspector-width: 300px; + --design-mode-toolbar-height: 3rem; +} diff --git a/src/styles/global-styles.scss b/src/styles/global-styles.scss index 6c0e395..a45856a 100644 --- a/src/styles/global-styles.scss +++ b/src/styles/global-styles.scss @@ -1,34 +1,32 @@ - -@import '@/styles/style-helpers.scss'; -@import '@/styles/media-queries.scss'; - -/* Essential global page layout styles */ +@import '@/styles/style-helpers.scss'; +@import '@/styles/media-queries.scss'; + +/* Essential global page layout styles */ html { padding: 0; margin: -3px 0 0 0; color: var(--text-primary, var(--primary)); background: var(--background); transition: background-color .2s ease, color .2s ease; + @extend .scroll-bar; + @extend .highlight; + box-sizing: border-box; + body { + background: var(--background); + margin: 0; + padding: 0; + } + input[type=button], button, a { + cursor: pointer; + } +} - @extend .scroll-bar; - @extend .highlight; - box-sizing: border-box; - /* Essential body styles */ - body { - background: var(--background); - margin: 0; - padding: 0; - } - /* Make links have pointy cursor */ - input[type=button], button, a { - cursor: pointer; - } -} - #shipyard { position: relative; min-height: 100vh; color: var(--text-primary, var(--primary)); + display: flex; + flex-direction: column; } :focus-visible { @@ -54,17 +52,18 @@ html { html { font-size: .9375rem; } } - -/* Hide text, and show 'Loading...' while Vue is initializing tags */ -[v-cloak] > * { display:none } +/* Hide text, and show 'Loading...' while Vue is initializing tags */ +[v-cloak] > * { display:none } [v-cloak]::before { content: "loading…" } -/* Shipyard command-center visual layer. Legacy selectors remain intact above. */ +/* Shipyard command-center visual layer */ body { background: - radial-gradient(circle at 58% -12%, rgba(34, 111, 190, .24), transparent 38rem), - linear-gradient(135deg, var(--background) 0%, #040b17 72%); - font-family: "Inter", "Segoe UI", sans-serif; + radial-gradient(circle at 20% 0%, rgba(59, 130, 246, 0.12), transparent 50%), + radial-gradient(circle at 80% 100%, rgba(168, 85, 247, 0.08), transparent 50%), + linear-gradient(135deg, var(--background) 0%, #040b17 60%, #030710 100%); + font-family: "Inter", "Segoe UI", "Raleway", sans-serif; + font-feature-settings: "liga" 0; } #shipyard { @@ -87,154 +86,112 @@ button:disabled, opacity: .58; } -.scroll-bar::-webkit-scrollbar { width: 7px; height: 7px; } -.scroll-bar::-webkit-scrollbar-track { background: rgba(3, 9, 20, .6); } +/* Custom dark scrollbar */ +.scroll-bar::-webkit-scrollbar { width: 6px; height: 6px; } +.scroll-bar::-webkit-scrollbar-track { background: rgba(59, 130, 246, 0.06); border-radius: 3px; } .scroll-bar::-webkit-scrollbar-thumb { - background: rgba(86, 168, 255, .34); - border: 2px solid transparent; - border-radius: 999px; + background: rgba(59, 130, 246, 0.25); + border-radius: 3px; + border: 1px solid transparent; background-clip: padding-box; } +.scroll-bar::-webkit-scrollbar-thumb:hover { + background: rgba(59, 130, 246, 0.4); +} + +/* Overriding styles for the modal component */ +.vm--modal, .shipyard-modal { + box-shadow: 0 20px 60px -10px rgba(0, 0, 0, 0.6), 0 0 20px rgba(59, 130, 246, 0.1) !important; + min-width: 350px; + min-height: 200px; + background: var(--background-darker); + @include phone { + left: 0.5rem !important; + right: 0.5rem !important; + width: 95% !important; + top: 2rem !important; + } +} +.vm--overlay { + background: #00000080; +} + +/* Overiding styles for the global toast component */ +.toast-message { + background: var(--toast-background) !important; + color: var(--toast-color) !important; + border: 1px solid var(--toast-color) !important; + border-radius: var(--curve-factor) !important; + font-size: 1.25rem !important; +} +.toast-error { + background: var(--danger) !important; + color: var(--white) !important; + font-size: 1.25rem !important; +} +.toast-success { + background: var(--success) !important; + color: var(--white) !important; + font-size: 1.25rem !important; +} - -/* Overriding styles for the modal component */ -.vm--modal, .shipyard-modal { - box-shadow: 0 40px 70px -2px hsl(0deg 0% 0% / 60%), 1px 1px 6px var(--primary) !important; - min-width: 350px; - min-height: 200px; - background: var(--background-darker); - @include phone { - left: 0.5rem !important; - right: 0.5rem !important; - width: 95% !important; - top: 2rem !important; - } -} -.vm--overlay { - background: #00000080; -} - -/* Overiding styles for the global toast component */ -.toast-message { - background: var(--toast-background) !important; - color: var(--toast-color) !important; - border: 1px solid var(--toast-color) !important; - border-radius: var(--curve-factor) !important; - font-size: 1.25rem !important; -} -.toast-error { - background: var(--danger) !important; - color: var(--white) !important; - font-size: 1.25rem !important; -} -.toast-success { - background: var(--success) !important; - color: var(--white) !important; - font-size: 1.25rem !important; -} - -/* v-select, dropdown styles */ -.v-select { - .vs__dropdown-toggle { - border-color: var(--primary); - background: var(--background); - cursor: pointer; - span.vs__selected { - color: var(--primary); - } - .vs__actions svg path { fill: var(--primary); } - } - ul.vs__dropdown-menu { - background: var(--background); - border-color: var(--primary); - li { - color: var(--primary); - &:hover { - color: var(--background); - background: var(--primary); - } - &.vs__dropdown-option--highlight { - color: var(--background); - background: var(--primary); - } - } - } -} - -/* Overriding styles for tooltip component */ -.tooltip { - display: block; - z-index: 5; - max-width: var(--tooltip-width); - border: none; - padding: 0; - .tooltip-inner { - background: var(--description-tooltip-background); - border: 1px solid var(--description-tooltip-color); - border-radius: var(--curve-factor-small); - color: var(--description-tooltip-color); - padding: var(--tooltip-padding); - overflow: hidden; - } - .tooltip-arrow { - width: 0; - height: 0; - border-style: solid; - position: absolute; - margin: var(--tooltip-arrow-size); - border-color: transparent; - border-width: var(--tooltip-arrow-size); - z-index: 1; - } - &[x-placement^="top"] { - margin-bottom: var(--tooltip-arrow-size); - .tooltip-arrow { - border-bottom-width: 0; - border-top-color: var(--description-tooltip-color); - bottom: calc(-1 * var(--tooltip-arrow-size)); - left: calc(50% - var(--tooltip-arrow-size)); - margin: 0 var(--tooltip-arrow-size); - } - } - &[x-placement^="bottom"] { - margin-top: var(--tooltip-arrow-size); - .tooltip-arrow { - border-top-width: 0; - border-bottom-color: var(--description-tooltip-color); - top: calc(-1 * var(--tooltip-arrow-size)); - left: calc(50% - var(--tooltip-arrow-size)); - margin: 0 var(--tooltip-arrow-size); - } - } - &[x-placement^="right"] { - margin-left: var(--tooltip-arrow-size); - .tooltip-arrow { - border-left-width: 0; - border-right-color: var(--description-tooltip-color); - left: calc(-1 * var(--tooltip-arrow-size)); - top: calc(50% - var(--tooltip-arrow-size)); - margin: var(--tooltip-arrow-size) 0; - } - } - &[x-placement^="left"] { - margin-right: var(--tooltip-arrow-size); - .tooltip-arrow { - border-right-width: 0; - border-left-color: var(--description-tooltip-color); - right: calc(-1 * var(--tooltip-arrow-size)); - top: calc(50% - var(--tooltip-arrow-size)); - margin: var(--tooltip-arrow-size) 0; - } - } - &[aria-hidden='true'] { - visibility: hidden; - opacity: 0; - transition: opacity .15s, visibility .15s; - } - &[aria-hidden='false'] { - visibility: visible; - opacity: 1; - transition: opacity .15s; - } - &.in-modal-tt { z-index: 999; } -} +/* v-select, dropdown styles */ +.v-select { + .vs__dropdown-toggle { + border-color: var(--border-subtle); + background: var(--surface-1); + cursor: pointer; + span.vs__selected { color: var(--primary); } + .vs__actions svg path { fill: var(--primary); } + } + ul.vs__dropdown-menu { + background: var(--surface-1); + border-color: var(--border-subtle); + li { + color: var(--text-primary); + &:hover { color: var(--background); background: var(--primary); } + &.vs__dropdown-option--highlight { color: var(--background); background: var(--primary); } + } + } +} + +/* Overriding styles for tooltip component */ +.tooltip { + display: block; + z-index: 5; + max-width: var(--tooltip-width); + border: none; + padding: 0; + .tooltip-inner { + background: var(--description-tooltip-background); + border: 1px solid var(--border-subtle); + border-radius: var(--curve-factor-small); + color: var(--text-primary); + padding: var(--tooltip-padding); + overflow: hidden; + } + .tooltip-arrow { + width: 0; height: 0; border-style: solid; position: absolute; + margin: var(--tooltip-arrow-size); border-color: transparent; + border-width: var(--tooltip-arrow-size); z-index: 1; + } + &[x-placement^="top"] { + margin-bottom: var(--tooltip-arrow-size); + .tooltip-arrow { border-bottom-width: 0; border-top-color: var(--border-subtle); bottom: calc(-1 * var(--tooltip-arrow-size)); left: calc(50% - var(--tooltip-arrow-size)); margin: 0 var(--tooltip-arrow-size); } + } + &[x-placement^="bottom"] { + margin-top: var(--tooltip-arrow-size); + .tooltip-arrow { border-top-width: 0; border-bottom-color: var(--border-subtle); top: calc(-1 * var(--tooltip-arrow-size)); left: calc(50% - var(--tooltip-arrow-size)); margin: 0 var(--tooltip-arrow-size); } + } + &[x-placement^="right"] { + margin-left: var(--tooltip-arrow-size); + .tooltip-arrow { border-left-width: 0; border-right-color: var(--border-subtle); left: calc(-1 * var(--tooltip-arrow-size)); top: calc(50% - var(--tooltip-arrow-size)); margin: var(--tooltip-arrow-size) 0; } + } + &[x-placement^="left"] { + margin-right: var(--tooltip-arrow-size); + .tooltip-arrow { border-right-width: 0; border-left-color: var(--border-subtle); right: calc(-1 * var(--tooltip-arrow-size)); top: calc(50% - var(--tooltip-arrow-size)); margin: var(--tooltip-arrow-size) 0; } + } + &[aria-hidden='true'] { visibility: hidden; opacity: 0; transition: opacity .15s, visibility .15s; } + &[aria-hidden='false'] { visibility: visible; opacity: 1; transition: opacity .15s; } + &.in-modal-tt { z-index: 999; } +} From da72a9205cf0f37b2d18900a87994ca76f2aec11 Mon Sep 17 00:00:00 2001 From: Liss-Bot Date: Fri, 11 Sep 2026 16:57:52 +0000 Subject: [PATCH 12/12] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Bump=20version=20to?= =?UTF-8?q?=203.1.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f6ce30e..89bcada 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shipyard", - "version": "3.1.4", + "version": "3.1.5", "author": "KhulnaSoft Dev (https://khulnasoft.com)", "license": "MIT", "scripts": {