]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
feat(ui): apply Tokyo Night Storm theme with semantic CSS tokens
authorJérôme Benoit <jerome.benoit@sap.com>
Wed, 18 Mar 2026 23:14:13 +0000 (00:14 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Wed, 18 Mar 2026 23:16:00 +0000 (00:16 +0100)
Add theme.css with two-layer token system: primitive tokens from
the official Tokyo Night Storm palette, semantic tokens mapping UI
roles to primitives. All components use semantic tokens exclusively.

Replace all hardcoded colors across 13 Vue components. Theme native
HTML elements (button, input, select, a, headings) globally. Toggle
button pressed state uses palette-semantic active bg + accent border
+ inset shadow for clear visual distinction.

Remove dead code: simulatorButtonClass computed and associated CSS
classes that duplicated global button styles.

ui/web/src/App.vue
ui/web/src/assets/theme.css [new file with mode: 0644]
ui/web/src/components/buttons/ToggleButton.vue
ui/web/src/components/charging-stations/CSData.vue
ui/web/src/components/charging-stations/CSTable.vue
ui/web/src/main.ts
ui/web/src/views/ChargingStationsView.vue

index 1a0b1d6428ffab304a84fa3800cb0fe57b0dfb4a..8bf915f2eeb266d4961bda38082579610215d24a 100644 (file)
@@ -21,8 +21,8 @@ import Container from '@/components/Container.vue'
   -moz-osx-font-smoothing: grayscale;
   display: flex;
   flex-direction: row;
-  color: black;
-  background-color: white;
+  color: var(--color-text);
+  background-color: var(--color-bg);
 }
 
 #action-container {
@@ -38,7 +38,7 @@ import Container from '@/components/Container.vue'
   margin-right: 0.2%;
   margin-left: 0.2%;
   padding: 0.4%;
