add theming via css custom properties
authorRigel Kent <sendmemail@rigelk.eu>
Mon, 3 Sep 2018 23:28:04 +0000 (01:28 +0200)
committerRigel Kent <par@rigelk.eu>
Tue, 4 Sep 2018 21:24:34 +0000 (23:24 +0200)
and a bonus dark color theme toggle

25 files changed:
client/src/app/+accounts/account-video-channels/account-video-channels.component.scss
client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss
client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.scss
client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.scss
client/src/app/+my-account/my-account-videos/my-account-videos.component.scss
client/src/app/app.component.html
client/src/app/app.component.scss
client/src/app/header/header.component.scss
client/src/app/login/login.component.scss
client/src/app/menu/menu.component.html
client/src/app/menu/menu.component.scss
client/src/app/menu/menu.component.ts
client/src/app/search/search.component.scss
client/src/app/shared/misc/help.component.scss
client/src/app/shared/video/video-feed.component.scss
client/src/app/shared/video/video-miniature.component.scss
client/src/app/videos/+video-edit/video-add.component.scss
client/src/app/videos/+video-watch/comment/video-comment.component.scss
client/src/app/videos/+video-watch/video-watch.component.scss
client/src/app/videos/video-list/video-overview.component.scss
client/src/assets/images/menu/moonsun.svg [new file with mode: 0644]
client/src/sass/application.scss
client/src/sass/include/_mixins.scss
client/src/sass/include/_variables.scss
client/src/sass/primeng-custom.scss

