Merge branch 'build/style-lint-fix-purge' into 'v3'

ui_migration Clean STYLE, setup Lint, at NPM and CI

Closes #764

See merge request openflexure/openflexure-microscope-server!577
This commit is contained in:
Julian Stirling 2026-05-11 09:02:41 +00:00
commit acdc88e870
25 changed files with 1825 additions and 229 deletions

View file

@ -156,8 +156,8 @@ eslint:
stage: analysis stage: analysis
extends: .javascript_webapp extends: .javascript_webapp
script: script:
# Build JS application for production
- npm run lint - npm run lint
- npm run lint:style
# Build JS app # Build JS app
build: build:

1799
webapp/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,9 @@
"serve": "vite serve --mode development", "serve": "vite serve --mode development",
"build": "vite build --mode production", "build": "vite build --mode production",
"lint": "eslint . --ignore-pattern .gitignore --max-warnings=0", "lint": "eslint . --ignore-pattern .gitignore --max-warnings=0",
"lint:fix": "eslint . --fix --ignore-pattern .gitignore" "lint:fix": "eslint . --fix --ignore-pattern .gitignore",
"lint:style": "stylelint \"src/**/*.{vue,less,css}\" --max-warnings=0",
"lint:style:fix": "stylelint \"src/**/*.{vue,less,css}\" --fix"
}, },
"dependencies": { "dependencies": {
"@vueuse/core": "^14.1.0", "@vueuse/core": "^14.1.0",
@ -38,7 +40,12 @@
"eslint-plugin-vue": "^9.20.0", "eslint-plugin-vue": "^9.20.0",
"less": "^4.5.1", "less": "^4.5.1",
"material-symbols": "^0.39.1", "material-symbols": "^0.39.1",
"postcss-html": "^1.8.1",
"postcss-less": "^6.0.0",
"prettier": "^3.2.8", "prettier": "^3.2.8",
"stylelint": "^17.11.0",
"stylelint-config-standard": "^40.0.0",
"stylelint-config-standard-less": "^4.1.0",
"typescript-eslint": "^8.59.0", "typescript-eslint": "^8.59.0",
"vite": "^7.3.1" "vite": "^7.3.1"
}, },

View file

@ -325,7 +325,7 @@ export default {
</script> </script>
<style lang="less"> <style lang="less">
@import "./assets/less/theme.less"; @import url("./assets/less/theme.less");
// We override the custom-electron-titlebar z-index // We override the custom-electron-titlebar z-index
// UIKit lightbox must be able to draw over the titlebar // UIKit lightbox must be able to draw over the titlebar
// as it currently always spawns at the root of the DOM // as it currently always spawns at the root of the DOM
@ -353,8 +353,7 @@ html {
} }
.control-component { .control-component {
overflow-y: auto; overflow: hidden auto;
overflow-x: hidden;
scrollbar-gutter: stable; scrollbar-gutter: stable;
width: 300px; width: 300px;
height: 100%; height: 100%;
@ -366,8 +365,7 @@ html {
} }
.view-component { .view-component {
overflow-y: auto; overflow: hidden auto;
overflow-x: hidden;
height: 100%; height: 100%;
padding: 0; padding: 0;
} }

View file

@ -52,7 +52,7 @@ h4, .uk-h4 {
} }
.uk-card-body { .uk-card-body {
padding: 20px 16px 8px 16px; padding: 20px 16px 8px;
width: 240px; width: 240px;
} }
@ -88,7 +88,6 @@ h4, .uk-h4 {
.uk-notification-message { .uk-notification-message {
border-radius: @paper-border-radius; border-radius: @paper-border-radius;
box-shadow: @big-shadow; box-shadow: @big-shadow;
word-break: break-word;
overflow-wrap: anywhere; overflow-wrap: anywhere;
} }
@ -172,8 +171,8 @@ a:hover {
} }
.uk-button-disabled { .uk-button-disabled {
border: 1px solid #999999 !important; border: 1px solid #999 !important;
background-color: #cccccc !important; background-color: #ccc !important;
color: #919191 !important; color: #919191 !important;
} }

