Skip to content

Commit

Permalink
#69: Add observer for detecting head attribute mutation.
Browse files Browse the repository at this point in the history
  • Loading branch information
nizniz187 committed Sep 3, 2022
1 parent 0dc82a3 commit 21e5aef
Show file tree
Hide file tree
Showing 7 changed files with 228 additions and 35 deletions.
20 changes: 15 additions & 5 deletions dist/index.bundle.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,12 @@
document.querySelector('#btnDarkTheme').addEventListener('click', function(e) {
this.style.display = 'none';
document.querySelector('#btnLightTheme').style.display = 'flex';
wc.initTheme('dark');
wc.setTheme('dark');
});
document.querySelector('#btnLightTheme').addEventListener('click', function(e) {
this.style.display = 'none';
document.querySelector('#btnDarkTheme').style.display = 'flex';
wc.initTheme('light');
wc.setTheme('light');
});

// manipulate calendar
Expand Down
8 changes: 8 additions & 0 deletions packages/w-components/WComponent.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import DOM from "./util/DOM.js";
import Theme from './util/Theme.js';

class WComponent extends HTMLElement{
/**
Expand Down Expand Up @@ -31,6 +32,13 @@ class WComponent extends HTMLElement{
this.update({name, oldValue, newValue});
}
}
/**
* Create & bind observer on head style theme changed.
* @param {function} callback
*/
bindThemeChangedObserver(callback) {
Theme.bindChangedObserver(callback);
}
/**
* Dynamically create getters & setters for property-attribute sync
* by parsing class field attribute object.
Expand Down
152 changes: 145 additions & 7 deletions packages/w-components/components/Code.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import WComponent, { DOM, AttributeParser } from "../WComponent.js";
import Theme, { THEME_LIGHT_NAME, THEME_DARK_NAME } from '../util/Theme.js';

const stylesheet = `
:host {
display: block;
color: var(--color-gray-80);
background-color: var(--color-gray-10);
border-radius: 4px;
padding: 20px;
white-space: pre-wrap;
}
`;
const lightThemeStylesheet = `
/*!
Theme: GitHub
Description: Light theme as seen on github.com
Expand Down Expand Up @@ -125,14 +136,131 @@ const stylesheet = `
.hljs-tag {
/* purposely ignored */
}
`;
const darkThemeStylesheet = `
/*!
Theme: GitHub Dark
Description: Dark theme as seen on github.com
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Outdated base version: https://github.com/primer/github-syntax-dark
Current colors taken from GitHub's CSS
*/
:host {
display: block;
color: var(--color-gray-80);
background-color: var(--color-gray-10);
border-radius: 4px;
padding: 20px;
white-space: pre-wrap;
.hljs {
color: #c9d1d9;
background: #0d1117;
}
.hljs-doctag,
.hljs-keyword,
.hljs-meta .hljs-keyword,
.hljs-template-tag,
.hljs-template-variable,
.hljs-type,
.hljs-variable.language_ {
/* prettylights-syntax-keyword */
color: #ff7b72;
}
.hljs-title,
.hljs-title.class_,
.hljs-title.class_.inherited__,
.hljs-title.function_ {
/* prettylights-syntax-entity */
color: #d2a8ff;
}
.hljs-attr,
.hljs-attribute,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-operator,
.hljs-variable,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-id {
/* prettylights-syntax-constant */
color: #79c0ff;
}
.hljs-regexp,
.hljs-string,
.hljs-meta .hljs-string {
/* prettylights-syntax-string */
color: #a5d6ff;
}
.hljs-built_in,
.hljs-symbol {
/* prettylights-syntax-variable */
color: #ffa657;
}
.hljs-comment,
.hljs-code,
.hljs-formula {
/* prettylights-syntax-comment */
color: #8b949e;
}
.hljs-name,
.hljs-quote,
.hljs-selector-tag,
.hljs-selector-pseudo {
/* prettylights-syntax-entity-tag */
color: #7ee787;
}
.hljs-subst {
/* prettylights-syntax-storage-modifier-import */
color: #c9d1d9;
}
.hljs-section {
/* prettylights-syntax-markup-heading */
color: #1f6feb;
font-weight: bold;
}
.hljs-bullet {
/* prettylights-syntax-markup-list */
color: #f2cc60;
}
.hljs-emphasis {
/* prettylights-syntax-markup-italic */
color: #c9d1d9;
font-style: italic;
}
.hljs-strong {
/* prettylights-syntax-markup-bold */
color: #c9d1d9;
font-weight: bold;
}
.hljs-addition {
/* prettylights-syntax-markup-inserted */
color: #aff5b4;
background-color: #033a16;
}
.hljs-deletion {
/* prettylights-syntax-markup-deleted */
color: #ffdcd7;
background-color: #67060c;
}
.hljs-char.escape_,
.hljs-link,
.hljs-params,
.hljs-property,
.hljs-punctuation,
.hljs-tag {
/* purposely ignored */
}
`;
class Code extends WComponent{
Expand All @@ -157,6 +285,7 @@ class Code extends WComponent{
constructor(){
super();
this.bindObserver();
this.bindThemeChangedObserver(theme => this.setThemeStylesheet(theme));
}

bindObserver() {
Expand Down Expand Up @@ -188,6 +317,15 @@ class Code extends WComponent{
this.parseAttributeValueByName(name, newValue);
this.loadHighlightContent();
}

setThemeStylesheet(theme) {
if(theme === THEME_DARK_NAME) {
this.setStylesheet(darkThemeStylesheet, 'theme');
} else {
this.setStylesheet(lightThemeStylesheet, 'theme');
}
this.loadHighlightContent();
}
}
Code.prototype.stylesheet=stylesheet;

Expand Down
25 changes: 4 additions & 21 deletions packages/w-components/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import DOM from "./util/DOM.js";
import DarkThemeStylesheet from "./theme/dark.css.js";
import LightThemeStylesheet from "./theme/light.css.js";
import Theme from "./util/Theme.js";

import AlertDialog from "./components/dialog/AlertDialog.js";
import Button from "./components/button/Button.js";
Expand Down Expand Up @@ -36,31 +35,15 @@ import TextInput from "./components/form/TextInput.js";
import TextArea from "./components/form/TextArea.js";
import TypeWriter from "./components/TypeWriter.js";

const THEME_STYLESHEET_ID = "wc-theme-stylesheet";

const defaultWConfig={theme:"light", spa:{basename:""}};
const wc={
init: function(wconfig={}){
window.wconfig=Object.assign(defaultWConfig, wconfig);
window.wconfig.prefix='w'; // force prefix to 'w'

this.initTheme(window.wconfig.theme);
this.setTheme(window.wconfig.theme);
},
initTheme:function(name){
const head=document.querySelector("head");
const themeElement=head.querySelector(`#${THEME_STYLESHEET_ID}`);
if(themeElement){
themeElement.remove();
}
let stylesheet;
if(name==="dark"){
stylesheet=DarkThemeStylesheet;
}else{
stylesheet=LightThemeStylesheet;
}
DOM.create("style", {props:{
id:THEME_STYLESHEET_ID, textContent:stylesheet
}}, head);
setTheme: function(name) {
Theme.setElement(name);
}
};