index 39c0840e4b4e82dcb9fe9f55dbac8f93c208a560..0c6de2efa42abfce52c4031f5c4f584f2fcdaa6f 100644 (file)
@@ -10,7 +10,7 @@ a.video-channel {
 
   display: inline-block;
   text-align: center;
-  color: #000;
+  color: var(--mainForegroundColor);
   margin: 10px 30px;
 
   img {
index 4c9167211cd97b5d2c5ade484242423ee176752f..c90bd514155238bbe6ab7f93e927e87d8d4da269 100644 (file)
@@ -28,7 +28,7 @@ input[type=submit] {
 
 .inner-form-title {
   text-transform: uppercase;
-  color: $orange-color;
+  color: var(--mainColor);
   font-weight: $font-bold;
   font-size: 13px;
   margin-top: 30px;
index 8cb0b677dfc64e4ae39b17a1e94a710f0f874d25..700d516d57067e144c18473c473f4eaf9a251c41 100644 (file)
@@ -19,7 +19,7 @@
       width: fit-content;
       display: flex;
       align-items: baseline;
-      color: #000;
+      color: var(--mainForegroundColor);
 
       .video-channel-display-name {
         font-weight: $font-semibold;
index 83d657f03984b8f816ddddc4c4167113cfbf1613..472cbb723721de3f16f1d936e90b5bc3ed9e6443 100644 (file)
@@ -29,7 +29,7 @@
       width: fit-content;
       display: flex;
       align-items: baseline;
-      color: #000;
+      color: var(--mainForegroundColor);
 
       .video-channel-display-name {
         font-weight: $font-semibold;
index 8d0dec07dc8a784bd5498c069549643ab8a9cfb6..2db81a3fe5ff47b4eed031d77aaaf829fbf2b74a 100644 (file)
@@ -59,7 +59,7 @@
     .video-info-name {
       @include disable-default-a-behaviour;
 
-      color: #000;
+      color: var(--mainForegroundColor);
       display: block;
       width: fit-content;
       font-size: 16px;
index 3eb8ef40a060f03755ee32926931cd8c8cada320..0564e1a7bd06ffc37bf9bb9cfd335a96ca6bd921 100644 (file)
@@ -14,7 +14,7 @@
       </a>
     </div>
 
-    <div class="header-right">
+    <div class="header-right" [ngClass]="{ 'border-bottom': isMenuDisplayed === false }">
       <my-header></my-header>
     </div>
   </div>
index e772e3a37475de4bee2c161bd290a3cf55d0d9de..b51a81eb1e41abb0f27ca9d8662a5a4319457792 100644 (file)
@@ -7,6 +7,7 @@
 
 .sub-header-container {
   margin-top: $header-height;
+  background-color: var(--mainBackgroundColor);
 }
 
 .header {
@@ -14,7 +15,7 @@
   position: fixed;
   top: 0;
   width: 100%;
-  background-color: $bg-color;
+  background-color: var(--mainBackgroundColor);
   z-index: 1000;
   box-shadow: 0 1px 3px rgba(0, 0, 0, 0.16);
   display: flex;
@@ -31,7 +32,8 @@
       @include icon(24px);
 
       &.icon-menu {
-        background-image: url('../assets/images/header/menu.svg');
+        background-color: var(--mainForegroundColor);
+        mask-image: url('../assets/images/header/menu.svg');
         margin: 0 18px 0 20px;
       }
     }
@@ -83,7 +85,6 @@
 }
 
 footer {
-  border-top: 1px solid $footer-border-color;
   padding: 10px 0;
   font-size: 11px;
   margin-top: $footer-margin;
index 8251ec1b5b9278064131a7ccd93cd021269ba177..bd03c338ac51247b35c00a0c00e196f59b28083a 100644 (file)
@@ -8,7 +8,7 @@
   padding-right: 40px; // For the search icon
 
   &::placeholder {
-    color: #000;
+    color: var(--inputPlaceholderColor);
   }
 
   &:focus::placeholder {
@@ -28,7 +28,8 @@
   @include icon(25px);
   height: 21px;
 
-  background-image: url('../../assets/images/header/search.svg');
+  background-color: var(--mainForegroundColor);
+  mask: url('../../assets/images/header/search.svg') no-repeat 50% 50%;
 
   // yolo
   position: absolute;
index 7978c58917a30032a57da58ed4c208e9816e0ef3..8541a2681378165adf4643e7e3056435e987fcac 100644 (file)
@@ -18,7 +18,7 @@ input[type=submit] {
 }
 
 .create-an-account, .forgot-password-button {
-  color: #000;
+  color: var(--mainForegroundColor);
   cursor: pointer;
   
   &:hover {
index 8fe6797d601cf36c85a64449b178196c320f3901..d9e75adeaf4ff2f69cbb6852a8af5b6a54491b88 100644 (file)
@@ -87,6 +87,9 @@
       <span class="language">
         <span (click)="openLanguageChooser()" i18n-title title="Change the language" class="icon icon-language"></span>
       </span>
+      <span class="color-palette">
+        <span (click)="toggleDarkTheme()" i18n-title title="Toggle dark interface" class="icon icon-moonsun"></span>
+      </span>
     </div>
   </menu>
 </div>
index 941c208e20f2e31fabb0f1f6156e2a14a4695974..4ef330b2f5a5ae585ee6d97f2443ad933f3a4ea3 100644 (file)
@@ -9,7 +9,7 @@
 }
 
 menu {
-  background-color: $black-background;
+  background-color: $menu-background;
   margin: 0;
   padding: 0;
   height: 100%;
@@ -190,10 +190,10 @@ menu {
   }
 
   .footer {
-    margin-bottom: 15px;
+    padding-bottom: 15px;
     padding-left: $menu-left-padding;
 
-    .language {
+    .language, .color-palette {
       display: inline-block;
       color: $menu-bottom-color;
       cursor: pointer;
@@ -213,6 +213,16 @@ menu {
           background-image: url('../../assets/images/menu/language.png');
         }
 
+        &.icon-moonsun  {
+          margin-left: 10px;
+          position: relative;
+          top: -1px;
+          width: 24px;
+          height: 24px;
+
+          background-image: url('../../assets/images/menu/moonsun.svg');
+        }
+
         &:hover {
           opacity: 1;
         }
index dded6b4d5a6b6e2453437cddba32b9646d64d9d1..3de4a78aff67ece86da9a413fd2f81be08117fe8 100644 (file)
@@ -22,6 +22,8 @@ export class MenuComponent implements OnInit {
     [UserRight.MANAGE_VIDEO_ABUSES]: '/admin/video-abuses',
     [UserRight.MANAGE_VIDEO_BLACKLIST]: '/admin/video-blacklist'
   }
+  private theme = document.querySelector('body')
+  private previousTheme = { }
 
   constructor (
     private authService: AuthService,
@@ -51,6 +53,13 @@ export class MenuComponent implements OnInit {
         }
       }
     )
+
+    // initialise the alternative theme with dark theme colors
+    this.previousTheme['mainBackgroundColor'] = '#111111'
+    this.previousTheme['mainForegroundColor'] = '#fff'
+    this.previousTheme['submenuColor'] = 'rgb(32,32,32)'
+    this.previousTheme['inputColor'] = 'gray'
+    this.previousTheme['inputPlaceholderColor'] = '#fff'
   }
 
   isRegistrationAllowed () {
@@ -96,6 +105,21 @@ export class MenuComponent implements OnInit {
     this.languageChooserModal.show()
   }
 
+  toggleDarkTheme () {
+    // switch properties
+    this.switchProperty('mainBackgroundColor')
+    this.switchProperty('mainForegroundColor')
+    this.switchProperty('submenuColor')
+    this.switchProperty('inputColor')
+    this.switchProperty('inputPlaceholderColor')
+  }
+
+  private switchProperty (property, newValue?) {
+    const propertyOldvalue = window.getComputedStyle(this.theme).getPropertyValue('--' + property)
+    this.theme.style.setProperty('--' + property, (newValue) ? newValue : this.previousTheme[property])
+    this.previousTheme[property] = propertyOldvalue
+  }
+
   private computeIsUserHasAdminAccess () {
     const right = this.getFirstAdminRightAvailable()
 
index 3be8f53118f4300803a974aa5d50be563d96c74d..67b2094b03b3666c442a46fbbae0619aec1fb43d 100644 (file)
@@ -67,7 +67,7 @@
         .video-info-name {
           @include disable-default-a-behaviour;
 
-          color: #000;
+          color: var(--mainForegroundColor);
           display: block;
           width: fit-content;
           font-size: 18px;
 
           display: flex;
           align-items: baseline;
-          color: #000;
+          color: var(--mainForegroundColor);
           width: fit-content;
 
           .video-channel-display-name {
index fe64a270d79002ffe94815689667e9b7e653dc3b..5c73a80310de606871e4ac868b83b886f34f93d3 100644 (file)
@@ -7,7 +7,6 @@
   position: relative;
   top: -2px;
   background-image: url('../../../assets/images/global/help.svg');
-  background-color: #fff;
   border: none;
   margin: 5px;
 }
index 9dab18ffd37e6d417c03343d038d6b984b7e0d1d..385764be0aaf0cddd3ffaba37307120f3f163a8b 100644 (file)
@@ -12,7 +12,8 @@
     &.icon-syndication {
       position: relative;
       top: -2px;
-      background-image: url('../../../assets/images/global/syndication.svg');
+      background-color: var(--mainForegroundColor);
+      mask-image: url('../../../assets/images/global/syndication.svg');
     }
   }
 }
\ No newline at end of file
index cc643f9d952d7a80cf65e4c5f11e71e4700863c5..895879adc5311ce210c734dbc8af78046f29081f 100644 (file)
@@ -22,7 +22,7 @@
       transition: color 0.2s;
       font-size: 16px;
       font-weight: $font-semibold;
-      color: $fg-color;
+      color: var(--mainForegroundColor);
       margin-top: 5px;
       margin-bottom: 5px;
 
index 892520e408afba4ebcbb2f984939e411e4dfb767..2f078d46d2a9b16cce2d91dc93dc7894b4625d5e 100644 (file)
@@ -5,8 +5,6 @@ $border-width: 3px;
 $border-type: solid;
 $border-color: #EAEAEA;
 
-$background-color:  #F7F7F7;
-
 /deep/ .root-tabset.video-add-tabset {
   &.hide-nav .nav {
     display: none !important;
@@ -24,7 +22,6 @@ $background-color:  #F7F7F7;
     a.nav-link {
       @include disable-default-a-behaviour;
 
-      color: #000;
       height: 40px !important;
       padding: 0 30px !important;
       font-size: 15px;
@@ -32,10 +29,10 @@ $background-color:  #F7F7F7;
       &.active {
         border: $border-width $border-type $border-color;
         border-bottom: none;
-        background-color: $background-color !important;
+        background-color: var(--mainBackgroundColor) !important;
 
         span {
-          border-bottom: 2px solid #F1680D;
+          border-bottom: 2px solid var(--mainColor);
           font-weight: $font-bold;
         }
       }
@@ -46,7 +43,7 @@ $background-color:  #F7F7F7;
     border: $border-width $border-type $border-color;
     border-top: none;
 
-    background-color: $background-color;
+    background-color: var(--mainBackgroundColor);
     border-radius: 3px;
     width: 100%;
     min-height: 440px;
index 78bcfe1212a432784f9023e961d33e02969691b4..285db061fbe53cb74a203e35e4944087a703d9f1 100644 (file)
@@ -35,7 +35,7 @@
       .comment-account {
         @include disable-default-a-behaviour;
 
-        color: #000;
+        color: var(--mainForegroundColor);
         font-weight: $font-bold;
       }
 
index be1388a836a872c8ca7eac25778f31b281c848fe..edd5ae6ba85a85c3f9e074c635f94bd0b59286ff 100644 (file)
         a {
           @include disable-default-a-behaviour;
 
-          color: #000;
+          color: var(--mainForegroundColor);
 
           &:hover {
             opacity: 0.8;
           display: inline;
           align-items: center;
           font-size: 13px;
-          color: #000;
+          color: var(--mainForegroundColor);
 
           span:hover {
             opacity: 0.8;
 
       a.video-attribute-value {
         @include disable-default-a-behaviour;
-        color: #000;
+        color: var(--mainForegroundColor);
 
         &:hover {
           opacity: 0.9;
   a {
     @include disable-default-a-behaviour;
 
-    color: $orange-color;
+    color: var(--mainColor);
     transition: color 0.3s;
 
     &:hover {
   }
 
   .privacy-concerns-okay {
-    background-color: $orange-color;
+    background-color: var(--mainColor);
     padding: 5px 8px 5px 7px;
     margin-left: auto;
     border-radius: 3px;
index e7dc60b4b8164271952da6cc16034ee27d571883..f5508cf614f78b05346c6631dc8b8b5c1602d479 100644 (file)
@@ -21,7 +21,7 @@
   a {
     @include disable-default-a-behaviour;
 
-    color: #000;
+    color: var(--mainForegroundColor);
   }
 }
 
diff --git a/client/src/assets/images/menu/moonsun.svg b/client/src/assets/images/menu/moonsun.svg
new file mode 100644 (file)
index 0000000..fe2a963
--- /dev/null
@@ -0,0 +1 @@
+<svg height="300px" width="300px" fill="#fff" xmlns="http://www.w3.org/2000/svg" data-name="Layer 1" viewBox="0 0 100 100" x="0px" y="0px"><title>Artboard 633</title><circle cx="50" cy="6" r="4"/><circle cx="50" cy="94" r="4"/><circle cx="6" cy="50" r="4"/><circle cx="94" cy="50" r="4"/><circle cx="18" cy="18" r="4"/><circle cx="82" cy="82" r="4"/><circle cx="18" cy="82" r="4"/><circle cx="82" cy="18" r="4"/><path d="M82,50A32,32,0,1,0,50,82,32,32,0,0,0,82,50ZM50,26a23.67,23.67,0,0,1,5.87.76c4.36,9.93.57,19-4.66,24.29s-14.4,9.24-24.45,4.83A23.75,23.75,0,0,1,26,50,24,24,0,0,1,50,26Zm0,48a23.94,23.94,0,0,1-18.26-8.47,29.38,29.38,0,0,0,3.74.26,30.07,30.07,0,0,0,21.41-9.11,29.82,29.82,0,0,0,8.61-25A24,24,0,0,1,50,74Z"/></svg>
\ No newline at end of file
index a4fea13c26ba768a938048cdf320e76f4231de9b..b92036de78c5c0b6313a036544cc895eae4e0657 100644 (file)
@@ -21,7 +21,7 @@ $assets-path: '../assets/';
 body {
   font-family: $main-fonts;
   font-weight: $font-regular;
-  color: #000;
+  color: var(--mainForegroundColor);
   font-size: 14px;
 }
 
@@ -83,7 +83,7 @@ label {
   }
 
   .sub-menu {
-    background-color: #F7F7F7;
+    background-color: var(--submenuColor);
     width: 100%;
     height: 81px;
     margin-bottom: 30px;
@@ -110,7 +110,7 @@ label {
 }
 
 .title-page {
-  color: #000;
+  color: var(--mainForegroundColor);
   font-size: 16px;
   display: inline-block;
   margin-right: 55px;
@@ -118,14 +118,14 @@ label {
   @include disable-default-a-behaviour;
 
   &.active, &.title-page-single {
-    border-bottom: 2px solid $orange-color;
+    border-bottom: 2px solid var(--mainColor);
     font-weight: $font-bold;
     margin-top: 30px;
     margin-bottom: 25px;
   }
 
   &:hover, &:active, &:focus {
-    color: #000;
+    color: var(--mainForegroundColor);
   }
 
   @media screen and (max-width: 500px) {
@@ -146,13 +146,14 @@ label {
     @include disable-default-a-behaviour;
 
     font-size: 16px;
-    color: #000;
+    color: var(--mainForegroundColor);
     padding: 5px 15px;
     border-radius: 0.25rem;
 
     &.active {
       font-weight: $font-semibold;
       background-color: #f0f0f0;
+      color: #000;
     }
   }
 }
@@ -188,6 +189,10 @@ label {
 }
 
 .modal {
+  .modal-content {
+    background-color: var(--mainBackgroundColor);
+  }
+
   .modal-header {
     border-bottom: none;
     margin-bottom: 5px;
@@ -249,7 +254,7 @@ label {
   a {
     @include disable-default-a-behaviour;
 
-    color: #000;
+    color: var(--mainForegroundColor);
   }
 }
 
@@ -259,7 +264,7 @@ ngb-tabset.bootstrap {
     &, & a {
       @include disable-default-a-behaviour;
 
-      color: #000 !important;
+      color: var(--mainForegroundColor) !important;
     }
   }
 }
index 765297c87f828c8cc11d6f4723ee8cad379c04c4..6e2feb748b06d5fbda21b7b55df5d381ec308009 100644 (file)
   display: inline-block;
   height: $button-height;
   width: $width;
-  background: #fff;
+  background: var(--inputColor);
   border: 1px solid #C6C6C6;
   border-radius: 3px;
   padding-left: 15px;
   padding-right: 15px;
+
+  &::placeholder {
+    color: var(--inputPlaceholderColor);
+  }
 }
 
 @mixin peertube-input-group($width) {
@@ -73,6 +77,7 @@
 
   .input-group-text{
     font-size: 14px;
+    color: gray;
   }
 }
 
 @mixin orange-button {
   &, &:active, &:focus {
     color: #fff;
-    background-color: $orange-color;
+    background-color: var(--mainColor);
   }
 
   &:hover {
     color: #fff;
-    background-color: $orange-hoover-color;
+    background-color: var(--mainHoverColor);
   }
 
   &[disabled], &.disabled {
   width: $width;
   border-radius: 3px;
   overflow: hidden;
-  background: #fff;
+  background: var(--inputColor);
   position: relative;
   font-size: 15px;
 
     position: relative;
     width: 18px;
     height: 18px;
-    border: $border-width solid #000;
+    border: $border-width solid var(--mainForegroundColor);
     border-radius: 3px;
     vertical-align: middle;
     cursor: pointer;
       height: 12px;
       opacity: 0;
       transform: rotate(45deg) scale(0);
-      border-right: 2px solid #fff;
-      border-bottom: 2px solid #fff;
+      border-right: 2px solid var(--mainForegroundColor);
+      border-bottom: 2px solid var(--mainForegroundColor);
     }
   }
 
   &:checked + span {
     border-color: transparent;
-    background: $orange-color;
+    background: var(--mainColor);
     animation: jelly 0.6s ease;
 
     &:after {
 
 @mixin in-content-small-title {
   text-transform: uppercase;
-  color: $orange-color;
+  color: var(--mainColor);
   font-weight: $font-bold;
   font-size: 13px;
 }
 @mixin actor-owner {
   @include disable-default-a-behaviour;
 
-  display: block;
+  display: inline-table;
   font-size: 13px;
   margin-top: 4px;
-  color: #000;
+  color: var(--mainForegroundColor);
 
   span:hover {
     opacity: 0.8;
index 7fd178c3b9b3a2378dc1dd79d9afe5b958591241..792a3f9c2f1157577607237d5cd824a2820e831d 100644 (file)
@@ -8,8 +8,6 @@ $grey-hoover-color: #EFEFEF;;
 $orange-color: #F1680D;
 $orange-hoover-color: #F97D46;
 
-$black-background: #000;
-$grey-background: #f6f2f2;
 $bg-color: #fff;
 $fg-color: #000;
 
@@ -27,11 +25,14 @@ $header-height: 50px;
 $header-border-color: #e9eff6;
 $search-input-width: 375px;
 
+$menu-background: #000;
 $menu-color: #fff;
 $menu-bottom-color: #C6C6C6;
 $menu-width: 240px;
 $menu-left-padding: 26px;
 
+$sub-menu-color: #F7F7F7;
+
 $footer-height: 30px;
 $footer-margin: 30px;
 
@@ -41,3 +42,40 @@ $video-thumbnail-height: 110px;
 $video-thumbnail-width: 200px;
 
 $theater-bottom-space: 85px;
+
+$input-color: $bg-color;
+$input-placeholder-color: #898989;
+
+/*** theme ***/
+
+body {
+  // now beware node-sass requires interpolation
+  // for css custom properties #{$var}
+  --mainColor: #{$orange-color};
+  --mainHoverColor: #{$orange-hoover-color};
+  --mainBackgroundColor: #{$bg-color};
+  --mainForegroundColor: #{$fg-color};
+  --submenuColor: #{$sub-menu-color};
+  --inputColor: #{$input-color};
+  --inputPlaceholderColor: #{$input-placeholder-color};
+}
+
+/*** map theme ***/
+
+// pass variables into a sass map,
+// to be warned of non-existing variables
+$variables: (
+  --mainColor: var(--mainColor),
+  --mainHoverColor: var(--mainHoverColor),
+  --mainBackgroundColor: var(--mainBackgroundColor),
+  --mainForegroundColor: var(--mainForegroundColor),
+  --submenuColor: var(--submenuColor),
+  --inputColor: var(--inputColor),
+  --inputPlaceholderColor: var(--inputPlaceholderColor)
+);
+
+/*** theme helper ***/
+
+@function var($variable) {
+  @return map-get($variables, $variable);
+}
index 1ec5c7da20c4c9bb3d261e45a394c0a044335019..a998652d5c1e446915f2677a23b21c5970c8cd52 100644 (file)
@@ -167,7 +167,7 @@ p-table {
           &.ui-state-active {
             &, &:hover, &:active, &:focus {
               color: #fff !important;
-              background-color: $orange-color !important;
+              background-color: var(--mainColor) !important;
             }
           }
         }