From 155fb279fa8228b96c17d5ac2ac1b0892646a59f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Mon, 2 Jan 2023 13:53:43 +0000 Subject: [PATCH 01/23] [web] Stop using eos-ds package Because it does not look alive anymore. --- web/package-lock.json | 54 ---------------------- web/package.json | 1 - web/src/app.scss | 66 +++++---------------------- web/src/assets/_variables.scss | 7 +++ web/src/assets/fonts.scss | 5 -- web/src/components/core/fieldset.scss | 6 +-- web/src/components/core/section.scss | 8 ++-- web/src/components/layout/layout.scss | 12 +---- web/src/patternfly.scss | 37 +++++++-------- 9 files changed, 45 insertions(+), 151 deletions(-) create mode 100644 web/src/assets/_variables.scss diff --git a/web/package-lock.json b/web/package-lock.json index c5e948a199..0acfc0156b 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -12,7 +12,6 @@ "@patternfly/react-core": "^4.261.0", "@patternfly/react-table": "^4.111.33", "core-js": "^3.21.1", - "eos-ds": "^5.0.0", "ipaddr.js": "^2.0.1", "react": "17.0.2", "react-dom": "17.0.2", @@ -4802,25 +4801,6 @@ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true }, - "node_modules/bootstrap": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz", - "integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/twbs" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/bootstrap" - } - ], - "peerDependencies": { - "jquery": "1.9.1 - 3", - "popper.js": "^1.16.1" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -6046,15 +6026,6 @@ "node": ">=4" } }, - "node_modules/eos-ds": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eos-ds/-/eos-ds-5.0.0.tgz", - "integrity": "sha512-NNUaYHAL2k3ZxjpyWm/rRppW6yfaVJabVpPI+NMSxcq+PNytDvD7XBxJ26InJNG5/YdFJaERIkb91BgGNQ0hnQ==", - "dependencies": { - "bootstrap": "^4.3.1", - "jquery": "^3.6.0" - } - }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -10612,11 +10583,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/jquery": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz", - "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==" - }, "node_modules/js-sdsl": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", @@ -18459,12 +18425,6 @@ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true }, - "bootstrap": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz", - "integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==", - "requires": {} - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -19357,15 +19317,6 @@ "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", "dev": true }, - "eos-ds": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eos-ds/-/eos-ds-5.0.0.tgz", - "integrity": "sha512-NNUaYHAL2k3ZxjpyWm/rRppW6yfaVJabVpPI+NMSxcq+PNytDvD7XBxJ26InJNG5/YdFJaERIkb91BgGNQ0hnQ==", - "requires": { - "bootstrap": "^4.3.1", - "jquery": "^3.6.0" - } - }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -22719,11 +22670,6 @@ } } }, - "jquery": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz", - "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==" - }, "js-sdsl": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", diff --git a/web/package.json b/web/package.json index 79db99c2b1..aa5bdab7ee 100644 --- a/web/package.json +++ b/web/package.json @@ -81,7 +81,6 @@ "@patternfly/react-core": "^4.261.0", "@patternfly/react-table": "^4.111.33", "core-js": "^3.21.1", - "eos-ds": "^5.0.0", "ipaddr.js": "^2.0.1", "react": "17.0.2", "react-dom": "17.0.2", diff --git a/web/src/app.scss b/web/src/app.scss index c6daa2431a..6d63d9901a 100644 --- a/web/src/app.scss +++ b/web/src/app.scss @@ -1,29 +1,9 @@ -// NOTE: eos-base/index imports a lot of styles not needed by now. -// What is more, EOS is using @import instead of @use, which is the -// preferred one. Read "What's Wrong With @import?" at -// https://sass-lang.com/documentation/at-rules/import -// This block us from importing them granularly as needed because some -// SCSS EOS modules contains variables from others, making the tools -// fail. For example, it's the case of titles.scss, which uses a variable -// from branding.scss. Although we use @use here, the titles.scss -// can't find the variable because it is namespaced with "branding.". -// -// So, by now we will do our best, and maybe send a fix to mainstream. -// -// Another option is to investigate if there is a way to purge or -// "tree-shake" CSS while building to import the whole package without -// worrying about packaging more than needed. This, however, might not help -// while working in development mode. - -// @import "eos-ds/dist/scss/eos-base/index.scss"; -@use "eos-ds/dist/scss/eos-base/variables/branding.scss"; +@use "@assets/_variables.scss" as branding; // D-Installer fonts @use "assets/fonts.scss"; -// Style focus as proposed by EOS -// https://eosdesignsystem.herokuapp.com/focus#scss-code -// but making use of :focus-visible, see https://matthiasott.com/notes/focus-visible-is-here +// Style focus making use of :focus-visible *:focus { outline: none; } @@ -33,34 +13,12 @@ } *:focus-visible { - box-shadow: 0 0 0 1px branding.$eos-bc-cerulean-500; -} - -// NOTE: commented it out because looks like those -// sizes makes the headings too big -// // See "eos-ds/dist/scss/eos-base/variables/titles.scss"; -// // and comment at the begining -// $eos-h1-font-size: 2em; -// $eos-h2-font-size: 1.75em; -// $eos-h3-font-size: 1.5em; -// $eos-h4-font-size: 1.3em; -// $eos-h5-font-size: 1.15em; -// $eos-h6-font-size: 1em; -// $eos-font-weight-headers-bold: 500; - -// .pf-c-content { -// // Content headings size -// --pf-c-content--h1--FontSize: #{$eos-h1-font-size}; -// --pf-c-content--h2--FontSize: #{$eos-h2-font-size}; -// --pf-c-content--h3--FontSize: #{$eos-h3-font-size}; -// --pf-c-content--h4--FontSize: #{$eos-h4-font-size}; -// --pf-c-content--h5--FontSize: #{$eos-h5-font-size}; -// --pf-c-content--h6--FontSize: #{$eos-h6-font-size}; -// } + box-shadow: 0 0 0 1px branding.$bc-cerulean-500; +} body { text-align: start; - color: branding.$eos-bc-gray-1000; + color: branding.$bc-gray-1000; } h1, h2, h3, h4, h5, h6 { @@ -84,7 +42,7 @@ p { #root { min-block-size: 100vh; - background-color: branding.$eos-bc-gray-50; + background-color: branding.$bc-gray-50; } .installation-overview-section { @@ -110,7 +68,7 @@ p { } .success-icon { - fill: branding.$eos-bc-green-500; + fill: branding.$bc-green-500; } // Make proposal actiosn compact @@ -147,22 +105,22 @@ p { // - https://drafts.csswg.org/selectors/#relational // - https://caniuse.com/css-has .pf-c-card.selected-product { - //border: 1px solid branding.$eos-bc-green-500; + //border: 1px solid branding.$bc-green-500; --pf-c-card--BoxShadow: var(--pf-global--BoxShadow--md); .pf-c-radio { // https://drafts.csswg.org/css-ui/#widget-accent // https://caniuse.com/mdn-css_properties_accent-color - accent-color: branding.$eos-bc-pine-500; + accent-color: branding.$bc-pine-500; } .pf-c-radio__label { - color: branding.$eos-bc-green-500; + color: branding.$bc-green-500; font-weight: bold; } .pf-c-radio__description { - color: branding.$eos-bc-pine-500; + color: branding.$bc-pine-500; } } @@ -180,7 +138,7 @@ p { .host-ip { vertical-align: middle; - color: branding.$eos-bc-gray-900; + color: branding.$bc-gray-900; } ul.connections-datalist { diff --git a/web/src/assets/_variables.scss b/web/src/assets/_variables.scss new file mode 100644 index 0000000000..fb84129c61 --- /dev/null +++ b/web/src/assets/_variables.scss @@ -0,0 +1,7 @@ +$bc-gray-50: #f2f2f2; //rgb(242, 242, 242); +$bc-cerulean-500: #00b2e2; //rgb(0, 178, 226); +$bc-gray-900: #686565; //rgb(104, 101, 101); +$bc-gray-1000: #141823; //rgb(20, 24, 35); +$bc-green-500: #30ba78; //rgb(48, 186, 120); +$bc-green-900: #0e7e3c; //rgb(14, 126, 60); +$bc-pine-500: #0c322c; //rgb(12, 50, 44); diff --git a/web/src/assets/fonts.scss b/web/src/assets/fonts.scss index 8d2681c175..5c3c8ac073 100644 --- a/web/src/assets/fonts.scss +++ b/web/src/assets/fonts.scss @@ -1,8 +1,3 @@ -// Note: for this particular case, we are not using -// @use "eos-ds/dist/scss/eos-base/variables/typography.scss" -// because it imports fonts from an external source, which does not fit requirements of the -// installer (which can be running in a machine without internet access) - $base: Lato, arial, helvetica, sans-serif; $headlines: Poppins, san-serif; $code: 'Roboto Mono', monospace; diff --git a/web/src/components/core/fieldset.scss b/web/src/components/core/fieldset.scss index 1d955fca67..3d85e4623c 100644 --- a/web/src/components/core/fieldset.scss +++ b/web/src/components/core/fieldset.scss @@ -1,11 +1,11 @@ @use "@assets/fonts.scss"; -@use "eos-ds/dist/scss/eos-base/variables/branding.scss"; +@use "@assets/_variables.scss" as branding; fieldset.d-installer-fieldset { padding: fonts.$size-base; border: 0; - border-top: 1px solid branding.$eos-bc-gray-50; - border-image: linear-gradient(45deg, branding.$eos-bc-gray-50, transparent) 1; + border-top: 1px solid branding.$bc-gray-50; + border-image: linear-gradient(45deg, branding.$bc-gray-50, transparent) 1; legend { padding-inline-end: fonts.$size-base; diff --git a/web/src/components/core/section.scss b/web/src/components/core/section.scss index 66858da9ea..19352452f8 100644 --- a/web/src/components/core/section.scss +++ b/web/src/components/core/section.scss @@ -1,5 +1,5 @@ @use "@assets/fonts.scss"; -@use "eos-ds/dist/scss/eos-base/variables/branding.scss"; +@use "@assets/_variables.scss" as branding; .d-installer-section { .d-installer-section-icon { @@ -8,7 +8,7 @@ .d-installer-section-title.using-separator { border-bottom: 1px solid #efefef; - border-image: linear-gradient(45deg, branding.$eos-bc-gray-50, transparent) 1; + border-image: linear-gradient(45deg, branding.$bc-gray-50, transparent) 1; } .d-installer-section-action { @@ -16,14 +16,14 @@ transition: all 0.2s ease-in-out; svg { - fill: branding.$eos-bc-green-500; + fill: branding.$bc-green-500; } &:hover { transform: scale(1.4); svg { - fill: branding.$eos-bc-pine-500; + fill: branding.$bc-pine-500; } } } diff --git a/web/src/components/layout/layout.scss b/web/src/components/layout/layout.scss index c5a6bd5286..10950f9baf 100644 --- a/web/src/components/layout/layout.scss +++ b/web/src/components/layout/layout.scss @@ -1,8 +1,7 @@ // See https://github.com/patternfly/patternfly/pull/4297 @use "@patternfly/react-styles/css/utilities/BoxShadow/box-shadow.css"; @use "@patternfly/react-styles/css/utilities/Text/text.css"; - -@use "eos-ds/dist/scss/eos-base/variables/branding"; +@use "@assets/_variables.scss" as branding; .layout { --header-block-size: 8ex; @@ -31,7 +30,7 @@ z-index: 100; inset-block-start: 0; - background-color: branding.$eos-bc-pine-500; + background-color: branding.$bc-pine-500; color: white; block-size: var(--header-block-size); @@ -42,13 +41,6 @@ justify-content: space-between; gap: 0.5rem; - // Centers the section title. - // In a certain way it contradicts recommendations for headings given at - // https://eosdesignsystem.herokuapp.com/typography#headline-margins - // but it's more inline with the "branding" alignment at - // https://eosdesignsystem.herokuapp.com/layout - // - // See global heading styles at src/app.scss h1 { margin-block-start: 10px; } diff --git a/web/src/patternfly.scss b/web/src/patternfly.scss index d234ed650b..50b4195e74 100644 --- a/web/src/patternfly.scss +++ b/web/src/patternfly.scss @@ -1,18 +1,18 @@ -// @import "eos-ds/dist/scss/eos-base/index.scss"; -@use "eos-ds/dist/scss/eos-base/variables/branding.scss"; +@use "@assets/_variables.scss" as branding; + +$bc-gray-50: #f2f2f2; //rgb(242, 242, 242); +$bc-green-500: #30ba78; //rgb(48, 186, 120); +$bc-green-900: #0e7e3c; //rgb(14, 126, 60); +$bc-pine-500: #0c322c; //rgb(12, 50, 44); + // See https://github.com/patternfly/patternfly/pull/4297 @use "@patternfly/react-styles/css/utilities/Sizing/sizing.css"; // D-Installer fonts @use "assets/fonts.scss"; :root { - // Overrides some PatternFly CSS variables for using values - // provided or suggested by EOS Design System. - // - // See more at - // - https://eosdesignsystem.herokuapp.com - // - https://gitlab.com/SUSE-UIUX/eos-ds-npm/ - // - https://github.com/mcoker/patternfly/blob/main/src/patternfly/base/_variables.scss + // Overrides some PatternFly CSS variables using values + // from brand.suse.com // Font families --pf-global--FontFamily--sans-serif: #{fonts.$base}; @@ -28,8 +28,6 @@ --pf-global--FontFamily--overpass--monospace: #{fonts.$code}; // Font size - // Based on sizes of EOS headings. - // See "eos-ds/dist/scss/eos-base/variables/titles.scss"; --pf-global--FontSize--4xl: 2em; --pf-global--FontSize--3xl: 1.75em; --pf-global--FontSize--2xl: 1.5em; @@ -51,26 +49,26 @@ --pf-global--FontWeight--overpass--bold: 700; // Colors - --pf-global--primary-color--100: #{branding.$eos-bc-green-500}; - --pf-global--primary-color--200: #{branding.$eos-bc-green-900}; + --pf-global--primary-color--100: #{branding.$bc-green-500}; + --pf-global--primary-color--200: #{branding.$bc-green-900}; --pf-global--link--Color: var(--pf-global--primary-color--100); --pf-global--link--Color--hover: var(--pf-global--primary-color--200); - --pf-global--BackgroundColor--dark-100: #{branding.$eos-bc-pine-500}; + --pf-global--BackgroundColor--dark-100: #{branding.$bc-pine-500}; } .pf-c-button.pf-m-link { // Colors for buttons mofidiers - --pf-c-button--m-link--Color: #{branding.$eos-bc-green-500}; - --pf-c-button--m-link--Color--hover: #{branding.$eos-bc-green-900}; - --pf-c-button--m-link--m-inline--hover--Color: #{branding.$eos-bc-green-900}; + --pf-c-button--m-link--Color: #{branding.$bc-green-500}; + --pf-c-button--m-link--Color--hover: #{branding.$bc-green-900}; + --pf-c-button--m-link--m-inline--hover--Color: #{branding.$bc-green-900}; } // Adds a tiny "padding" when focusing a primary or secondary action to avoid // https://github.com/yast/d-installer/issues/115#issuecomment-1087375598 .pf-c-button.pf-m-primary:focus-visible, .pf-c-button.pf-m-secondary:focus-visible { - box-shadow: 0 0 0 1px white, 0 0 0 2px branding.$eos-bc-cerulean-500; + box-shadow: 0 0 0 1px white, 0 0 0 2px branding.$bc-cerulean-500; } // PatternFly overrides for using CSS Logical Properties @@ -106,8 +104,7 @@ .pf-c-form__actions, .pf-c-modal-box__footer { - // EOS prefers buttons placed at the right - // Read https://eosdesignsystem.herokuapp.com/buttons/positioning + // We prefer buttons placed at the right flex-direction: row-reverse; // Overrides buttons margins. In row-reverse mode, we need margin From 92d99d0687e5bb0dd85da967a65ade15fc5ca18e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Mon, 2 Jan 2023 14:55:26 +0000 Subject: [PATCH 02/23] [web] Remove dead Sass import --- web/src/components/layout/layout.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/web/src/components/layout/layout.scss b/web/src/components/layout/layout.scss index 10950f9baf..b9d81453d9 100644 --- a/web/src/components/layout/layout.scss +++ b/web/src/components/layout/layout.scss @@ -1,6 +1,5 @@ // See https://github.com/patternfly/patternfly/pull/4297 @use "@patternfly/react-styles/css/utilities/BoxShadow/box-shadow.css"; -@use "@patternfly/react-styles/css/utilities/Text/text.css"; @use "@assets/_variables.scss" as branding; .layout { From a20adc8dede51862d9b5844f59cd24ef1a3b2a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Mon, 2 Jan 2023 18:00:31 +0000 Subject: [PATCH 03/23] [web] Simplify the layout By using CSS Grid Layout[1], CSS Flexible Box Layout (aka Flexbox), and starting to set the foundations to follow the CubeCSS[3] methodology. [1] https://www.w3.org/TR/css-grid-1/ [2] https://www.w3.org/TR/css-flexbox-1 [3] https://cube.fyi/ --- web/src/app.scss | 16 +-- web/src/assets/_variables.scss | 17 +++ web/src/components/layout/Layout.jsx | 36 +++---- web/src/components/layout/layout.scss | 148 ++++++++------------------ web/src/index.html | 2 +- web/src/index.js | 2 +- 6 files changed, 76 insertions(+), 145 deletions(-) diff --git a/web/src/app.scss b/web/src/app.scss index 6d63d9901a..0fe827c137 100644 --- a/web/src/app.scss +++ b/web/src/app.scss @@ -22,29 +22,15 @@ body { } h1, h2, h3, h4, h5, h6 { + margin: 0; font-family: fonts.$headlines; font-weight: 500; } -h1, h2, h3 { - margin-block-start: 20px; - margin-block-end: 10px; -} - -h4, h5, h6 { - margin-block-start: 10px; - margin-block-end: 10px; -} - p { margin-block-start: fonts.$size-base; } -#root { - min-block-size: 100vh; - background-color: branding.$bc-gray-50; -} - .installation-overview-section { // FIXME: look for a better approach about this. // It overrides inline paddings for "button links" since using "isInline" prop diff --git a/web/src/assets/_variables.scss b/web/src/assets/_variables.scss index fb84129c61..0e6d0f2f89 100644 --- a/web/src/assets/_variables.scss +++ b/web/src/assets/_variables.scss @@ -5,3 +5,20 @@ $bc-gray-1000: #141823; //rgb(20, 24, 35); $bc-green-500: #30ba78; //rgb(48, 186, 120); $bc-green-900: #0e7e3c; //rgb(14, 126, 60); $bc-pine-500: #0c322c; //rgb(12, 50, 44); + +:root { + --color-core-brand: #30BA78; // Jungle Green + --color-core-primary: #0C322C; // Pine Green + --color-core-secondary: #192072; // Midnight Blue + --color-core-tertiary: #90EBCD; // Midnight Blue + + --color-background-primary: var(--color-core-primary); + --color-background-secondary: #EFEFEF; // Fog + + --color-text-primary: var(--color-core-primary); + --color-text-secondary: #EFEFEF; + + --space-s: .5em; + --space-m: 1em; + --space-l: 1.5em; +} diff --git a/web/src/components/layout/Layout.jsx b/web/src/components/layout/Layout.jsx index 693f424fda..5eb39c1cc9 100644 --- a/web/src/components/layout/Layout.jsx +++ b/web/src/components/layout/Layout.jsx @@ -57,36 +57,28 @@ const FooterInfoArea = createTeleporter(); * */ function Layout({ children }) { - const responsiveWidthRules = "pf-u-w-66-on-lg pf-u-w-50-on-xl pf-u-w-33-on-2xl"; - const className = `layout ${responsiveWidthRules}`; - return ( -
-
-
-