-  border: solid 0.25px black;
+  border: solid 0.25px var(--color-border);
 }
 
 body {
diff --git a/ui/web/src/assets/theme.css b/ui/web/src/assets/theme.css
new file mode 100644 (file)
index 0000000..2bb633b
--- /dev/null
@@ -0,0 +1,84 @@
+/* Tokyo Night Storm */
+
+:root {
+  /* Palette */
+  --tn-bg-dark: #1f2335;
+  --tn-bg-base: #24283b;
+  --tn-bg-raised: #1b1e2e;
+  --tn-bg-hover: #292e42;
+  --tn-bg-active: #2c324a;
+  --tn-fg-base: #a9b1d6;
+  --tn-fg-bright: #c0caf5;
+  --tn-fg-muted: #8089b3;
+  --tn-blue: #7aa2f7;
+  --tn-accent: #3d59a1;
+  --tn-white: #ffffff;
+
+  /* Semantic */
+  --color-bg: var(--tn-bg-base);
+  --color-bg-surface: var(--tn-bg-dark);
+  --color-bg-input: var(--tn-bg-raised);
+  --color-bg-hover: var(--tn-bg-hover);
+  --color-bg-active: var(--tn-bg-active);
+  --color-bg-header: var(--tn-bg-dark);
+  --color-bg-caption: var(--tn-bg-raised);
+  --color-bg-button: var(--tn-accent);
+  --color-bg-button-hover: color-mix(in srgb, var(--tn-accent) 67%, transparent);
+  --color-text: var(--tn-fg-base);
+  --color-text-strong: var(--tn-fg-bright);
+  --color-text-muted: var(--tn-fg-muted);
+  --color-text-on-button: var(--tn-white);
+  --color-primary: var(--tn-blue);
+  --color-border: var(--tn-bg-raised);
+  --color-border-row: var(--tn-bg-hover);
+  --color-accent: var(--tn-accent);
+  --color-shadow-inset: rgba(0, 0, 0, 0.4);
+}
+
+body {
+  color: var(--color-text);
+  background-color: var(--color-bg);
+}
+
+button,
+.button {
+  color: var(--color-text-on-button);
+  background-color: var(--color-bg-button);
+  border: 1px solid var(--color-border);
+  cursor: pointer;
+}
+
+button:hover,
+.button:hover {
+  background-color: var(--color-bg-button-hover);
+}
+
+input,
+select,
+textarea {
+  color: var(--color-text);
+  background-color: var(--color-bg-input);
+  border: 1px solid var(--color-border-row);
+}
+
+input::placeholder {
+  color: var(--color-text-muted);
+}
+
+input:focus,
+select:focus,
+textarea:focus {
+  outline: 1px solid var(--color-primary);
+}
+
+a {
+  color: var(--color-primary);
+}
+
+h1,
+h2,
+h3,
+p,
+li {
+  color: var(--color-text);
+}
index de1d269255a2f415981ddf483aa6b0f7f9e908a6..04195d777ab7d18f20eb3f8ffc4a99242595a1bd 100644 (file)
@@ -50,8 +50,9 @@ const click = (): void => {
 </script>
 
 <style>
-.on {
-  background-color: lightgrey;
-  border-style: inset;
+button.on {
+  background-color: var(--color-bg-active);
+  border: 1px solid var(--color-accent);
+  box-shadow: inset 0 2px 4px var(--color-shadow-inset);
 }
 </style>
index 28a8b4d3436b332b15387631b44eba68a7d4efeb..7d1f4ce3d52d8678485ff61c574c694d7cd438b3 100644 (file)
@@ -267,7 +267,7 @@ const deleteChargingStation = (): void => {
 #connectors-table {
   display: flex;
   flex-direction: column;
-  background-color: white;
+  background-color: var(--color-bg-surface);
   overflow: auto hidden;
   border-collapse: collapse;
   empty-cells: show;
@@ -283,15 +283,15 @@ const deleteChargingStation = (): void => {
   flex-direction: row;
   justify-content: center;
   align-items: center;
-  border: solid 0.25px black;
+  border: solid 0.25px var(--color-border-row);
 }
 
 .connectors-table__row:nth-of-type(even) {
-  background-color: whitesmoke;
+  background-color: var(--color-bg-hover);
 }
 
 #connectors-table__head .connectors-table__row {
-  background-color: lightgrey;
+  background-color: var(--color-bg-header);
 }
 
 .connectors-table__column {
index 26bd9b52cb03fe769c73d1050d5a212c9124e4c7..3ed3b6b8bab3f71ee2d6fe777cad432e09476bc0 100644 (file)
@@ -106,11 +106,11 @@ const $emit = defineEmits(['need-refresh'])
 #cs-table {
   height: fit-content;
   width: 100%;
-  background-color: white;
+  background-color: var(--color-bg-surface);
   display: flex;
   flex-direction: column;
   overflow: auto hidden;
-  border: solid 0.25px black;
+  border: solid 0.25px var(--color-border);
   border-collapse: collapse;
   empty-cells: show;
 }
@@ -123,8 +123,8 @@ const $emit = defineEmits(['need-refresh'])
 }
 
 #cs-table__caption {
-  color: ivory;
-  background-color: black;
+  color: var(--color-text-strong);
+  background-color: var(--color-bg-caption);
   font-size: 1.5rem;
   font-weight: bold;
   padding: 0.5rem;
@@ -137,11 +137,11 @@ const $emit = defineEmits(['need-refresh'])
   flex-direction: row;
   justify-content: center;
   align-items: center;
-  border: solid 0.25px black;
+  border: solid 0.25px var(--color-border-row);
 }
 
 .cs-table__row:nth-of-type(even) {
-  background-color: whitesmoke;
+  background-color: var(--color-bg-hover);
 }
 
 .cs-table__column {
@@ -153,7 +153,7 @@ const $emit = defineEmits(['need-refresh'])
 }
 
 #cs-table__head .cs-table__row {
-  background-color: lightgrey;
+  background-color: var(--color-bg-header);
 }
 
 .cs-table__connectors-column {
index 77eb8d1d0b56c8c50638ca1fc335c4e02f4554ed..d40f9a250580e9d40bf8ab15a8893bd260b14c32 100644 (file)
@@ -9,6 +9,8 @@ import { router } from '@/router'
 
 import 'vue-toast-notification/dist/theme-bootstrap.css'
 
+import '@/assets/theme.css'
+
 const app = createApp(App as Component)
 
 const initializeApp = (app: AppType, config: ConfigurationData) => {
index c530223d139e38e10d815a8e880fc5c263522557..ecf937ba601c6c6230dabafc5ae6df15141033bc 100644 (file)
@@ -64,7 +64,6 @@
       <ToggleButton
         :id="'simulator'"
         :key="state.renderSimulator"
-        :class="simulatorButtonClass"
         :off="() => stopSimulator()"
         :on="() => startSimulator()"
         :status="simulatorStarted"
@@ -142,9 +141,6 @@ const simulatorState = ref<SimulatorState | undefined>(undefined)
 
 const simulatorStarted = computed((): boolean | undefined => simulatorState.value?.started)
 
-const simulatorButtonClass = computed((): string =>
-  simulatorState.value?.started === true ? 'simulator-stop-button' : 'simulator-start-button'
-)
 const simulatorButtonMessage = computed(
   (): string =>
     `${simulatorState.value?.started === true ? 'Stop' : 'Start'} Simulator${
@@ -355,18 +351,19 @@ const stopSimulator = (): void => {
 #ui-server-container {
   display: flex;
   justify-content: center;
-  border-style: outset;
+  border: 1px solid var(--color-border-row);
 }
 
 #ui-server-selector {
   width: 100%;
-  background-color: rgb(239, 239, 239);
+  background-color: var(--color-bg-input);
+  color: var(--color-text);
   font: small-caption;
   text-align: center;
 }
 
 #ui-server-selector:hover {
-  background-color: rgb(229, 229, 229);
+  background-color: var(--color-bg-hover);
 }
 
 #buttons-container {
@@ -376,46 +373,22 @@ const stopSimulator = (): void => {
   top: 0;
 }
 
-.simulator-start-button {
-  color: ivory;
-  background-color: green;
-}
-
-.simulator-start-button:hover {
-  background-color: rgb(0, 98, 0);
-}
-
-.simulator-stop-button {
-  color: ivory;
-  background-color: red;
-}
-
-.simulator-stop-button:hover {
-  background-color: rgb(225, 0, 0);
-}
-
 #action-button {
   flex: none;
 }
 
 #reload-button {
-  color: ivory;
-  background-color: blue;
   font-size: 1.5rem;
 }
 
-#reload-button:hover {
-  background-color: rgb(0, 0, 225);
-}
-
 #reload-button:active {
-  background-color: darkblue;
+  background-color: var(--color-primary);
 }
 
 #action {
   min-width: max-content;
-  color: ivory;
-  background-color: black;
+  color: var(--color-text-strong);
+  background-color: var(--color-bg-caption);
   padding: 0.8%;
 }
 </style>