Expand Down
2 changes: 2 additions & 0 deletions packages/w-components/util/DOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const DOM={
}
return element;
},

setProperties:function(element, properties){
for(const name in properties){
element[name]=properties[name];
Expand All @@ -54,6 +55,7 @@ const DOM={
}
return element;
},

addListeners:function(element, listeners, useCapture){
for(const name in listeners){
if(listeners[name] instanceof Array){
Expand Down
52 changes: 52 additions & 0 deletions packages/w-components/util/Theme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import DOM from './DOM.js';
import DarkThemeStylesheet from "../theme/dark.css.js";
import LightThemeStylesheet from "../theme/light.css.js";

const Theme = {
bindChangedObserver(callback) {
const handler = mutation => {
const theme = this.getCurrentName();
if(mutation[0].attributeName === ATTR_NAME && mutation[0].oldValue !== theme) {
callback(theme);
}
};
const observer = new MutationObserver(handler);
observer.observe(document.head, { attributes: true, attributeOldValue: true });
},
createElement(stylesheet) {
DOM.create("style", {props:{
id: STYLESHEET_ID, textContent: stylesheet
}}, document.head);
},
getCurrentName() {
return document.head.getAttribute(ATTR_NAME);
},
getElement() {
return document.head.querySelector(`#${STYLESHEET_ID}`);
},
setElement(name) {
const element = this.getElement();
if(element){
element.remove();
}

let stylesheet = LightThemeStylesheet;
if(name === DARK_NAME){
stylesheet=DarkThemeStylesheet;
}
this.createElement(stylesheet);
document.head.setAttribute(ATTR_NAME, name)
window.wconfig.theme = name;
}
};

const STYLESHEET_ID = 'w-theme-stylesheet';
const ATTR_NAME = 'theme';
const LIGHT_NAME = 'light';
const DARK_NAME = 'dark';

export default Theme;
export {
STYLESHEET_ID as THEME_STYLESHEET_ID, ATTR_NAME as THEME_ATTR_NAME,
LIGHT_NAME as THEME_LIGHT_NAME, DARK_NAME as THEME_DARK_NAME
};

0 comments on commit 21e5aef

Please sign in to comment.