- - -

-
+ <> +
+

+ + +

- -
+ + -
{children}
+
{children}
-
-
- Logo of SUSE - -
+
-
-
+ + Logo of SUSE + + ); } diff --git a/web/src/components/layout/layout.scss b/web/src/components/layout/layout.scss index b9d81453d9..b115c4fe34 100644 --- a/web/src/components/layout/layout.scss +++ b/web/src/components/layout/layout.scss @@ -1,135 +1,71 @@ // See https://github.com/patternfly/patternfly/pull/4297 -@use "@patternfly/react-styles/css/utilities/BoxShadow/box-shadow.css"; -@use "@assets/_variables.scss" as branding; -.layout { - --header-block-size: 8ex; - --footer-block-size: calc(1.5 * var(--header-block-size)); - --min-layout-content-block-size: calc(100vh - var(--header-block-size)); - --layout-content-padding: 1.3rem; - --layout-content-padding-block-end: calc( - var(--layout-content-padding) - + var(--footer-block-size) - ); - - @extend .pf-u-box-shadow-md; - - background-color: white; - margin-inline: auto; - - // Needed for "telling" the fixed footer its (inherited) inline-size. - inline-size: 100%; +h1, h2, h3, h4, h5 { + margin: 0; } -.layout__header { - @extend .pf-u-box-shadow-md-bottom; - - // Note: "position: fixed" + "width: inherit" does not work here. Sticky is enough for the header - position: sticky; - z-index: 100; - inset-block-start: 0; - - background-color: branding.$bc-pine-500; - color: white; - - block-size: var(--header-block-size); - padding: 0.5rem; - - display: flex; - align-items: center; - justify-content: space-between; - gap: 0.5rem; - - h1 { - margin-block-start: 10px; - } +body { + background: #ccc; } -.layout__header-section-actions { - button { - vertical-align: text-top; - } +#d-installer { + display: grid; + grid-template-rows: auto 1fr auto; + grid-template-areas: + 'header' + 'content' + 'footer' + ; + overflow: hidden; + height: 100dvb; + block-size: 100dvb; + background: white; svg { - fill: white; + fill: currentColor; vertical-align: middle; } } -.layout__header-action-icon { - fill: white; - block-size: 1.5rem; - inline-size: 1.5rem; - vertical-align: middle; +#d-installer > * { + padding: var(--space-m) var(--space-s); } -.layout__header-section-title { - font-size: 1.5rem; +@media (width > 50em) { + #d-installer { + max-inline-size: 50em; + margin-inline: auto; + } } -.layout__header-section-title-icon > svg { - fill: white; - // Sadly, we can't use font-size with SVG icons - block-size: 1em; - inline-size: 1em; - vertical-align: sub; - margin-inline-end: 0.5em; +// utility, stand for "margin-inline-end-small"; +.mie-s { + margin-inline-end: var(--space-s); } -.layout__content { - padding: var(--layout-content-padding); - padding-block-end: var(--layout-content-padding-block-end); - min-block-size: var(--min-layout-content-block-size); +#d-installer > header { + grid-area: header; + background: var(--color-background-primary); + color: var(--color-text-secondary); } -// Needed because a block-size: 100% is not an option when the parent does not -// have an explicit block-size (it has a min-block-size instead). -// See https://stackoverflow.com/a/8468131 and https://www.w3.org/TR/CSS22/visudet.html#the-height-property -.layout__content-child--filling-block-size { - // NOTE: "min-block-size: inherit;" does not work for us. It produces padding - // that we do not want unless necessary. Moreover, the .layout__content - // container element already produce needed padding. - min-block-size: calc( - var(--min-layout-content-block-size) - - var(--layout-content-padding) - - var(--layout-content-padding-block-end) - ); +#d-installer > main { + grid-area: content; + overflow-y: auto; // Sadly, only Firefox supports oerflow-block at this moment (Jan 2023) + overflow-block: auto; + padding: var(--space-l); } -.layout__footer { - @extend .pf-u-box-shadow-sm-top; - - position: fixed; - inset-block-end: 0; - - background-color: white; - - block-size: var(--footer-block-size); - inline-size: inherit; - padding: 1rem; - - display: flex; - justify-content: space-between; - align-items: center; - - gap: 1rem 1rem; +#d-installer > footer { + grid-area: footer; } -.layout__footer-info-area { +.flow-flex-row { display: flex; align-items: center; - - .company-logo { - width: 120px; - margin-inline-start: -1rem; - } + justify-content: space-between; } -.layout__footer-actions-area { - align-self: center; - text-align: center; - - display: flex; - justify-content: end; - gap: 1rem; +.flow-flex-row[data-state='reversed'] { + flex-direction: row-reverse; } diff --git a/web/src/index.html b/web/src/index.html index dc2be5d387..ed95deb8dc 100644 --- a/web/src/index.html +++ b/web/src/index.html @@ -8,7 +8,7 @@ D-Installer -
+
diff --git a/web/src/index.js b/web/src/index.js index 352976f056..f491c12f4f 100644 --- a/web/src/index.js +++ b/web/src/index.js @@ -69,5 +69,5 @@ ReactDOM.render( , - document.getElementById("root") + document.getElementById("d-installer") ); From cb1488b931bf987ff5c307da7f3e62d0f514c254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 3 Jan 2023 11:59:09 +0000 Subject: [PATCH 04/23] [web] Stop using PatternFly layout components I.e., Flex, Split, Stack, and Bullseye. The latest also include our Center component. They are going to be replaced by custom CSS utilities, which hopefully will help to reduce the components complexity and the amount of DOM nodes. --- .../components/core/InstallationFinished.jsx | 34 +++++----- .../components/core/InstallationProgress.jsx | 4 +- web/src/components/core/ProgressReport.jsx | 52 +++++++------- web/src/components/core/Section.jsx | 52 +++++--------- web/src/components/layout/Center.jsx | 29 -------- web/src/components/layout/DBusError.jsx | 21 +++--- .../components/layout/LoadingEnvironment.jsx | 16 ++--- web/src/components/layout/index.js | 1 - web/src/components/layout/layout.scss | 24 +++++++ .../components/network/AddressesDataList.jsx | 36 ++++------ web/src/components/network/DnsDataList.jsx | 34 +++------- web/src/components/network/Network.jsx | 48 +++++++------ .../components/network/WifiConnectionForm.jsx | 2 +- .../network/WifiHiddenNetworkForm.jsx | 29 +++----- .../network/WifiNetworkListItem.jsx | 68 +++++++------------ web/src/components/overview/Overview.jsx | 30 +++----- .../components/overview/StorageSection.jsx | 30 +++----- .../questions/LuksActivationQuestion.jsx | 42 +++++------- .../components/storage/ProposalActions.jsx | 40 +++++------ web/src/components/storage/ProposalPage.jsx | 48 ++++++------- web/src/components/users/Users.jsx | 15 +--- 21 files changed, 265 insertions(+), 390 deletions(-) delete mode 100644 web/src/components/layout/Center.jsx diff --git a/web/src/components/core/InstallationFinished.jsx b/web/src/components/core/InstallationFinished.jsx index 16975ba13d..a40496e894 100644 --- a/web/src/components/core/InstallationFinished.jsx +++ b/web/src/components/core/InstallationFinished.jsx @@ -29,7 +29,7 @@ import { EmptyStateBody } from "@patternfly/react-core"; -import { Icon, Center, Title as SectionTitle, PageIcon, MainActions } from "@components/layout"; +import { Icon, Title as SectionTitle, PageIcon, MainActions } from "@components/layout"; import { useInstallerClient } from "@context/installer"; function InstallationFinished() { @@ -46,23 +46,21 @@ function InstallationFinished() { -
- - } className="success-icon" /> - - Congratulations! - - -
- The installation on your machine is complete. - - At this point you can 'Reboot' the machine to log in to the new system. - - Have a lot of fun! Your openSUSE Development Team. -
-
-
-
+ + } className="success-icon" /> + + Congratulations! + + +
+ The installation on your machine is complete. + + At this point you can 'Reboot' the machine to log in to the new system. + + Have a lot of fun! Your openSUSE Development Team. +
+
+
); } diff --git a/web/src/components/core/InstallationProgress.jsx b/web/src/components/core/InstallationProgress.jsx index c7bca7ec44..6162e2f39e 100644 --- a/web/src/components/core/InstallationProgress.jsx +++ b/web/src/components/core/InstallationProgress.jsx @@ -22,7 +22,7 @@ import React from "react"; import ProgressReport from "./ProgressReport"; -import { Center, Icon, Title, PageIcon } from "@components/layout"; +import { Icon, Title, PageIcon } from "@components/layout"; import { Questions } from "@components/questions"; function InstallationProgress() { @@ -30,7 +30,7 @@ function InstallationProgress() { <> Installing -
+ ); diff --git a/web/src/components/core/ProgressReport.jsx b/web/src/components/core/ProgressReport.jsx index eb708f7826..93d4396f3a 100644 --- a/web/src/components/core/ProgressReport.jsx +++ b/web/src/components/core/ProgressReport.jsx @@ -23,7 +23,7 @@ import React, { useState, useEffect } from "react"; import { useCancellablePromise } from "@/utils"; import { useInstallerClient } from "@context/installer"; -import { Progress, Stack, StackItem, Text } from "@patternfly/react-core"; +import { Progress, Text } from "@patternfly/react-core"; const ProgressReport = () => { const client = useInstallerClient(); @@ -54,36 +54,32 @@ const ProgressReport = () => { }); }, [client.software]); - if (!progress.steps) return Waiting for progress status...; + if (!progress.steps) return Waiting for progress status...; return ( - - - - +
+ - - - - + +
); }; diff --git a/web/src/components/core/Section.jsx b/web/src/components/core/Section.jsx index 58db408c21..e51c088182 100644 --- a/web/src/components/core/Section.jsx +++ b/web/src/components/core/Section.jsx @@ -24,10 +24,6 @@ import React from "react"; import { Button, - Split, - SplitItem, - Stack, - StackItem, Text, TextContent, TextVariants, @@ -109,7 +105,6 @@ const renderIcon = (icon, ariaLabel, size = 32) => { * @param {React.ReactNode} [props.actionTooltip] - text to be shown as a tooltip when user hovers action icon, if present * @param {React.MouseEventHandler} [props.onActionClick] - callback to be triggered when user clicks on action icon, if present * @param {JSX.Element} [props.children] - the section content - * @param {object} [props.otherProps] PF4/Split props, see {@link https://www.patternfly.org/v4/layouts/split#props} */ export default function Section({ title, @@ -121,7 +116,6 @@ export default function Section({ actionTooltip, onActionClick, children, - ...otherProps }) { const renderAction = () => { if (typeof onActionClick !== 'function') return null; @@ -147,34 +141,22 @@ export default function Section({ ); return ( - - - {renderIcon(icon, `${title} section icon`, 32)} - - - - - - - {title} {renderAction()} - - - - { description && description !== "" && - - - - {description} - - - } - { errors?.length > 0 && - - - } - {children} - - - +
+ {renderIcon(icon, `${title} section icon`, 32)} + + + {title} {renderAction()} + + + { description && description !== "" && + + + {description} + + } + { errors?.length > 0 && + } + {children} +
); } diff --git a/web/src/components/layout/Center.jsx b/web/src/components/layout/Center.jsx deleted file mode 100644 index bea4fb1d6d..0000000000 --- a/web/src/components/layout/Center.jsx +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) [2022] SUSE LLC - * - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, contact SUSE LLC. - * - * To contact SUSE LLC about this file by physical or electronic mail, you may - * find current contact information at www.suse.com. - */ - -import React from "react"; -import { Bullseye } from "@patternfly/react-core"; - -const Center = ({ children }) => ( - {children} -); - -export default Center; diff --git a/web/src/components/layout/DBusError.jsx b/web/src/components/layout/DBusError.jsx index 8d9510f8ff..9d04cee38b 100644 --- a/web/src/components/layout/DBusError.jsx +++ b/web/src/components/layout/DBusError.jsx @@ -24,7 +24,6 @@ import { Button, Title, EmptyState, EmptyStateIcon, EmptyStateBody } from "@patt import { Icon, - Center, MainActions, PageIcon, Title as PageTitle, @@ -44,17 +43,15 @@ function DBusError() { -
- - } /> - - Cannot connect to D-Bus - - - Could not connect to the D-Bus service. Please, check whether it is running. - - -
+ + } /> + + Cannot connect to D-Bus + + + Could not connect to the D-Bus service. Please, check whether it is running. + + ); } diff --git a/web/src/components/layout/LoadingEnvironment.jsx b/web/src/components/layout/LoadingEnvironment.jsx index e34ea8754c..48133e10fb 100644 --- a/web/src/components/layout/LoadingEnvironment.jsx +++ b/web/src/components/layout/LoadingEnvironment.jsx @@ -22,18 +22,16 @@ import React from "react"; import { Title, EmptyState, EmptyStateIcon } from "@patternfly/react-core"; -import { Icon, Center } from "@components/layout"; +import { Icon } from "@components/layout"; function LoadingEnvironment({ text = "Loading installation environment, please wait." }) { return ( -
- - } /> - - { text } - - -
+ + } /> + + { text } + + ); } diff --git a/web/src/components/layout/index.js b/web/src/components/layout/index.js index 6e21f5df63..518e317179 100644 --- a/web/src/components/layout/index.js +++ b/web/src/components/layout/index.js @@ -22,6 +22,5 @@ export * from "./Layout"; export { default as Layout } from "./Layout"; export { default as Icon } from "./Icon"; -export { default as Center } from "./Center"; export { default as DBusError } from "./DBusError"; export { default as LoadingEnvironment } from "./LoadingEnvironment"; diff --git a/web/src/components/layout/layout.scss b/web/src/components/layout/layout.scss index b115c4fe34..48cd74c443 100644 --- a/web/src/components/layout/layout.scss +++ b/web/src/components/layout/layout.scss @@ -54,6 +54,8 @@ body { overflow-y: auto; // Sadly, only Firefox supports oerflow-block at this moment (Jan 2023) overflow-block: auto; padding: var(--space-l); + + display: grid; // Sadly, only Firefox allow native subgrids. } #d-installer > footer { @@ -69,3 +71,25 @@ body { .flow-flex-row[data-state='reversed'] { flex-direction: row-reverse; } + +.vertically-centered { + align-self: center; +} + +.horizontally-centered { + inline-size: 100%; + margin-inline: 0 auto; + text-align: center; +} + +.has-gutter { + gap: var(--space-s); +} + +.has-gutter-size-1 { + gap: var(--space-m); +} + +.pad-size-1 { + padding: var(--space-m) +} diff --git a/web/src/components/network/AddressesDataList.jsx b/web/src/components/network/AddressesDataList.jsx index c17ef6d7f7..6197d8d486 100644 --- a/web/src/components/network/AddressesDataList.jsx +++ b/web/src/components/network/AddressesDataList.jsx @@ -34,8 +34,6 @@ import { DataListItemCells, DataListCell, DataListAction, - Stack, - StackItem, Split, SplitItem } from "@patternfly/react-core"; @@ -118,24 +116,20 @@ export default function AddressesDataList({ const newAddressButtonText = addresses.length ? "Add another address" : "Add an address"; return ( - - - - - Addresses - - - - - - - - - {addresses.map(address => renderAddress(address))} - - - + <> + + + Addresses + + + + + + + {addresses.map(address => renderAddress(address))} + + ); } diff --git a/web/src/components/network/DnsDataList.jsx b/web/src/components/network/DnsDataList.jsx index f64681956f..d0c63a83e2 100644 --- a/web/src/components/network/DnsDataList.jsx +++ b/web/src/components/network/DnsDataList.jsx @@ -33,11 +33,7 @@ import { DataListItemRow, DataListItemCells, DataListCell, - DataListAction, - Stack, - StackItem, - Split, - SplitItem + DataListAction } from "@patternfly/react-core"; import { FormLabel } from "@components/core"; @@ -96,24 +92,14 @@ export default function DnsDataList({ servers: originalServers, updateDnsServers const newDnsButtonText = servers.length ? "Add another DNS" : "Add DNS"; return ( - - - - - DNS - - - - - - - - - {servers.map(server => renderDns(server))} - - - + <> + DNS + + + {servers.map(server => renderDns(server))} + + ); } diff --git a/web/src/components/network/Network.jsx b/web/src/components/network/Network.jsx index 50264f86bd..a3ccfab70d 100644 --- a/web/src/components/network/Network.jsx +++ b/web/src/components/network/Network.jsx @@ -20,7 +20,7 @@ */ import React, { useEffect, useState } from "react"; -import { Button, Stack, StackItem } from "@patternfly/react-core"; +import { Button } from "@patternfly/react-core"; import { useInstallerClient } from "@context/installer"; import { ConnectionTypes, NetworkEventTypes } from "@client/network"; @@ -30,7 +30,6 @@ export default function Network() { const client = useInstallerClient(); const [initialized, setInitialized] = useState(false); const [connections, setConnections] = useState([]); - const [wifiSelectorOpen, setWifiSelectorOpen] = useState(false); const [wifiScanSupported, setWifiScanSupported] = useState(false); useEffect(() => { @@ -81,23 +80,34 @@ export default function Network() { const activeWifiConnections = connections.filter(c => c.type === ConnectionTypes.WIFI); const showNetwork = (activeWiredConnections.length > 0 || activeWifiConnections.length > 0); + const Content = () => { + if (!showNetwork) { + return "No network connection was detected"; + } + + return ( + <> + + + + ); + }; + + const WifiOptions = () => { + const [wifiSelectorOpen, setWifiSelectorOpen] = useState(false); + + return ( + <> + + setWifiSelectorOpen(false)} /> + + ); + }; + return ( - - { showNetwork && - <> - - - - - - - } - { !showNetwork && No network connection was detected } - { wifiScanSupported && - - - setWifiSelectorOpen(false)} /> - } - + <> + + { wifiScanSupported && } + ); } diff --git a/web/src/components/network/WifiConnectionForm.jsx b/web/src/components/network/WifiConnectionForm.jsx index 03a98b082d..ef3911b96a 100644 --- a/web/src/components/network/WifiConnectionForm.jsx +++ b/web/src/components/network/WifiConnectionForm.jsx @@ -82,7 +82,7 @@ export default function WifiConnectionForm({ network, onCancel, onSubmitCallback }; return ( -
+ { error &&

Please, review provided settings and try again.

diff --git a/web/src/components/network/WifiHiddenNetworkForm.jsx b/web/src/components/network/WifiHiddenNetworkForm.jsx index af359a97fc..0ad996580f 100644 --- a/web/src/components/network/WifiHiddenNetworkForm.jsx +++ b/web/src/components/network/WifiHiddenNetworkForm.jsx @@ -24,13 +24,10 @@ import React from "react"; import { Button, Card, - CardBody, - Split, - SplitItem, + CardBody } from "@patternfly/react-core"; import { classNames } from "@/utils"; -import { Center } from "@components/layout"; import WifiConnectionForm from "./WifiConnectionForm"; /** @@ -52,24 +49,18 @@ function HiddenNetworkForm({ network, visible, beforeDisplaying, beforeHiding, o )} > - - - { visible && - } - - + { visible && + } { !visible && -
- -
} + } ); } diff --git a/web/src/components/network/WifiNetworkListItem.jsx b/web/src/components/network/WifiNetworkListItem.jsx index 48a9aeaf1d..f130641ddc 100644 --- a/web/src/components/network/WifiNetworkListItem.jsx +++ b/web/src/components/network/WifiNetworkListItem.jsx @@ -26,15 +26,13 @@ import { CardBody, Radio, Spinner, - Split, - SplitItem, Text } from "@patternfly/react-core"; import { classNames } from "@/utils"; import { ConnectionState } from "@client/network/model"; -import { Center, Icon } from "@components/layout"; +import { Icon } from "@components/layout"; import { WifiNetworkMenu, WifiConnectionForm } from "@components/network"; const networkState = (state) => { @@ -83,47 +81,31 @@ function WifiNetworkListItem ({ network, isSelected, isActive, onSelect, onCance )} > - - - - {network.security.join(", ")}{" "} - {network.strength} - - } - isChecked={isSelected || isActive || false} - onClick={onSelect} - /> - - -
- {showSpinner && } -
-
- -
- - { showSpinner && !network.connection && "Connecting" } - { networkState(network.connection?.state)} - -
-
- { network.settings && - -
- -
-
} -
+
+ + {network.security.join(", ")}{" "} + {network.strength} + + } + isChecked={isSelected || isActive || false} + onClick={onSelect} + /> +
+ {showSpinner && } + + { showSpinner && !network.connection && "Connecting" } + { networkState(network.connection?.state)} + + { network.settings && + } +
+
{ isSelected && (!network.settings || network.settings.error) && - - - - - } + }
); diff --git a/web/src/components/overview/Overview.jsx b/web/src/components/overview/Overview.jsx index 0a40d0e546..2df376c484 100644 --- a/web/src/components/overview/Overview.jsx +++ b/web/src/components/overview/Overview.jsx @@ -23,7 +23,7 @@ import React, { useState } from "react"; import { useNavigate, Navigate } from "react-router-dom"; import { useSoftware } from "@context/software"; -import { Button, Flex, FlexItem } from "@patternfly/react-core"; +import { Button } from "@patternfly/react-core"; import { Icon, Title, PageIcon, PageActions, MainActions } from "@components/layout"; import { Section, InstallButton } from "@components/core"; @@ -59,32 +59,20 @@ function Overview() { return ; } - const sections = [ -
}> - -
, -
}> - -
, - , - - ]; - - const Sections = () => { - return sections.map((section, i) => ( - - {section} - - )); - }; - return ( <> {selectedProduct && selectedProduct.name} setShowErrors(true)} /> - +
}> + +
+
}> + +
+ + ); } diff --git a/web/src/components/overview/StorageSection.jsx b/web/src/components/overview/StorageSection.jsx index d0d3bf8b1c..3bda627781 100644 --- a/web/src/components/overview/StorageSection.jsx +++ b/web/src/components/overview/StorageSection.jsx @@ -22,11 +22,7 @@ import React, { useReducer, useEffect } from "react"; import { useNavigate } from "react-router-dom"; -import { - Button, - Stack, - StackItem -} from '@patternfly/react-core'; +import { Button } from '@patternfly/react-core'; import { useCancellablePromise } from "@/utils"; import { useInstallerClient } from "@context/installer"; @@ -94,20 +90,16 @@ export default function StorageSection ({ showErrors }) { if (state.busy || !state.proposal) return ; return ( - - - - - - - - + <> + + + ); }; diff --git a/web/src/components/questions/LuksActivationQuestion.jsx b/web/src/components/questions/LuksActivationQuestion.jsx index 452a97f699..b3180eb3cb 100644 --- a/web/src/components/questions/LuksActivationQuestion.jsx +++ b/web/src/components/questions/LuksActivationQuestion.jsx @@ -20,7 +20,7 @@ */ import React, { useState } from "react"; -import { Alert, Form, FormGroup, Stack, StackItem, Text, TextInput } from "@patternfly/react-core"; +import { Alert, Form, FormGroup, Text, TextInput } from "@patternfly/react-core"; import { Icon } from "@components/layout"; import { Popup } from "@components/core"; import { QuestionActions } from "@components/questions"; @@ -29,9 +29,7 @@ const renderAlert = (attempt) => { if (!attempt || attempt === 1) return null; return ( - - - + ); }; @@ -60,27 +58,21 @@ export default function LuksActivationQuestion({ question, answerCallback }) { aria-label="Question" titleIconVariant={() => } > - - { renderAlert(question.attempt) } - - - { question.text } - - - - - - - - - - + { renderAlert(question.attempt) } + + { question.text } + +
+ + + +
- - - Actions to perform for creating the file systems and for ensuring the system boots. - - - - {renderActionsList(generalActions)} - {subvolActions.length > 0 && ( - setIsExpanded(!isExpanded)} - toggleText={toggleText} - className="expandable-actions" - > - {renderActionsList(subvolActions)} - - )} - -
+ <> + + Actions to perform for creating the file systems and for ensuring the system boots. + + {renderActionsList(generalActions)} + {subvolActions.length > 0 && ( + setIsExpanded(!isExpanded)} + toggleText={toggleText} + className="expandable-actions" + > + {renderActionsList(subvolActions)} + + )} + ); } diff --git a/web/src/components/storage/ProposalPage.jsx b/web/src/components/storage/ProposalPage.jsx index d8c65b5262..4104546a35 100644 --- a/web/src/components/storage/ProposalPage.jsx +++ b/web/src/components/storage/ProposalPage.jsx @@ -25,8 +25,6 @@ import { useNavigate } from "react-router-dom"; import { Alert, Button, - Flex, - FlexItem, } from "@patternfly/react-core"; import { useInstallerClient } from "@context/installer"; @@ -98,33 +96,25 @@ export default function ProposalPage() { if (state.busy || !state.proposal) return ; return ( - - - } - title="Devices will not be modified until installation starts." - /> - - - - - - - - - - - + <> + } + title="Devices will not be modified until installation starts." + /> + + + + ); }; diff --git a/web/src/components/users/Users.jsx b/web/src/components/users/Users.jsx index 58edd73f86..f7762426a4 100644 --- a/web/src/components/users/Users.jsx +++ b/web/src/components/users/Users.jsx @@ -20,7 +20,6 @@ */ import React, { useEffect, useState } from "react"; -import { Stack, StackItem } from "@patternfly/react-core"; import { useInstallerClient } from "@context/installer"; import { Section } from "@components/core"; @@ -44,17 +43,9 @@ export default function Users({ showErrors }) { icon={() => } errors={showErrors ? errors : []} > - - - - - - - - - - - + + + ); From 7db9c6f4a69bccce4494375453a35965cc44d2d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 3 Jan 2023 16:37:36 +0000 Subject: [PATCH 05/23] [web] Bring back Center component temporary Because latest Firefox versions does not support the rationale (:has) pseudo-selector yet. * https://www.w3.org/TR/selectors-4/#relational * https://developer.mozilla.org/en-US/docs/Web/CSS/:has#browser_compatibility --- .../components/core/InstallationFinished.jsx | 8 +-- .../components/core/InstallationProgress.jsx | 4 +- web/src/components/core/ProgressReport.jsx | 6 +- web/src/components/layout/Center.jsx | 55 +++++++++++++++++++ web/src/components/layout/DBusError.jsx | 7 ++- web/src/components/layout/Layout.jsx | 2 +- .../components/layout/LoadingEnvironment.jsx | 16 +++--- web/src/components/layout/index.js | 1 + web/src/components/layout/layout.scss | 16 +++++- 9 files changed, 94 insertions(+), 21 deletions(-) create mode 100644 web/src/components/layout/Center.jsx diff --git a/web/src/components/core/InstallationFinished.jsx b/web/src/components/core/InstallationFinished.jsx index a40496e894..9babd310ad 100644 --- a/web/src/components/core/InstallationFinished.jsx +++ b/web/src/components/core/InstallationFinished.jsx @@ -29,7 +29,7 @@ import { EmptyStateBody } from "@patternfly/react-core"; -import { Icon, Title as SectionTitle, PageIcon, MainActions } from "@components/layout"; +import { Center, Icon, Title as SectionTitle, PageIcon, MainActions } from "@components/layout"; import { useInstallerClient } from "@context/installer"; function InstallationFinished() { @@ -37,7 +37,7 @@ function InstallationFinished() { const onRebootAction = () => client.manager.rebootSystem(); return ( - <> +
Installation Finished @@ -46,7 +46,7 @@ function InstallationFinished() { - + } className="success-icon" /> Congratulations! @@ -61,7 +61,7 @@ function InstallationFinished() { </div> </EmptyStateBody> </EmptyState> - </> + </Center> ); } diff --git a/web/src/components/core/InstallationProgress.jsx b/web/src/components/core/InstallationProgress.jsx index 6162e2f39e..c7bca7ec44 100644 --- a/web/src/components/core/InstallationProgress.jsx +++ b/web/src/components/core/InstallationProgress.jsx @@ -22,7 +22,7 @@ import React from "react"; import ProgressReport from "./ProgressReport"; -import { Icon, Title, PageIcon } from "@components/layout"; +import { Center, Icon, Title, PageIcon } from "@components/layout"; import { Questions } from "@components/questions"; function InstallationProgress() { @@ -30,7 +30,7 @@ function InstallationProgress() { <> <Title>Installing - +
); diff --git a/web/src/components/core/ProgressReport.jsx b/web/src/components/core/ProgressReport.jsx index 93d4396f3a..68601b722e 100644 --- a/web/src/components/core/ProgressReport.jsx +++ b/web/src/components/core/ProgressReport.jsx @@ -54,10 +54,10 @@ const ProgressReport = () => { }); }, [client.software]); - if (!progress.steps) return Waiting for progress status...; + if (!progress.steps) return Waiting for progress status...; return ( -
+ <> { aria-label={subProgress?.message || " "} aria-hidden={!subProgress} /> -
+ ); }; diff --git a/web/src/components/layout/Center.jsx b/web/src/components/layout/Center.jsx new file mode 100644 index 0000000000..1d79b6560a --- /dev/null +++ b/web/src/components/layout/Center.jsx @@ -0,0 +1,55 @@ +/* + * Copyright (c) [2022] SUSE LLC + * + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, contact SUSE LLC. + * + * To contact SUSE LLC about this file by physical or electronic mail, you may + * find current contact information at www.suse.com. + */ + +import React from "react"; + +/** + * Wrapper component for centering vertically its children + * + * @note It could be relaced by the 'vertically-centered' CSS utility class once Firefox add support + * by default for the :has selector, which allows having something like + * + * .parent:has(.vertically-centered) { + * display: grid; + * place-items: center; + * block-size: 100%; + * } + * + * .vertically-centered { inline-size: 100%; } + * + * We can use \@support CSS at rule and use a workaround when :has not available, but somehow + * prefer waiting until Firefox get support. + * + * To know more, read + * - https://www.w3.org/TR/selectors-4/#relational + * - https://ishadeed.com/article/css-has-parent-selector/ + * + * @param {React.ReactNode} [props.children] + */ +const Center = ({ children }) => ( +
+
+ {children} +
+
+); + +export default Center; diff --git a/web/src/components/layout/DBusError.jsx b/web/src/components/layout/DBusError.jsx index 9d04cee38b..8f7e120387 100644 --- a/web/src/components/layout/DBusError.jsx +++ b/web/src/components/layout/DBusError.jsx @@ -23,6 +23,7 @@ import React from "react"; import { Button, Title, EmptyState, EmptyStateIcon, EmptyStateBody } from "@patternfly/react-core"; import { + Center, Icon, MainActions, PageIcon, @@ -38,12 +39,12 @@ const ReloadAction = () => ( function DBusError() { return ( - <> +
D-Bus Error - + } /> Cannot connect to D-Bus @@ -52,7 +53,7 @@ function DBusError() { Could not connect to the D-Bus service. Please, check whether it is running. </EmptyStateBody> </EmptyState> - </> + </Center> ); } diff --git a/web/src/components/layout/Layout.jsx b/web/src/components/layout/Layout.jsx index 5eb39c1cc9..7b5823ac59 100644 --- a/web/src/components/layout/Layout.jsx +++ b/web/src/components/layout/Layout.jsx @@ -68,7 +68,7 @@ function Layout({ children }) { <HeaderActions.Target as="span" /> </header> - <main>{children}</main> + <main className="">{children}</main> <footer className="flow-flex-row" data-state="reversed"> <FooterActions.Target diff --git a/web/src/components/layout/LoadingEnvironment.jsx b/web/src/components/layout/LoadingEnvironment.jsx index 48133e10fb..4547845fc3 100644 --- a/web/src/components/layout/LoadingEnvironment.jsx +++ b/web/src/components/layout/LoadingEnvironment.jsx @@ -22,16 +22,18 @@ import React from "react"; import { Title, EmptyState, EmptyStateIcon } from "@patternfly/react-core"; -import { Icon } from "@components/layout"; +import { Center, Icon } from "@components/layout"; function LoadingEnvironment({ text = "Loading installation environment, please wait." }) { return ( - <EmptyState className="vertically-centered"> - <EmptyStateIcon icon={({ ...props }) => <Icon name="loading" {...props} />} /> - <Title headingLevel="h2" size="4xl"> - { text } - - +
+ + } /> + + { text } + + +
); } diff --git a/web/src/components/layout/index.js b/web/src/components/layout/index.js index 518e317179..6e21f5df63 100644 --- a/web/src/components/layout/index.js +++ b/web/src/components/layout/index.js @@ -22,5 +22,6 @@ export * from "./Layout"; export { default as Layout } from "./Layout"; export { default as Icon } from "./Icon"; +export { default as Center } from "./Center"; export { default as DBusError } from "./DBusError"; export { default as LoadingEnvironment } from "./LoadingEnvironment"; diff --git a/web/src/components/layout/layout.scss b/web/src/components/layout/layout.scss index 48cd74c443..9b56cf4c4c 100644 --- a/web/src/components/layout/layout.scss +++ b/web/src/components/layout/layout.scss @@ -72,8 +72,22 @@ body { flex-direction: row-reverse; } +// Sadly, Firefox does not support :has pseudo-selector yet. +// See @components/layout/Center documentation. +// +// main:has(.vertically-centered) { +// display: grid; +// place-items: center; +// block-size: 100%; +// } .vertically-centered { - align-self: center; + display: grid; + place-items: center; + block-size: 100%; +} + +.vertically-centered > div { + inline-size: 100%; } .horizontally-centered { From aa179bc0d38ae83128cc21f40dbe03853a01577b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 3 Jan 2023 16:39:29 +0000 Subject: [PATCH 06/23] [web] Add missing icon props --- web/src/components/core/InstallationFinished.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/core/InstallationFinished.jsx b/web/src/components/core/InstallationFinished.jsx index 9babd310ad..d3e14e6883 100644 --- a/web/src/components/core/InstallationFinished.jsx +++ b/web/src/components/core/InstallationFinished.jsx @@ -47,7 +47,7 @@ function InstallationFinished() { - } className="success-icon" /> + } className="success-icon" /> Congratulations! From 0393909585321277bcfae98e850770aa22e916df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 10 Jan 2023 08:49:18 +0000 Subject: [PATCH 07/23] [web] Change how to build WiFi networks list Using a native unordered list instead of PatternFly/Card, which was not designed for building lists[1]. [1] https://www.patternfly.org/v4/components/card/design-guidelines --- web/src/components/network/Network.jsx | 1 + .../components/network/WifiConnectionForm.jsx | 2 +- .../network/WifiHiddenNetworkForm.jsx | 32 +++------- .../network/WifiNetworkListItem.jsx | 64 ++++++++----------- .../components/network/WifiNetworksList.jsx | 63 ++++++++++++------ web/src/components/network/WifiSelector.jsx | 11 +--- 6 files changed, 87 insertions(+), 86 deletions(-) diff --git a/web/src/components/network/Network.jsx b/web/src/components/network/Network.jsx index a3ccfab70d..26c33d617b 100644 --- a/web/src/components/network/Network.jsx +++ b/web/src/components/network/Network.jsx @@ -24,6 +24,7 @@ import { Button } from "@patternfly/react-core"; import { useInstallerClient } from "@context/installer"; import { ConnectionTypes, NetworkEventTypes } from "@client/network"; +import { Icon } from "@components/layout"; import { NetworkWifiStatus, NetworkWiredStatus, WifiSelector } from "@components/network"; export default function Network() { diff --git a/web/src/components/network/WifiConnectionForm.jsx b/web/src/components/network/WifiConnectionForm.jsx index ef3911b96a..03a98b082d 100644 --- a/web/src/components/network/WifiConnectionForm.jsx +++ b/web/src/components/network/WifiConnectionForm.jsx @@ -82,7 +82,7 @@ export default function WifiConnectionForm({ network, onCancel, onSubmitCallback }; return ( -
+ { error &&

Please, review provided settings and try again.

diff --git a/web/src/components/network/WifiHiddenNetworkForm.jsx b/web/src/components/network/WifiHiddenNetworkForm.jsx index 0ad996580f..2eb6e7d3b8 100644 --- a/web/src/components/network/WifiHiddenNetworkForm.jsx +++ b/web/src/components/network/WifiHiddenNetworkForm.jsx @@ -21,13 +21,8 @@ import React from "react"; -import { - Button, - Card, - CardBody -} from "@patternfly/react-core"; +import { Button } from "@patternfly/react-core"; -import { classNames } from "@/utils"; import WifiConnectionForm from "./WifiConnectionForm"; /** @@ -39,24 +34,15 @@ import WifiConnectionForm from "./WifiConnectionForm"; * @param {function} props.beforeDisplaying - callback to trigger before displaying the form * @param {function} props.beforeHiding - callback to trigger before hiding the form */ -function HiddenNetworkForm({ network, visible, beforeDisplaying, beforeHiding, onSubmitCallback }) { +function WifiHiddenNetworkForm({ network, visible, beforeDisplaying, beforeHiding, onSubmitCallback }) { return ( <> - - - { visible && - } - - + { visible && + } { !visible && - - +
+ Addresses + +
{addresses.map(address => renderAddress(address))} From f5775f49d35c8da279d1f3d07fe90797ec81306e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 10 Jan 2023 14:59:40 +0000 Subject: [PATCH 09/23] [web] Restructure styles --- web/src/assets/_variables.scss | 24 --- web/src/{ => assets/styles}/app.scss | 99 +------------ web/src/assets/styles/blocks.scss | 52 +++++++ web/src/assets/styles/composition.scss | 14 ++ web/src/assets/{ => styles}/fonts.scss | 0 web/src/assets/styles/global.scss | 49 ++++++ web/src/assets/styles/index.scss | 11 ++ web/src/assets/styles/layout.scss | 0 .../assets/styles/patternfly-overrides.scss | 140 ++++++++++++++++++ web/src/assets/styles/utilities.scss | 88 +++++++++++ web/src/assets/styles/variables.scss | 57 +++++++ .../components/core/InstallationFinished.jsx | 2 +- web/src/components/core/Section.jsx | 83 +++++------ web/src/components/core/ValidationErrors.jsx | 6 +- web/src/components/core/fieldset.scss | 13 +- web/src/components/core/section.scss | 37 ----- .../components/language/LanguageSelector.jsx | 2 +- web/src/components/layout/Center.jsx | 2 +- web/src/components/layout/Icon.jsx | 2 +- web/src/components/layout/Layout.jsx | 8 +- web/src/components/layout/layout.scss | 72 +-------- .../components/network/AddressesDataList.jsx | 2 +- web/src/components/network/Network.jsx | 1 - .../network/WifiNetworkListItem.jsx | 7 +- .../components/network/WifiNetworksList.jsx | 6 +- web/src/components/network/WifiSelector.jsx | 2 +- web/src/components/overview/Overview.jsx | 4 +- .../components/overview/StorageSection.jsx | 9 +- .../storage/ProposalActionsSection.jsx | 2 +- .../storage/ProposalSettingsSection.jsx | 2 +- .../storage/ProposalTargetSection.jsx | 2 +- web/src/components/users/Users.jsx | 3 +- web/src/index.js | 13 +- web/src/patternfly.scss | 135 ----------------- 34 files changed, 498 insertions(+), 451 deletions(-) delete mode 100644 web/src/assets/_variables.scss rename web/src/{ => assets/styles}/app.scss (60%) create mode 100644 web/src/assets/styles/blocks.scss create mode 100644 web/src/assets/styles/composition.scss rename web/src/assets/{ => styles}/fonts.scss (100%) create mode 100644 web/src/assets/styles/global.scss create mode 100644 web/src/assets/styles/index.scss create mode 100644 web/src/assets/styles/layout.scss create mode 100644 web/src/assets/styles/patternfly-overrides.scss create mode 100644 web/src/assets/styles/utilities.scss create mode 100644 web/src/assets/styles/variables.scss delete mode 100644 web/src/components/core/section.scss delete mode 100644 web/src/patternfly.scss diff --git a/web/src/assets/_variables.scss b/web/src/assets/_variables.scss deleted file mode 100644 index 0e6d0f2f89..0000000000 --- a/web/src/assets/_variables.scss +++ /dev/null @@ -1,24 +0,0 @@ -$bc-gray-50: #f2f2f2; //rgb(242, 242, 242); -$bc-cerulean-500: #00b2e2; //rgb(0, 178, 226); -$bc-gray-900: #686565; //rgb(104, 101, 101); -$bc-gray-1000: #141823; //rgb(20, 24, 35); -$bc-green-500: #30ba78; //rgb(48, 186, 120); -$bc-green-900: #0e7e3c; //rgb(14, 126, 60); -$bc-pine-500: #0c322c; //rgb(12, 50, 44); - -:root { - --color-core-brand: #30BA78; // Jungle Green - --color-core-primary: #0C322C; // Pine Green - --color-core-secondary: #192072; // Midnight Blue - --color-core-tertiary: #90EBCD; // Midnight Blue - - --color-background-primary: var(--color-core-primary); - --color-background-secondary: #EFEFEF; // Fog - - --color-text-primary: var(--color-core-primary); - --color-text-secondary: #EFEFEF; - - --space-s: .5em; - --space-m: 1em; - --space-l: 1.5em; -} diff --git a/web/src/app.scss b/web/src/assets/styles/app.scss similarity index 60% rename from web/src/app.scss rename to web/src/assets/styles/app.scss index 0fe827c137..8ab7b3e30b 100644 --- a/web/src/app.scss +++ b/web/src/assets/styles/app.scss @@ -1,49 +1,3 @@ -@use "@assets/_variables.scss" as branding; - -// D-Installer fonts -@use "assets/fonts.scss"; - -// Style focus making use of :focus-visible -*:focus { - outline: none; -} - -*:focus:not(:focus-visible) { - box-shadow: none; -} - -*:focus-visible { - box-shadow: 0 0 0 1px branding.$bc-cerulean-500; -} - -body { - text-align: start; - color: branding.$bc-gray-1000; -} - -h1, h2, h3, h4, h5, h6 { - margin: 0; - font-family: fonts.$headlines; - font-weight: 500; -} - -p { - margin-block-start: fonts.$size-base; -} - -.installation-overview-section { - // FIXME: look for a better approach about this. - // It overrides inline paddings for "button links" since using "isInline" prop - // is not an option becaue it removes block margins too. - .pf-m-link { - padding-inline: 0; - } - - p { - margin-block-start: 0; - } -} - .loading-screen-icon { text-align: center; @@ -53,10 +7,6 @@ p { } } -.success-icon { - fill: branding.$bc-green-500; -} - // Make proposal actiosn compact .proposal-actions li + li { margin-block-start: 0; @@ -97,16 +47,16 @@ p { .pf-c-radio { // https://drafts.csswg.org/css-ui/#widget-accent // https://caniuse.com/mdn-css_properties_accent-color - accent-color: branding.$bc-pine-500; + accent-color: var(--color-primary-darkest); } .pf-c-radio__label { - color: branding.$bc-green-500; + color: var(--color-primary); font-weight: bold; } .pf-c-radio__description { - color: branding.$bc-pine-500; + color: var(--color-primary-darkest); } } @@ -124,7 +74,7 @@ p { .host-ip { vertical-align: middle; - color: branding.$bc-gray-900; + color: var(--color-gray); } ul.connections-datalist { @@ -171,13 +121,13 @@ button.remove-link:hover { // Custom styles for summary warnings .warning-text { color: var(--pf-global--warning-color--200); - font-size: calc(fonts.$size-base - 2px); + font-size: calc(var(--fs-base) - 2px); a, small { text-decoration: underline; margin-inline: 4px; color: var(--pf-global--warning-color--200); - font-size: calc(fonts.$size-base - 2px); + font-size: calc(var(--fs-base) - 2px); } svg { @@ -190,43 +140,6 @@ button.hidden-popover-button { display: inline; } -// Custom selection list -.selection-list-item { - transition: - font-size .15s ease-in-out, - font-weight .25s ease-in-out, - margin-block .15s ease-in-out, - box-shadow .35s ease-in-out; -} - -.selection-list-item .pf-c-card__body { - padding: 0; -} -.selection-list-item .pf-c-card__body .header { - border-block-end: 1px solid #eee; - padding: fonts.$size-base; -} - -.selection-list-item .pf-c-card__body .content { - padding: calc(fonts.$size-base * 2); -} - -.selection-list-focused-item { - margin-block: 20px; - box-shadow: 0 0 6px rgba(0,0,0,.16),0 6px 12px rgba(0,0,0,.32); -} - -.selection-list-focused-item .pf-c-radio input { - // Keep input vertically aligned with the label - margin-top: calc(var(--pf-c-radio__label--FontSize) * 0.3); -} - -.selection-list-checked-item .pf-c-radio label, -.selection-list-focused-item .pf-c-radio label { - font-size: calc(var(--pf-c-radio__label--FontSize) * 1.3); - font-weight: bold; -} - .danger-action { color: var(--pf-global--danger-color--200); svg { diff --git a/web/src/assets/styles/blocks.scss b/web/src/assets/styles/blocks.scss new file mode 100644 index 0000000000..57afc772e7 --- /dev/null +++ b/web/src/assets/styles/blocks.scss @@ -0,0 +1,52 @@ +// Standar section +section { + display: grid; + grid-template-columns: var(--icon-size-m) 1fr; + grid-template-areas: + "icon title" + ".... content" + ; + gap: var(--spacer-small); +} + +section > svg { + grid-aread: icon; +} + +section > h2 { + grid-area: title; +} + +section > .content { + grid-area: content; +} + +// Custom selection list +.selection-list > * { + border: 1px solid #eee; + transition: + font-size .15s ease-in-out, + font-weight .25s ease-in-out, + margin-block .15s ease-in-out, + box-shadow .35s ease-in-out; + + margin-block-start: -2px; +} + +.selection-list .header { + border-block-end: 1px solid #eee; + padding: var(--spacer-normal); +} + +.selection-list .content { + padding: var(--spacer-normal); +} + +.selection-list [data-state="focused"] { + margin-block: 20px; + box-shadow: 0 0 6px rgba(0,0,0,.16),0 6px 12px rgba(0,0,0,.32); +} + +.selection-list [data-state="unstyled"] { + border: 0; +} diff --git a/web/src/assets/styles/composition.scss b/web/src/assets/styles/composition.scss new file mode 100644 index 0000000000..fb8a3bc8eb --- /dev/null +++ b/web/src/assets/styles/composition.scss @@ -0,0 +1,14 @@ +// .stack > * + * { +.stack > :where(:not(:first-child)) { + margin-block-start: var(--stack-gutter); +} + +.split { + display: flex; + align-items: center; + gap: var(--split-gutter); +} + +[data-state="reversed"] { + flex-direction: row-reverse; +} diff --git a/web/src/assets/fonts.scss b/web/src/assets/styles/fonts.scss similarity index 100% rename from web/src/assets/fonts.scss rename to web/src/assets/styles/fonts.scss diff --git a/web/src/assets/styles/global.scss b/web/src/assets/styles/global.scss new file mode 100644 index 0000000000..9931f44643 --- /dev/null +++ b/web/src/assets/styles/global.scss @@ -0,0 +1,49 @@ +// Global CSS starts +body { + line-height: var(--lh-normal); + font-size: var(--fs-base); + color: var(--color-text-primary); + background: var(--color-gray); + text-align: start; + overflow-x: hidden; +} + +h1, h2, h3, h4, h5, h6 { + margin: 0; + font-family: var(--ff-headlines); + font-weight: var(--fw-bold); +} + +h1 { font-size: var(--fs-h1); } +h2 { font-size: var(--fs-h2); } + +a { + color: currentColor; +} + +table { + border-collapse: collapse; +} + +th { + text-align: start; +} + +// :focus { +// outline: 2px dotted; +// outline-offset: 0.25rem; +// } +// Style focus making use of :focus-visible +*:focus { + outline: none; +} + +*:focus:not(:focus-visible) { + box-shadow: none; +} + +*:focus-visible { + // outline: 1px dotted; + // outline-offset: 0.25rem; + box-shadow: 0 0 0 1px var(--focus-color); +} diff --git a/web/src/assets/styles/index.scss b/web/src/assets/styles/index.scss new file mode 100644 index 0000000000..064498d177 --- /dev/null +++ b/web/src/assets/styles/index.scss @@ -0,0 +1,11 @@ +@use "@assets/styles/fonts.scss"; +@use "@assets/styles/variables.scss"; +// TODO: merge app and global +@use "@assets/styles/global.scss"; +@use "@assets/styles/app.scss"; +@use "@assets/styles/utilities.scss"; +@use "@assets/styles/composition.scss"; +@use "@assets/styles/blocks.scss"; + +// PatternFly overrides +@use "@assets/styles/patternfly-overrides.scss"; diff --git a/web/src/assets/styles/layout.scss b/web/src/assets/styles/layout.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/web/src/assets/styles/patternfly-overrides.scss b/web/src/assets/styles/patternfly-overrides.scss new file mode 100644 index 0000000000..2c2f0b4d5e --- /dev/null +++ b/web/src/assets/styles/patternfly-overrides.scss @@ -0,0 +1,140 @@ +// See https://github.com/patternfly/patternfly/pull/4297 +@use "@patternfly/react-styles/css/utilities/Sizing/sizing.css"; + +:root { + // Overrides some PatternFly CSS variables using values + // from brand.suse.com + + // Font families + --pf-global--FontFamily--sans-serif: var(--ff); + --pf-global--FontFamily--heading--sans-serif: var(--ff-headings); + --pf-global--FontFamily--monospace: var(--ff-code); + --pf-global--FontFamily--redhat-updated--sans-serif: var(--ff); + --pf-global--FontFamily--redhat-updated--heading--sans-serif: var(--ff-headings); + --pf-global--FontFamily--redhat--monospace: var(--ff-code); + --pf-global--FontFamily--redhatVF--sans-serif: var(--ff); + --pf-global--FontFamily--redhatVF--heading--sans-serif: var(--ff-headings); + --pf-global--FontFamily--redhatVF--monospace: var(--ff-code); + --pf-global--FontFamily--overpass--sans-serif: var(--ff); + --pf-global--FontFamily--overpass--monospace: var(--ff-code); + + // Font size + --pf-global--FontSize--4xl: 2em; + --pf-global--FontSize--3xl: 1.75em; + --pf-global--FontSize--2xl: 1.5em; + --pf-global--FontSize--xl: 1.3em; + --pf-global--FontSize--lg: 1.15em; + --pf-global--FontSize--md: var(--fs-base); + // TODO: find better equivalences for sm and xs + // --pf-global--FontSize--xs: #{$pf-global--FontSize--xs}; + // --pf-global--FontSize--sm: #{$pf-global--FontSize--sm}; + // --pf-global--FontSize--sm: #{fonts.$size-base - 1px}; + // --pf-global--FontSize--xs: #{fonts.$size-base - 2px}; + + // Font weight + --pf-global--FontWeight--light: var(--fw-light); + --pf-global--FontWeight--normal: var(--fw-normal); + --pf-global--FontWeight--semi-bold: var(--fw-medium); + --pf-global--FontWeight--overpass--semi-bold: var(--fw-medium); + --pf-global--FontWeight--bold: var(--fw-bold); + --pf-global--FontWeight--overpass--bold: var(--fw-bold); + + // Colors + --pf-global--primary-color--100: var(--color-primary);//#{branding.$bc-green-500}; + --pf-global--primary-color--200: var(--color-primary); //#{branding.$bc-green-900}; + --pf-global--link--Color: var(--color-link); + --pf-global--link--Color--hover: var(--color-link-hover); + --pf-global--BackgroundColor--dark-100: var(--color-primary); //#{branding.$bc-pine-500}; + --pf-global--BackgroundColor--dark-100: var(--color-primary); //#{branding.$bc-pine-500}; + +} + +.pf-c-button.pf-m-primary { + --pf-c-button--m-primary--BackgroundColor: var(--color-button-primary); + --pf-c-button--m-primary--hover--BackgroundColor: var(--color-button-primary-hover) +} + +.pf-c-button.pf-m-link { + // Colors for buttons mofidiers + --pf-c-button--m-link--Color: var(--color-link);//#{branding.$bc-green-500}; + --pf-c-button--m-link--Color--hover: var(--color-link-hover);//#{branding.$bc-green-900}; + --pf-c-button--m-link--m-inline--hover--Color: var(--link-color-hover);//#{branding.$bc-green-900}; +} + +.pf-c-button.pf-m-plain { + --pf-c-button--m-plain--Color: var(--color-button-plain-link); + --pf-c-button--m-plain--hover--Color: var(--color-button-plain-link-hover); +} + +// Adds a tiny "padding" when focusing a primary or secondary action to avoid +// https://github.com/yast/d-installer/issues/115#issuecomment-1087375598 +.pf-c-button.pf-m-primary:focus-visible, +.pf-c-button.pf-m-secondary:focus-visible { + box-shadow: 0 0 0 1px white, 0 0 0 2px var(--focus-color); +} + +// PatternFly overrides for using CSS Logical Properties +// .pf-l-split.pf-m-gutter > :not(:last-child) { +// margin-inline-end: var(--pf-l-split--m-gutter--MarginRight); +// } + +// .pf-l-flex.pf-m-column > * { +// margin: 0; +// margin-block-end: var(--pf-l-flex--spacer); +// } + +// .pf-c-alert__icon { +// margin-block-start: var(--pf-c-alert__icon--MarginTop); +// margin-inline-end: var(--pf-c-alert__icon--MarginRight); +// } + +// .pf-m-grid-md.pf-c-table [data-label]::before { +// text-align: start; +// } + +// SVG icons does not obey font-size +.pf-c-empty-state__icon { + inline-size: 10rem; + block-size: 10rem; +} + +// Fix single-line subprogress missaligment +.pf-c-progress.pf-m-singleline .pf-c-progress__bar { + grid-row: 1/3; + grid-column: 1/3; +} + +.pf-c-modal-box__body { + padding-block: var(--pf-c-modal-box__body--PaddingTop); +} +.pf-c-form__actions, +.pf-c-modal-box__footer { + // We prefer buttons placed at the right + flex-direction: row-reverse; + + // Overrides buttons margins. In row-reverse mode, we need margin + // for the :last-child too. + // See https://github.com/patternfly/patternfly/blob/9c8cb7c8609613ab53eef3fe05addda16bc63233/src/patternfly/components/ModalBox/modal-box.scss#L211 + > .pf-c-button { + margin-inline-end: var(--pf-c-modal-box__footer--c-button--MarginRight); + } +} + +// Do not change the default cursor for labels forms because it is confusing +// +// See: +// * https://github.com/yast/d-installer/issues/115#issuecomment-1090205696 +// * https://github.com/patternfly/patternfly/issues/4777#issuecomment-1092090484 +.pf-c-form__label { + --pf-c-form__label--hover--Cursor: default; + --pf-c-form__label--m-disabled--hover--Cursor: default; +} + +// Do not use thick border-top for data lists +.pf-c-data-list { + --pf-c-data-list--BorderTopWidth: 2px; +} + +td .pf-c-label { + margin-inline-start: 5px; +} diff --git a/web/src/assets/styles/utilities.scss b/web/src/assets/styles/utilities.scss new file mode 100644 index 0000000000..d933a3f51e --- /dev/null +++ b/web/src/assets/styles/utilities.scss @@ -0,0 +1,88 @@ +.justify-between { + justify-content: space-between; +} + +// Sadly, Firefox does not support :has pseudo-selector yet. +// See @components/layout/Center documentation. +// +// main:has(.vertically-centered) { +// display: grid; +// place-items: center; +// block-size: 100%; +// } + +//.content-block-centered { +.vertically-centered { + display: grid; + place-items: center; + block-size: 100%; + inline-size: 100%; +} + +.horizontally-centered { + inline-size: 100%; + margin-inline: 0 auto; + text-align: center; +} + +.icon-size-10 { + width: 10px; + height: 10px; +} + +.icon-size-16 { + width: 16px; + height: 16px; +} + +.icon-size-24 { + width: 24px; + height: 24px; +} + +.icon-size-32 { + width: 32px; + height: 32px; +} + +.color-warn { + color: var(--color-warn); +} + +.color-success { + color: var(--color-success); +} + +.full-width { + inline-size: 100%; +} + +.transform-on-hover { + transition: all 0.2s ease-in-out; + + &:hover { + transform: scale(1.4); + color: var(--color-primary-darkest); + } +} + +.gradient-border-bottom { + border-bottom: 1px solid #efefef; + border-image: linear-gradient( + var(--gradient-border-angle), + var(--gradient-border-start-color), + var(--gradient-border-end-color) + ) 1; +} + +.visually-hidden { + border: 0; + clip: rect(0 0 0 0); + height: auto; + margin: 0; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; + white-space: nowrap; +} diff --git a/web/src/assets/styles/variables.scss b/web/src/assets/styles/variables.scss new file mode 100644 index 0000000000..7001281608 --- /dev/null +++ b/web/src/assets/styles/variables.scss @@ -0,0 +1,57 @@ +:root { + --ff: Lato, arial, helvetica, sans-serif; + --ff-headlines: Poppins, sans-serif; + --ff-code: 'Roboto Mono', monospace; + + --fw-light: 300; + --fw-normal: 400; + --fw-medium: 400; + --fw-bold: 500; + + --fs-base: 14px; + --fs-h1: 1.6rem; + --fs-h2: 1.3rem; + + --lh-normal: 1.5; + --lh-medium: 1.6; + --lh-large: 1.7; + + --spacer-small: 0.5rem; + --spacer-normal: 1rem; + --spacer-medium: 1.5rem; + --spacer-large: 2rem; + + --stack-gutter: var(--spacer-normal); + --split-gutter: var(--spacer-small); + + --color-primary: #30BA78; + --color-primary-darkest: #0C322C; + --color-gray: #F2F2F2; + --color-gray-dark: #EFEFEF; // Fog + + --color-link: #30BA78; + --color-link-hover: #0C322C; + + --color-button-primary: #30BA78; + --color-button-primary-hover: #0C322C; + + --color-button-plain-link: #30BA78; + --color-button-plain-link-hover: #0C322C; + + --color-background-primary: var(--color-primary-darkest); + --color-background-secondary: var(--color-gray-dark); + + --color-text-primary: var(--color-primary-darkest); + --color-text-secondary:var(--color-gray-dark); + + --color-success: #30BA78; + --color-warn: #d4351c; // #FE7C3F; // Persimmon + + --focus-color: #00b2e2; //cerulean 500 + + --gradient-border-angle: 45deg; + --gradient-border-start-color: var(--color-gray); + --gradient-border-end-color: transparent; + + --icon-size-m: 32px; +} diff --git a/web/src/components/core/InstallationFinished.jsx b/web/src/components/core/InstallationFinished.jsx index d3e14e6883..67bc1546ef 100644 --- a/web/src/components/core/InstallationFinished.jsx +++ b/web/src/components/core/InstallationFinished.jsx @@ -47,7 +47,7 @@ function InstallationFinished() { - } className="success-icon" /> + } className="color-success" /> Congratulations! diff --git a/web/src/components/core/Section.jsx b/web/src/components/core/Section.jsx index e51c088182..6bbab9cde2 100644 --- a/web/src/components/core/Section.jsx +++ b/web/src/components/core/Section.jsx @@ -32,31 +32,19 @@ import { import { Icon } from '@components/layout'; import { ValidationErrors } from "@components/core"; -import { classNames } from "@/utils"; - -import "./section.scss"; - -const SettingsIcon = ({ ...props }) => ; /** * Helper method for rendering section icon * - * @param {React.FunctionComponent|React.ComponentClass} icon - * @param {string} ariaLabel + * @param {string} name * @param {number} [size=32] * * @return {React.ReactNode} */ -const renderIcon = (icon, ariaLabel, size = 32) => { - if (!icon) return null; - - const SectionIcon = icon; +const renderIcon = (name, size = 32) => { + if (!name) return null; - return ( -
- -
- ); + return ; }; /** @@ -98,31 +86,31 @@ const renderIcon = (icon, ariaLabel, size = 32) => { * @param {object} props * @param {string} props.title - The title for the section * @param {string} [props.description] - A tiny description for the section - * @param {boolean} [props.usingSeparator] - whether or not a thin border should be shown between title and content - * @param {React.FunctionComponent} [props.icon] - An icon for the section - * @param {import("@client/mixins").ValidationError[]} [props.errors] - Validation errors to be shown before the title - * @param {React.FunctionComponent|React.ComponentClass} [props.actionIcon=SettingsIcon] - An icon component to be used for section actions + * @param {boolean} [props.hasSeparator] - whether or not a thin border should be shown between title and content + * @param {string} [props.iconName] - the name of the icon section, if any + * @param {string} [props.actionIconName="settings"] - name for the icon for linking to section settings, when needed * @param {React.ReactNode} [props.actionTooltip] - text to be shown as a tooltip when user hovers action icon, if present * @param {React.MouseEventHandler} [props.onActionClick] - callback to be triggered when user clicks on action icon, if present + * @param {import("@client/mixins").ValidationError[]} [props.errors] - Validation errors to be shown before the title * @param {JSX.Element} [props.children] - the section content */ export default function Section({ title, description, - usingSeparator, - icon, - errors, - actionIcon = SettingsIcon, + hasSeparator, + iconName, + actionIconName = "settings", actionTooltip, onActionClick, + errors, children, }) { const renderAction = () => { if (typeof onActionClick !== 'function') return null; const Action = () => ( - ); @@ -135,28 +123,29 @@ export default function Section({ ); }; - const titleClassNames = classNames( - "d-installer-section-title", - usingSeparator && "using-separator" - ); + let headerClassNames = "split"; + if (hasSeparator) headerClassNames += " gradient-border-bottom"; return ( -
- {renderIcon(icon, `${title} section icon`, 32)} - - - {title} {renderAction()} - - - { description && description !== "" && - - - {description} - - } - { errors?.length > 0 && - } - {children} -
+
+ {renderIcon(iconName, 32)} + + + {title} + {renderAction()} + + +
+ { description && description !== "" && + + + {description} + + } + { errors?.length > 0 && + } + {children} +
+
); } diff --git a/web/src/components/core/ValidationErrors.jsx b/web/src/components/core/ValidationErrors.jsx index 0c69141e2d..66dcba40e0 100644 --- a/web/src/components/core/ValidationErrors.jsx +++ b/web/src/components/core/ValidationErrors.jsx @@ -67,14 +67,12 @@ const ValidationErrors = ({ title = "Errors", errors }) => { if (errors.length === 1) { return ( - <> -
{warningIcon} {errors[0].message}
- +
{warningIcon} {errors[0].message}
); } else { return ( <> -
+
{ warningIcon } setPopoverVisible(true)}>{`${errors.length} errors found`} - diff --git a/web/src/components/layout/Center.jsx b/web/src/components/layout/Center.jsx index 1d79b6560a..9e142f2573 100644 --- a/web/src/components/layout/Center.jsx +++ b/web/src/components/layout/Center.jsx @@ -46,7 +46,7 @@ import React from "react"; */ const Center = ({ children }) => (
-
+
{children}
diff --git a/web/src/components/layout/Icon.jsx b/web/src/components/layout/Icon.jsx index 0301dcccdb..60bdc20dfd 100644 --- a/web/src/components/layout/Icon.jsx +++ b/web/src/components/layout/Icon.jsx @@ -99,6 +99,6 @@ export default function Icon({ name, size = 32, ...otherProps }) { const IconComponent = icons[name]; return (IconComponent) - ? + ? : `icon ${name} not found!`; } diff --git a/web/src/components/layout/Layout.jsx b/web/src/components/layout/Layout.jsx index 7b5823ac59..83ef811afb 100644 --- a/web/src/components/layout/Layout.jsx +++ b/web/src/components/layout/Layout.jsx @@ -59,18 +59,18 @@ const FooterInfoArea = createTeleporter(); function Layout({ children }) { return ( <> -
+

- +

-
{children}
+
{children}
-
+
* { - padding: var(--space-m) var(--space-s); + padding: var(--spacer-normal); } @media (width > 50em) { @@ -38,14 +28,12 @@ body { } } -// utility, stand for "margin-inline-end-small"; -.mie-s { - margin-inline-end: var(--space-s); -} - #d-installer > header { + --color-button-plain-link: white; + --color-button-plain-link-hover: #fcfcfc; + grid-area: header; - background: var(--color-background-primary); + background: var(--color-primary-darkest); color: var(--color-text-secondary); } @@ -53,57 +41,9 @@ body { grid-area: content; overflow-y: auto; // Sadly, only Firefox supports oerflow-block at this moment (Jan 2023) overflow-block: auto; - padding: var(--space-l); - - display: grid; // Sadly, only Firefox allow native subgrids. + padding: var(--spacer-medium); } #d-installer > footer { grid-area: footer; } - -.flow-flex-row { - display: flex; - align-items: center; - justify-content: space-between; -} - -.flow-flex-row[data-state='reversed'] { - flex-direction: row-reverse; -} - -// Sadly, Firefox does not support :has pseudo-selector yet. -// See @components/layout/Center documentation. -// -// main:has(.vertically-centered) { -// display: grid; -// place-items: center; -// block-size: 100%; -// } -.vertically-centered { - display: grid; - place-items: center; - block-size: 100%; -} - -.vertically-centered > div { - inline-size: 100%; -} - -.horizontally-centered { - inline-size: 100%; - margin-inline: 0 auto; - text-align: center; -} - -.has-gutter { - gap: var(--space-s); -} - -.has-gutter-size-1 { - gap: var(--space-m); -} - -.pad-size-1 { - padding: var(--space-m) -} diff --git a/web/src/components/network/AddressesDataList.jsx b/web/src/components/network/AddressesDataList.jsx index b577c767c0..24e7e987af 100644 --- a/web/src/components/network/AddressesDataList.jsx +++ b/web/src/components/network/AddressesDataList.jsx @@ -115,7 +115,7 @@ export default function AddressesDataList({ return ( <> -
+
Addresses ); diff --git a/web/src/components/core/Section.test.jsx b/web/src/components/core/Section.test.jsx index c99c4439df..1eaa710a41 100644 --- a/web/src/components/core/Section.test.jsx +++ b/web/src/components/core/Section.test.jsx @@ -24,8 +24,6 @@ import { screen } from "@testing-library/react"; import { installerRender } from "@/test-utils"; import { Section } from "@components/core"; -const FakeIcon = () => "FI"; - describe("Section", () => { it("renders given title", () => { installerRender(
); @@ -41,12 +39,6 @@ describe("Section", () => { screen.getByText("Intended to perform awesome tweaks"); }); - it("renders given icon", () => { - installerRender(
); - - screen.getByRole("figure", { name: "Awesome settings section icon" }); - }); - it("renders given errors", () => { installerRender(
@@ -56,12 +48,12 @@ describe("Section", () => { }); describe("when onActionClick callback is given", () => { - it("renders an action icon", () => { + it("renders a link for section settings", () => { installerRender(
null} /> ); - screen.getByRole("figure", { name: "Awesome settings section action icon" }); + screen.getByLabelText("Section settings"); }); it("triggers the action when user clicks on it", async () => { @@ -83,9 +75,9 @@ describe("Section", () => { let inputText = screen.queryByRole("textbox", { name: "Awesome input" }); expect(inputText).not.toBeInTheDocument(); - const actionIcon = screen.getByRole("figure", { name: "Awesome settings section action icon" }); + const actionLink = screen.getByLabelText("Section settings"); - await user.click(actionIcon); + await user.click(actionLink); inputText = screen.queryByRole("textbox", { name: "Awesome input" }); expect(inputText).toBeInTheDocument(); diff --git a/web/src/components/network/Network.test.jsx b/web/src/components/network/Network.test.jsx index 78164adf9a..1ab48e70a9 100644 --- a/web/src/components/network/Network.test.jsx +++ b/web/src/components/network/Network.test.jsx @@ -27,8 +27,8 @@ import { ConnectionTypes } from "@client/network"; import { createClient } from "@client"; jest.mock("@client"); -jest.mock("@components/network/NetworkWiredStatus", () => () => "Wired Connections"); -jest.mock("@components/network/NetworkWifiStatus", () => () => "WiFi Connections"); +jest.mock("@components/network/NetworkWiredStatus", () => () =>
Wired Connections
); +jest.mock("@components/network/NetworkWifiStatus", () => () =>
WiFi Connections
); const networkSettings = { wifiScanSupported: false, hostname: "test" }; let settingsFn = jest.fn().mockReturnValue(networkSettings); diff --git a/web/src/components/network/WifiNetworkListItem.test.jsx b/web/src/components/network/WifiNetworkListItem.test.jsx index 4ebbf0b22d..b857a2530a 100644 --- a/web/src/components/network/WifiNetworkListItem.test.jsx +++ b/web/src/components/network/WifiNetworkListItem.test.jsx @@ -50,11 +50,11 @@ describe("NetworkListItem", () => { }); describe("when isSelected prop is true", () => { - it("renders network as selected", async () => { + it("renders network as focused", async () => { installerRender(); - const wrapper = await screen.findByRole("article"); - expect(wrapper.classList.contains("selection-list-checked-item")).toBe(true); + const wrapper = await screen.findByRole("listitem"); + expect(wrapper).toHaveAttribute("data-state", "focused"); }); it("renders the input radio as checked", async () => { @@ -65,13 +65,6 @@ describe("NetworkListItem", () => { }); describe("when isActive prop is true", () => { - it("renders network as selected", async () => { - installerRender(); - - const wrapper = await screen.findByRole("article"); - expect(wrapper.classList.contains("selection-list-checked-item")).toBe(true); - }); - it("renders the input radio as checked", async () => { installerRender(); @@ -110,8 +103,8 @@ describe("NetworkListItem", () => { it("renders network as focused", async () => { installerRender(); - const wrapper = await screen.findByRole("article"); - expect(wrapper.classList.contains("selection-list-focused-item")).toBe(true); + const wrapper = await screen.findByRole("listitem"); + expect(wrapper).toHaveAttribute("data-state", "focused"); }); }); }); diff --git a/web/src/components/network/WifiNetworksList.test.jsx b/web/src/components/network/WifiNetworksList.test.jsx index 0b8ee14206..06d4b53ff9 100644 --- a/web/src/components/network/WifiNetworksList.test.jsx +++ b/web/src/components/network/WifiNetworksList.test.jsx @@ -44,9 +44,9 @@ const otherNetwork = { const networksMock = [myNetwork, otherNetwork]; describe("WifiNetworksList", () => { - it("renders nothing when no networks are given", async () => { - const { container } = installerRender(, { usingLayout: false }); - await waitFor(() => expect(container).toBeEmptyDOMElement()); + it("renders link for connect to a hidden network", () => { + installerRender(, { usingLayout: false }); + screen.getByRole("button", { name: "Connect to hidden network" }); }); it("displays networks information", async () => { diff --git a/web/src/components/overview/Overview.test.jsx b/web/src/components/overview/Overview.test.jsx index a48b14555b..b4e2826659 100644 --- a/web/src/components/overview/Overview.test.jsx +++ b/web/src/components/overview/Overview.test.jsx @@ -51,7 +51,7 @@ jest.mock('react-router-dom', () => ({ })); jest.mock("@components/language/LanguageSelector", () => () => "Language Selector"); -jest.mock("@components/overview/StorageSection", () => () => "Storage Section"); +jest.mock("@components/overview/StorageSection", () => () =>
Storage Section
); jest.mock("@components/network/Network", () => () => "Network Configuration"); jest.mock("@components/users/Users", () => () => "Users Configuration"); jest.mock("@components/core/InstallButton", () => () => "Install Button"); diff --git a/web/src/components/storage/ProposalPage.test.jsx b/web/src/components/storage/ProposalPage.test.jsx index fe08a337b0..3fd6d76a77 100644 --- a/web/src/components/storage/ProposalPage.test.jsx +++ b/web/src/components/storage/ProposalPage.test.jsx @@ -27,10 +27,10 @@ import { ProposalPage } from "@components/storage"; const FakeProposalTargetSection = ({ calculateProposal }) => { return ( - <> +
Target section Calculate - +
); }; @@ -43,8 +43,8 @@ jest.mock("react-router-dom", () => ({ jest.mock("@components/core/InstallerSkeleton", () => () => "Loading proposal"); jest.mock("@components/storage/ProposalTargetSection", () => FakeProposalTargetSection); -jest.mock("@components/storage/ProposalSettingsSection", () => () => "Settings section"); -jest.mock("@components/storage/ProposalActionsSection", () => () => "Actions section"); +jest.mock("@components/storage/ProposalSettingsSection", () => () =>
Settings section
); +jest.mock("@components/storage/ProposalActionsSection", () => () =>
Actions section
); let proposal; diff --git a/web/src/components/storage/ProposalSettingsSection.test.jsx b/web/src/components/storage/ProposalSettingsSection.test.jsx index 1fd82132a2..010a0a13d8 100644 --- a/web/src/components/storage/ProposalSettingsSection.test.jsx +++ b/web/src/components/storage/ProposalSettingsSection.test.jsx @@ -53,7 +53,7 @@ it("renders the list of the volumes to create", () => { it("renders an icon for configuring the settings", () => { installerRender(); - screen.getByRole("button", { name: "Settings section action icon" }); + screen.getByRole("button", { name: "Section settings" }); }); it("does not show the popup by default", async () => { @@ -67,7 +67,7 @@ it("does not show the popup by default", async () => { it("shows the popup with the form when the icon is clicked", async () => { const { user } = installerRender(); - const button = screen.getByRole("button", { name: "Settings section action icon" }); + const button = screen.getByRole("button", { name: "Section settings" }); await user.click(button); await screen.findByRole("dialog"); @@ -79,7 +79,7 @@ it("closes the popup without submitting the form when cancel is clicked", async const { user } = installerRender(); - const button = screen.getByRole("button", { name: "Settings section action icon" }); + const button = screen.getByRole("button", { name: "Section settings" }); await user.click(button); const popup = await screen.findByRole("dialog"); @@ -95,7 +95,7 @@ it("closes the popup and submits the form when accept is clicked", async () => { const { user } = installerRender(); - const button = screen.getByRole("button", { name: "Settings section action icon" }); + const button = screen.getByRole("button", { name: "Section settings" }); await user.click(button); const popup = await screen.findByRole("dialog"); diff --git a/web/src/components/storage/ProposalTargetSection.test.jsx b/web/src/components/storage/ProposalTargetSection.test.jsx index 22f20b7417..824ccd2a65 100644 --- a/web/src/components/storage/ProposalTargetSection.test.jsx +++ b/web/src/components/storage/ProposalTargetSection.test.jsx @@ -51,7 +51,7 @@ it("renders the proposal summary", () => { it("renders an icon for configuring the candidate devices", () => { installerRender(); - screen.getByRole("button", { name: "Device section action icon" }); + screen.getByRole("button", { name: "Section settings" }); }); it("does not show the popup by default", async () => { @@ -65,7 +65,7 @@ it("does not show the popup by default", async () => { it("shows the popup with the form when the icon is clicked", async () => { const { user } = installerRender(); - const button = screen.getByRole("button", { name: "Device section action icon" }); + const button = screen.getByRole("button", { name: "Section settings" }); await user.click(button); await screen.findByRole("dialog"); @@ -77,7 +77,7 @@ it("closes the popup without submitting the form when cancel is clicked", async const { user } = installerRender(); - const button = screen.getByRole("button", { name: "Device section action icon" }); + const button = screen.getByRole("button", { name: "Section settings" }); await user.click(button); const popup = await screen.findByRole("dialog"); @@ -93,7 +93,7 @@ it("closes the popup and submits the form when accept is clicked", async () => { const { user } = installerRender(); - const button = screen.getByRole("button", { name: "Device section action icon" }); + const button = screen.getByRole("button", { name: "Section settings" }); await user.click(button); const popup = await screen.findByRole("dialog"); From 8442b3b2f53b7f159fc7fb6825ccf9bc245f79cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 10 Jan 2023 17:11:46 +0000 Subject: [PATCH 12/23] [web] Move layout.scss file to styles --- web/src/assets/styles/index.scss | 1 + web/src/assets/styles/layout.scss | 44 ++++++++++++++++++++++++ web/src/components/layout/Layout.jsx | 1 - web/src/components/layout/layout.scss | 49 --------------------------- 4 files changed, 45 insertions(+), 50 deletions(-) delete mode 100644 web/src/components/layout/layout.scss diff --git a/web/src/assets/styles/index.scss b/web/src/assets/styles/index.scss index 064498d177..07311e0041 100644 --- a/web/src/assets/styles/index.scss +++ b/web/src/assets/styles/index.scss @@ -3,6 +3,7 @@ // TODO: merge app and global @use "@assets/styles/global.scss"; @use "@assets/styles/app.scss"; +@use "@assets/styles/layout.scss"; @use "@assets/styles/utilities.scss"; @use "@assets/styles/composition.scss"; @use "@assets/styles/blocks.scss"; diff --git a/web/src/assets/styles/layout.scss b/web/src/assets/styles/layout.scss index e69de29bb2..fe9116864d 100644 --- a/web/src/assets/styles/layout.scss +++ b/web/src/assets/styles/layout.scss @@ -0,0 +1,44 @@ +#d-installer { + display: grid; + grid-template-rows: auto 1fr auto; + grid-template-areas: + 'header' + 'content' + 'footer' + ; + overflow: hidden; + height: 100dvb; + block-size: 100dvb; + max-inline-size: 1024px; + margin-inline: auto; + background: white; + + svg { + fill: currentColor; + vertical-align: middle; + } +} + +#d-installer > * { + padding: var(--spacer-normal); +} + +#d-installer > header { + --color-button-plain-link: white; + --color-button-plain-link-hover: #fcfcfc; + + grid-area: header; + background: var(--color-primary-darkest); + color: var(--color-text-secondary); +} + +#d-installer > main { + grid-area: content; + overflow-y: auto; // Sadly, only Firefox supports oerflow-block at this moment (Jan 2023) + overflow-block: auto; + padding: var(--spacer-medium); +} + +#d-installer > footer { + grid-area: footer; +} diff --git a/web/src/components/layout/Layout.jsx b/web/src/components/layout/Layout.jsx index 83ef811afb..70d256d40e 100644 --- a/web/src/components/layout/Layout.jsx +++ b/web/src/components/layout/Layout.jsx @@ -21,7 +21,6 @@ import React from "react"; -import "./layout.scss"; import logoUrl from "@assets/suse-horizontal-logo.svg"; import { createTeleporter } from "react-teleporter"; diff --git a/web/src/components/layout/layout.scss b/web/src/components/layout/layout.scss deleted file mode 100644 index b00ff91b37..0000000000 --- a/web/src/components/layout/layout.scss +++ /dev/null @@ -1,49 +0,0 @@ -#d-installer { - display: grid; - grid-template-rows: auto 1fr auto; - grid-template-areas: - 'header' - 'content' - 'footer' - ; - overflow: hidden; - height: 100dvb; - block-size: 100dvb; - background: white; - - svg { - fill: currentColor; - vertical-align: middle; - } -} - -#d-installer > * { - padding: var(--spacer-normal); -} - -@media (width > 50em) { - #d-installer { - max-inline-size: 50em; - margin-inline: auto; - } -} - -#d-installer > header { - --color-button-plain-link: white; - --color-button-plain-link-hover: #fcfcfc; - - grid-area: header; - background: var(--color-primary-darkest); - color: var(--color-text-secondary); -} - -#d-installer > main { - grid-area: content; - overflow-y: auto; // Sadly, only Firefox supports oerflow-block at this moment (Jan 2023) - overflow-block: auto; - padding: var(--spacer-medium); -} - -#d-installer > footer { - grid-area: footer; -} From c20adbc4060f73925152204717a366ef74e3db5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 10 Jan 2023 17:17:23 +0000 Subject: [PATCH 13/23] [web] Better title aligment --- web/src/components/layout/Layout.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/layout/Layout.jsx b/web/src/components/layout/Layout.jsx index 70d256d40e..fcbf306516 100644 --- a/web/src/components/layout/Layout.jsx +++ b/web/src/components/layout/Layout.jsx @@ -59,7 +59,7 @@ function Layout({ children }) { return ( <>
-

+

From 612ae17d109207a2d826098f0ac45100240ef067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 10 Jan 2023 19:37:59 +0000 Subject: [PATCH 14/23] [web] Limit logo inline-size --- web/src/assets/styles/layout.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/src/assets/styles/layout.scss b/web/src/assets/styles/layout.scss index fe9116864d..2a94b1aaa8 100644 --- a/web/src/assets/styles/layout.scss +++ b/web/src/assets/styles/layout.scss @@ -42,3 +42,7 @@ #d-installer > footer { grid-area: footer; } + +#d-installer > footer >img { + max-inline-size: 150px; +} From 5cf689d6d07f6f61312167c04965e3102e520404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Wed, 11 Jan 2023 09:07:25 +0000 Subject: [PATCH 15/23] [web] Fix fonts import Since we're using an specific rule in webpack.config.js file for fonts, we can't rely on @use Sass at-rule for importing the fonts.scss file. Instead, we have to import it in the index.js file directly, for making webpack aware of it. What is more, most probably the fonts.scss file could be renamed to fonts.css since it does not contain nothing to process with Sass. Related to https://github.com/yast/d-installer/pull/385 --- web/src/assets/{styles => }/fonts.scss | 0 web/src/assets/styles/index.scss | 1 - web/src/index.js | 2 ++ 3 files changed, 2 insertions(+), 1 deletion(-) rename web/src/assets/{styles => }/fonts.scss (100%) diff --git a/web/src/assets/styles/fonts.scss b/web/src/assets/fonts.scss similarity index 100% rename from web/src/assets/styles/fonts.scss rename to web/src/assets/fonts.scss diff --git a/web/src/assets/styles/index.scss b/web/src/assets/styles/index.scss index 07311e0041..748fbf7133 100644 --- a/web/src/assets/styles/index.scss +++ b/web/src/assets/styles/index.scss @@ -1,4 +1,3 @@ -@use "@assets/styles/fonts.scss"; @use "@assets/styles/variables.scss"; // TODO: merge app and global @use "@assets/styles/global.scss"; diff --git a/web/src/index.js b/web/src/index.js index a97be2cba8..2e9cca2cc4 100644 --- a/web/src/index.js +++ b/web/src/index.js @@ -31,6 +31,8 @@ import { InstallerClientProvider } from "@context/installer"; import { SoftwareProvider } from "@context/software"; import { createClient } from "@/client"; +import "@assets/fonts.scss"; + import App from "@/App"; import Main from "@/Main"; import { Overview } from "@components/overview"; From c0a64aff173fba14226df0b54c3bd3f1dba76099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Wed, 11 Jan 2023 09:13:26 +0000 Subject: [PATCH 16/23] [web] Move fonts.scss to fonts.css Removing dead Sass variables too. --- web/src/assets/{fonts.scss => fonts.css} | 6 ------ web/src/index.js | 2 +- web/webpack.config.js | 4 ++-- 3 files changed, 3 insertions(+), 9 deletions(-) rename web/src/assets/{fonts.scss => fonts.css} (96%) diff --git a/web/src/assets/fonts.scss b/web/src/assets/fonts.css similarity index 96% rename from web/src/assets/fonts.scss rename to web/src/assets/fonts.css index 5c3c8ac073..1560ba77c3 100644 --- a/web/src/assets/fonts.scss +++ b/web/src/assets/fonts.css @@ -1,9 +1,3 @@ -$base: Lato, arial, helvetica, sans-serif; -$headlines: Poppins, san-serif; -$code: 'Roboto Mono', monospace; -$size-base: 14px; -$line-height: 1.5rem; - /** * Lato font, a sanserif family designed by Ɓukasz Dziedzic and others (see * http://www.latofonts.com/team) and published under the open-source Open Font License diff --git a/web/src/index.js b/web/src/index.js index 2e9cca2cc4..08cc746f37 100644 --- a/web/src/index.js +++ b/web/src/index.js @@ -31,7 +31,7 @@ import { InstallerClientProvider } from "@context/installer"; import { SoftwareProvider } from "@context/software"; import { createClient } from "@/client"; -import "@assets/fonts.scss"; +import "@assets/fonts.css"; import App from "@/App"; import Main from "@/Main"; diff --git a/web/webpack.config.js b/web/webpack.config.js index 9f39f2a919..4f03bc52d3 100644 --- a/web/webpack.config.js +++ b/web/webpack.config.js @@ -93,7 +93,7 @@ module.exports = { }, { test: /\.s?css$/, - exclude: [/fonts.scss/], + exclude: [/fonts.css/], use: [ Extract.loader, { @@ -117,7 +117,7 @@ module.exports = { }, // Load D-Intaller fonts { - test: /fonts.scss/, + test: /fonts.css/, use: [ { loader: 'css-loader' }, { loader: 'sass-loader' } From f54477b08c8c92d3092f06992543d328360b8d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Wed, 11 Jan 2023 09:14:19 +0000 Subject: [PATCH 17/23] [web] Relocate some CSS/Sass imports --- web/src/index.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/web/src/index.js b/web/src/index.js index 08cc746f37..70c4d6998e 100644 --- a/web/src/index.js +++ b/web/src/index.js @@ -24,14 +24,14 @@ import ReactDOM from "react-dom"; import "core-js/stable"; import "regenerator-runtime/runtime"; -import "@patternfly/patternfly/patternfly-base.scss"; - import { HashRouter, Routes, Route } from "react-router-dom"; import { InstallerClientProvider } from "@context/installer"; import { SoftwareProvider } from "@context/software"; import { createClient } from "@/client"; import "@assets/fonts.css"; +import "@patternfly/patternfly/patternfly-base.scss"; +import "@assets/styles/index.scss"; import App from "@/App"; import Main from "@/Main"; @@ -39,8 +39,6 @@ import { Overview } from "@components/overview"; import { ProductSelectionPage } from "@components/software"; import { ProposalPage as StoragePage } from "@components/storage"; -import "@assets/styles/index.scss"; - ReactDOM.render( From 049d0025c1d74f0544d18aa1b0b859535aa87181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Wed, 11 Jan 2023 09:29:32 +0000 Subject: [PATCH 18/23] [web] Mount layout wrapper inside #root node --- web/src/assets/styles/layout.scss | 12 ++++++------ web/src/components/layout/Layout.jsx | 4 ++-- web/src/index.html | 2 +- web/src/index.js | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/web/src/assets/styles/layout.scss b/web/src/assets/styles/layout.scss index 2a94b1aaa8..a2581fc37b 100644 --- a/web/src/assets/styles/layout.scss +++ b/web/src/assets/styles/layout.scss @@ -1,4 +1,4 @@ -#d-installer { +.wrapper { display: grid; grid-template-rows: auto 1fr auto; grid-template-areas: @@ -19,11 +19,11 @@ } } -#d-installer > * { +.wrapper > * { padding: var(--spacer-normal); } -#d-installer > header { +.wrapper > header { --color-button-plain-link: white; --color-button-plain-link-hover: #fcfcfc; @@ -32,17 +32,17 @@ color: var(--color-text-secondary); } -#d-installer > main { +.wrapper > main { grid-area: content; overflow-y: auto; // Sadly, only Firefox supports oerflow-block at this moment (Jan 2023) overflow-block: auto; padding: var(--spacer-medium); } -#d-installer > footer { +.wrapper > footer { grid-area: footer; } -#d-installer > footer >img { +.wrapper > footer > img { max-inline-size: 150px; } diff --git a/web/src/components/layout/Layout.jsx b/web/src/components/layout/Layout.jsx index fcbf306516..b9c48a5085 100644 --- a/web/src/components/layout/Layout.jsx +++ b/web/src/components/layout/Layout.jsx @@ -57,7 +57,7 @@ const FooterInfoArea = createTeleporter(); */ function Layout({ children }) { return ( - <> +

@@ -77,7 +77,7 @@ function Layout({ children }) { Logo of SUSE

- +
); } diff --git a/web/src/index.html b/web/src/index.html index ed95deb8dc..dc2be5d387 100644 --- a/web/src/index.html +++ b/web/src/index.html @@ -8,7 +8,7 @@ D-Installer -
+
diff --git a/web/src/index.js b/web/src/index.js index 70c4d6998e..e2f2da7f4f 100644 --- a/web/src/index.js +++ b/web/src/index.js @@ -58,5 +58,5 @@ ReactDOM.render( , - document.getElementById("d-installer") + document.getElementById("root") ); From 6998583c00f6fa49ea542bbe1dffa31518786086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Wed, 11 Jan 2023 09:38:32 +0000 Subject: [PATCH 19/23] [web] Add shadow utilities --- web/src/assets/styles/utilities.scss | 12 ++++++++++++ web/src/assets/styles/variables.scss | 1 + web/src/components/layout/Layout.jsx | 6 +++--- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/web/src/assets/styles/utilities.scss b/web/src/assets/styles/utilities.scss index d933a3f51e..bdbcd0c524 100644 --- a/web/src/assets/styles/utilities.scss +++ b/web/src/assets/styles/utilities.scss @@ -86,3 +86,15 @@ width: 1px; white-space: nowrap; } + +.shadow { + box-shadow: 0px 0px 10px 0px var(--color-gray-darker); +} + +.top-shadow { + box-shadow: 0px 5px 10px 0px var(--color-gray-darker); +} + +.bottom-shadow { + box-shadow: 0px -3px 10px 0px var(--color-gray-darker); +} diff --git a/web/src/assets/styles/variables.scss b/web/src/assets/styles/variables.scss index 7001281608..b7cb505ba3 100644 --- a/web/src/assets/styles/variables.scss +++ b/web/src/assets/styles/variables.scss @@ -28,6 +28,7 @@ --color-primary-darkest: #0C322C; --color-gray: #F2F2F2; --color-gray-dark: #EFEFEF; // Fog + --color-gray-darker: #999999; --color-link: #30BA78; --color-link-hover: #0C322C; diff --git a/web/src/components/layout/Layout.jsx b/web/src/components/layout/Layout.jsx index b9c48a5085..49f34d5013 100644 --- a/web/src/components/layout/Layout.jsx +++ b/web/src/components/layout/Layout.jsx @@ -57,8 +57,8 @@ const FooterInfoArea = createTeleporter(); */ function Layout({ children }) { return ( -
-
+
+

@@ -69,7 +69,7 @@ function Layout({ children }) {
{children}
-