View file

@ -49,7 +49,7 @@
.hook-base-body() { .hook-base-body() {
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility; text-rendering: optimizelegibility;
} }
// //
@ -139,8 +139,7 @@
// //
// Inverse // Inverse
// //
// Colours for dark mode also in the colors section
@inverse-global-color: fade(@global-inverse-color, 80%);
@inverse-global-muted-color: fade(@global-inverse-color, 60%); @inverse-global-muted-color: fade(@global-inverse-color, 60%);
// //
@ -187,6 +186,7 @@
color: @inverse-global-color; color: @inverse-global-color;
border-color: @inverse-global-color; border-color: @inverse-global-color;
} }
.uk-alert-danger { .uk-alert-danger {
color: @notification-message-danger-color; color: @notification-message-danger-color;
border-color: @notification-message-danger-color border-color: @notification-message-danger-color
@ -202,7 +202,6 @@
* Links * Links
*/ */
.hook-inverse() { .hook-inverse() {
.uk-link:hover, .uk-link:hover,
.uk-button-link:hover, .uk-button-link:hover,
a:hover { a:hover {
@ -224,6 +223,7 @@
color: @inverse-primary-muted-color; color: @inverse-primary-muted-color;
border-color: @inverse-primary-muted-color; border-color: @inverse-primary-muted-color;
} }
.uk-button:hover { .uk-button:hover {
background-color: @inverse-primary-muted-color; background-color: @inverse-primary-muted-color;
color: #fff; color: #fff;
@ -244,8 +244,8 @@
.uk-button-disabled { .uk-button-disabled {
border: 1px solid @darkened-primary-color !important; border: 1px solid @darkened-primary-color !important;
background-color: #333333 !important; background-color: #333 !important;
color: #777777 !important; color: #777 !important;
} }
} }

View file

@ -246,6 +246,7 @@ export default {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
#component-left { #component-left {
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -266,8 +267,7 @@ export default {
#switcher-left-container { #switcher-left-container {
margin: 0; margin: 0;
padding: 0; padding: 0;
overflow-x: hidden; overflow: hidden auto;
overflow-y: auto;
height: 100%; height: 100%;
background-color: rgba(180, 180, 180, 0.1); background-color: rgba(180, 180, 180, 0.1);
border-width: 0 1px 0 0; border-width: 0 1px 0 0;

View file

@ -39,7 +39,7 @@ export default {
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import "../../assets/less/variables.less"; @import url("../../assets/less/variables.less");
.progress { .progress {
position: relative; position: relative;
@ -49,7 +49,7 @@ export default {
background-color: rgba(180, 180, 180, 0.15); background-color: rgba(180, 180, 180, 0.15);
border-radius: 2px; border-radius: 2px;
background-clip: padding-box; background-clip: padding-box;
margin: 0.5rem 0 1rem 0; margin: 0.5rem 0 1rem;
overflow: hidden; overflow: hidden;
} }
@ -73,7 +73,7 @@ export default {
} }
} }
.progress .indeterminate:before { .progress .indeterminate::before {
content: ""; content: "";
position: absolute; position: absolute;
background-color: inherit; background-color: inherit;
@ -81,11 +81,10 @@ export default {
left: 0; left: 0;
bottom: 0; bottom: 0;
will-change: left, right; will-change: left, right;
-webkit-animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite; animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
} }
.progress .indeterminate:after { .progress .indeterminate::after {
content: ""; content: "";
position: absolute; position: absolute;
background-color: inherit; background-color: inherit;
@ -93,63 +92,38 @@ export default {
left: 0; left: 0;
bottom: 0; bottom: 0;
will-change: left, right; will-change: left, right;
-webkit-animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite; animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
-webkit-animation-delay: 1.15s;
animation-delay: 1.15s; animation-delay: 1.15s;
} }
@-webkit-keyframes indeterminate {
0% {
left: -35%;
right: 100%;
}
60% {
left: 100%;
right: -90%;
}
100% {
left: 100%;
right: -90%;
}
}
@keyframes indeterminate { @keyframes indeterminate {
0% { 0% {
left: -35%; left: -35%;
right: 100%; right: 100%;
} }
60% { 60% {
left: 100%; left: 100%;
right: -90%; right: -90%;
} }
100% { 100% {
left: 100%; left: 100%;
right: -90%; right: -90%;
} }
} }
@-webkit-keyframes indeterminate-short {
0% {
left: -200%;
right: 100%;
}
60% {
left: 107%;
right: -8%;
}
100% {
left: 107%;
right: -8%;
}
}
@keyframes indeterminate-short { @keyframes indeterminate-short {
0% { 0% {
left: -200%; left: -200%;
right: 100%; right: 100%;
} }
60% { 60% {
left: 107%; left: 107%;
right: -8%; right: -8%;
} }
100% { 100% {
left: 107%; left: 107%;
right: -8%; right: -8%;

View file

@ -96,7 +96,7 @@ export default {
<style lang="less" scoped> <style lang="less" scoped>
// Custom UIkit CSS modifications // Custom UIkit CSS modifications
@import "../../assets/less/variables.less"; @import url("../../assets/less/variables.less");
.tabicon-active { .tabicon-active {
color: #fff !important; color: #fff !important;

View file

@ -105,8 +105,7 @@ export default {
.log-container { .log-container {
height: 100%; height: 100%;
overflow-y: auto; overflow: auto;
overflow-x: auto;
background-color: white; background-color: white;
color: black; color: black;
padding: 0.5em; padding: 0.5em;

View file

@ -44,7 +44,7 @@ export default {
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import "../../assets/less/variables.less"; @import url("../../assets/less/variables.less");
.in-button { .in-button {
position: absolute; position: absolute;
@ -67,7 +67,7 @@ export default {
background-color: rgba(180, 180, 180, 0.15); background-color: rgba(180, 180, 180, 0.15);
border-radius: 2px; border-radius: 2px;
background-clip: padding-box; background-clip: padding-box;
margin: 0.5rem 0 1rem 0; margin: 0.5rem 0 1rem;
overflow: hidden; overflow: hidden;
} }
@ -91,7 +91,7 @@ export default {
} }
} }
.progress .indeterminate:before { .progress .indeterminate::before {
content: ""; content: "";
position: absolute; position: absolute;
background-color: inherit; background-color: inherit;
@ -99,11 +99,10 @@ export default {
left: 0; left: 0;
bottom: 0; bottom: 0;
will-change: left, right; will-change: left, right;
-webkit-animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite; animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
} }
.progress .indeterminate:after { .progress .indeterminate::after {
content: ""; content: "";
position: absolute; position: absolute;
background-color: inherit; background-color: inherit;
@ -111,63 +110,38 @@ export default {
left: 0; left: 0;
bottom: 0; bottom: 0;
will-change: left, right; will-change: left, right;
-webkit-animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite; animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
-webkit-animation-delay: 1.15s;
animation-delay: 1.15s; animation-delay: 1.15s;
} }
@-webkit-keyframes indeterminate {
0% {
left: -35%;
right: 100%;
}
60% {
left: 100%;
right: -90%;
}
100% {
left: 100%;
right: -90%;
}
}
@keyframes indeterminate { @keyframes indeterminate {
0% { 0% {
left: -35%; left: -35%;
right: 100%; right: 100%;
} }
60% { 60% {
left: 100%; left: 100%;
right: -90%; right: -90%;
} }
100% { 100% {
left: 100%; left: 100%;
right: -90%; right: -90%;
} }
} }
@-webkit-keyframes indeterminate-short {
0% {
left: -200%;
right: 100%;
}
60% {
left: 107%;
right: -8%;
}
100% {
left: 107%;
right: -8%;
}
}
@keyframes indeterminate-short { @keyframes indeterminate-short {
0% { 0% {
left: -200%; left: -200%;
right: 100%; right: 100%;
} }
60% { 60% {
left: 107%; left: 107%;
right: -8%; right: -8%;
} }
100% { 100% {
left: 107%; left: 107%;
right: -8%; right: -8%;

View file

@ -91,13 +91,12 @@ export default {
}; };
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import "../../assets/less/variables.less"; @import url("../../assets/less/variables.less");
#progress-and-cancel-row { #progress-and-cancel-row {
display: flex; display: flex;
flex-flow: row wrap; flex-flow: row wrap;
justify-content: flex-start; place-content: stretch flex-start;
align-content: stretch;
align-items: center; align-items: center;
width: 100%; width: 100%;
} }
@ -107,16 +106,19 @@ export default {
margin-left: 5px; margin-left: 5px;
margin-right: 5px; margin-right: 5px;
} }
#progress-and-cancel-row .not-stretchy { #progress-and-cancel-row .not-stretchy {
flex-grow: 0; flex-grow: 0;
margin-left: 5px; margin-left: 5px;
margin-right: 5px; margin-right: 5px;
} }
#status-modal { #status-modal {
max-height: 90vh; // never exceed 90% of viewport height max-height: 90vh; // never exceed 90% of viewport height
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
#status-modal .log-container { #status-modal .log-container {
height: 10em; height: 10em;
} }

View file

@ -46,7 +46,8 @@ export default {
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import "../../assets/less/variables.less"; @import url("../../assets/less/variables.less");
a.uk-button-disabled { a.uk-button-disabled {
pointer-events: none; pointer-events: none;
} }

View file

@ -425,31 +425,32 @@ export default {
.input-and-buttons-container { .input-and-buttons-container {
display: flex; display: flex;
flex-flow: row wrap; flex-flow: row wrap;
justify-content: flex-start; place-content: stretch flex-start;
align-content: stretch;
align-items: center; align-items: center;
width: 100%; width: 100%;
} }
.property-input { .property-input {
flex-grow: 1; flex-grow: 1;
margin-left: 5px; margin-left: 5px;
margin-right: 5px; margin-right: 5px;
width: 6em; width: 6em;
} }
/*Hide standard spinners as it isn't possible to customise the browser ones.*/
/* Hide standard spinners as it isn't possible to customise the browser ones. */
.numeric-property { .numeric-property {
-moz-appearance: textfield; appearance: textfield;
} }
.numeric-property::-webkit-outer-spin-button, .numeric-property::-webkit-outer-spin-button,
.numeric-property::-webkit-inner-spin-button { .numeric-property::-webkit-inner-spin-button {
-webkit-appearance: none; appearance: none;
} }
.number-wrapper { .number-wrapper {
display: flex; display: flex;
flex-flow: row wrap; flex-flow: row wrap;
justify-content: flex-start; place-content: stretch flex-start;
align-content: stretch;
align-items: center; align-items: center;
flex-grow: 1; flex-grow: 1;
} }
@ -474,25 +475,31 @@ export default {
cursor: pointer; cursor: pointer;
color: #888; color: #888;
} }
.dropdown { .dropdown {
background-color: #fff; background-color: #fff;
border: 1px solid #ccc; border: 1px solid #ccc;
opacity: 1; opacity: 1;
} }
.edited { .edited {
background-color: #fff3cd; background-color: #fff3cd;
} }
@keyframes green-flash { @keyframes green-flash {
0% { 0% {
background-color: #3fda63; background-color: #3fda63;
} }
100% { 100% {
background-color: white; background-color: white;
} }
} }
.flash { .flash {
animation: green-flash 0.7s ease; animation: green-flash 0.7s ease;
/*Without this background-colour chrome will ignore the animation colour.*/
/* Without this background-colour chrome will ignore the animation colour. */
background-color: white; background-color: white;
} }
</style> </style>

View file

@ -218,6 +218,7 @@ export default {
.control-component { .control-component {
width: 33%; width: 33%;
} }
#log-display { #log-display {
height: 20em; height: 20em;
} }

View file

@ -176,22 +176,24 @@ export default {
.input-and-buttons-container { .input-and-buttons-container {
display: flex; display: flex;
flex-flow: column wrap; flex-flow: column wrap;
justify-content: flex-start; place-content: stretch flex-start;
align-content: stretch;
align-items: center; align-items: center;
width: 100%; width: 100%;
} }
.numeric-setting-line-input { .numeric-setting-line-input {
flex-grow: 1; flex-grow: 1;
margin: 5px 0px; margin: 5px 0;
width: 5em; width: 5em;
/* Stop Firefox showing input spinners, other /* Stop Firefox showing input spinners, other
browsers set with block below */ browsers set with block below */
-moz-appearance: textfield; appearance: textfield;
} }
/* Chrome, Safari, Edge, Opera */ /* Chrome, Safari, Edge, Opera */
.numeric-setting-line-input::-webkit-outer-spin-button, .numeric-setting-line-input::-webkit-outer-spin-button,
.numeric-setting-line-input::-webkit-inner-spin-button { .numeric-setting-line-input::-webkit-inner-spin-button {
-webkit-appearance: none; appearance: none;
} }
</style> </style>

View file

@ -177,14 +177,17 @@ export default {
grid-column: 2; grid-column: 2;
grid-row: 1; grid-row: 1;
} }
.dpad-grid #left-button { .dpad-grid #left-button {
grid-column: 1; grid-column: 1;
grid-row: 2; grid-row: 2;
} }
.dpad-grid #right-button { .dpad-grid #right-button {
grid-column: 3; grid-column: 3;
grid-row: 2; grid-row: 2;
} }
.dpad-grid #down-button { .dpad-grid #down-button {
grid-column: 2; grid-column: 2;
grid-row: 3; grid-row: 3;
@ -194,6 +197,7 @@ export default {
grid-column: 1; grid-column: 1;
grid-row: 5; grid-row: 5;
} }
.both-controls #focus-in-button { .both-controls #focus-in-button {
grid-column: 3; grid-column: 3;
grid-row: 5; grid-row: 5;
@ -203,6 +207,7 @@ export default {
grid-column: 1; grid-column: 1;
grid-row: 1; grid-row: 1;
} }
.focus-only #focus-in-button { .focus-only #focus-in-button {
grid-column: 3; grid-column: 3;
grid-row: 1; grid-row: 1;

View file

@ -241,12 +241,13 @@ export default {
@error-bg-color: #fef4f6; @error-bg-color: #fef4f6;
.logging-navbar { .logging-navbar {
border-width: 0 0 1px 0; border-width: 0 0 1px;
border-style: solid; border-style: solid;
border-color: rgba(180, 180, 180, 0.25); border-color: rgba(180, 180, 180, 0.25);
margin-bottom: 30px; margin-bottom: 30px;
height: 80px; height: 80px;
} }
.logging-entry { .logging-entry {
white-space: break-spaces; white-space: break-spaces;
padding: 0; padding: 0;
@ -272,16 +273,16 @@ export default {
color: darken(@warning-color, 15%); color: darken(@warning-color, 15%);
} }
.uk-light .uk-alert-warning .logging-header {
background: desaturate(darken(@warning-color, 15%), 10%);
color: darken(@warning-bg-color, 5%);
}
.uk-alert-danger .logging-header { .uk-alert-danger .logging-header {
background: darken(@error-bg-color, 15%); background: darken(@error-bg-color, 15%);
color: darken(@error-color, 15%); color: darken(@error-color, 15%);
} }
.uk-light .uk-alert-warning .logging-header {
background: desaturate(darken(@warning-color, 15%), 10%);
color: darken(@warning-bg-color, 5%);
}
.uk-light .uk-alert-danger .logging-header { .uk-light .uk-alert-danger .logging-header {
background: desaturate(darken(@error-color, 10%), 10%); background: desaturate(darken(@error-color, 10%), 10%);
color: darken(@error-bg-color, 5%); color: darken(@error-bg-color, 5%);
@ -313,9 +314,11 @@ export default {
background: #888; background: #888;
border-radius: 6px; border-radius: 6px;
} }
.more-info-container { .more-info-container {
display: flex; display: flex;
} }
.more-info { .more-info {
color: inherit; color: inherit;
text-decoration: underline; text-decoration: underline;

View file

@ -80,7 +80,7 @@ export default {
<style lang="less" scoped> <style lang="less" scoped>
// Custom UIkit CSS modifications // Custom UIkit CSS modifications
@import "../../assets/less/variables.less"; @import url("../../assets/less/variables.less");
.container { .container {
display: flex; display: flex;
@ -109,6 +109,6 @@ export default {
.shutdown-button { .shutdown-button {
display: inline; display: inline;
text-align: center; text-align: center;
margin: 30px 30px 30px 30px; margin: 30px;
} }
</style> </style>

View file

@ -173,7 +173,7 @@ ul {
display: block; display: block;
text-align: center; text-align: center;
list-style-type: none; list-style-type: none;
margin: 5px 0px 10px 0px; margin: 5px 0 10px;
padding: 0; padding: 0;
} }

View file

@ -230,7 +230,7 @@ export default {
<style lang="less" scoped> <style lang="less" scoped>
.gallery-navbar { .gallery-navbar {
border-width: 0 0 1px 0; border-width: 0 0 1px;
border-style: solid; border-style: solid;
border-color: rgba(180, 180, 180, 0.25); border-color: rgba(180, 180, 180, 0.25);
} }

View file

@ -36,6 +36,7 @@ export default {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
} }
#mini-stream { #mini-stream {
min-width: 300px; min-width: 300px;
max-width: 600px; max-width: 600px;

View file

@ -159,11 +159,10 @@ export default {
<style lang="less" scoped> <style lang="less" scoped>
// Custom UIkit CSS modifications // Custom UIkit CSS modifications
@import "../../assets/less/variables.less"; @import url("../../assets/less/variables.less");
.settings-nav { .settings-nav {
overflow-y: auto; overflow: hidden auto;
overflow-x: hidden;
width: 250px; width: 250px;
padding: 10px; padding: 10px;
background-color: rgba(180, 180, 180, 0.03); background-color: rgba(180, 180, 180, 0.03);

View file

@ -94,7 +94,7 @@ export default {
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
@import "../../assets/less/variables.less"; @import url("../../assets/less/variables.less");
.matrix-container { .matrix-container {
display: inline-block; display: inline-block;

View file

@ -0,0 +1,35 @@
// stylelint.config.mjs
export default {
extends: ["stylelint-config-standard"],
overrides: [
{
// VUE FILES OVERRIDE
files: ["**/*.vue"],
customSyntax: "postcss-html",
rules: {
// Stop Stylelint from throwing errors when it sees
// LESS functions (like darken, lighten, desaturate) inside Vue files.
"declaration-property-value-no-unknown": null,
},
},
{
// LESS FILES OVERRIDE
files: ["**/*.less"],
customSyntax: "postcss-less",
extends: ["stylelint-config-standard-less"],
},
],
rules: {
// Global rules
"selector-class-pattern": null,
"no-invalid-position-at-import-rule": null,
"no-empty-source": null,
// Needed rgba for UIkit color math
"color-function-notation": null,
"alpha-value-notation": null,
"color-function-alias-notation": null,
},
};