Skip to content

Commit

Permalink
feat(docs): speed up navigation through turbolinks (VIV-1585)
Browse files Browse the repository at this point in the history
  • Loading branch information
RichardHelm committed Feb 23, 2024
1 parent c98fb90 commit 2a7300d
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 70 deletions.
5 changes: 3 additions & 2 deletions apps/docs/_layouts/base.njk
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,12 @@
{% block header %}{% endblock %}

<script type="module" src="{{ '/assets/scripts/live-sample.js' | url}}"></script>
<script type="module" src="{{ '/assets/scripts/turbolinks.js' | url}}"></script>
<script src="{{ '/assets/scripts/cache-assets.js' | url}}"></script>

</head>

<body>
<body hx-boost="true" hx-target="main" hx-select="main" hx-swap="innerHTML scroll:html:top">

<vwc-header id="header-main" slot="app-content">

Expand All @@ -106,7 +107,7 @@
{% include "navigation.njk" %}
</vwc-layout>

<main slot="app-content">
<main slot="app-content" hx-history-elt>
{% block banner %}{% endblock %}
<vwc-layout column-basis="block" class="main-layout">
<article class="article">
Expand Down
42 changes: 39 additions & 3 deletions apps/docs/assets/bundled-scripts/icons-gallery.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ let jsonData;
let index = 0;
let numShown = NUM_TO_SHOW;

fetchJSONData();

async function fetchJSONData() {
export async function initIconsGallery() {
try {
const response = await fetch(`${BASE_URL}/v${ICON_SET_VERSION}/manifest.json`);
jsonData = await response.json();
Expand Down Expand Up @@ -44,6 +42,7 @@ function addOption(categoryName) {

function showIcons(data) {
index = 0;
let last;
while (last = iconsLayout.lastChild) iconsLayout.removeChild(last);
while (index < data.length) {
addIcon(data[index].id);
Expand Down Expand Up @@ -145,4 +144,41 @@ function filterIconsByTag(iconsArray) {
window.showMore = showMore;
window.onClickFilter = onClickFilter;

customElements.define('vivid-icons-gallery', class VividIconsGallery extends HTMLElement {
constructor() {
super();
this.innerHTML = `
<div class="div-wrapper">
<vwc-action-group shape="pill">
<vwc-text-field id="searchIcons" icon="search-line" placeholder="Search" appearance='ghost' shape="pill" oninput="onClickFilter()" aria-label="Search Icons"></vwc-text-field>
<vwc-divider orientation="vertical"></vwc-divider>
<vwc-select id="selectCategory" appearance='ghost' shape="pill" aria-label="Category" onchange="onClickFilter()">
<vwc-option text="Category"></vwc-option>
</vwc-select>
</vwc-action-group>
<div class="tag-wrapper">
<vwc-tag-group class="tag-group" onclick="onClickFilter()">
Filter By Style:
<vwc-tag id="solidTag" label="Solid" selectable shape="pill"></vwc-tag>
<vwc-tag id="linearTag" label="Line" selectable shape="pill"></vwc-tag>
</vwc-tag-group>
<vwc-tag-group class="tag-group" onclick="onClickFilter()">
Filter By Color:
<vwc-tag id="singleTag" label="Single Color" selectable shape="pill"></vwc-tag>
<vwc-tag id="multiTag" label="Multi Color" selectable shape="pill"></vwc-tag>
</vwc-tag-group>
</div>
<vwc-layout id="iconsLayout" gutters="small">
</vwc-layout>
<div class="button-wrapper">
<vwc-button id="showMoreButton" label="Show More" appearance='filled' onclick="showMore()" shape="pill"></vwc-button>
</div>
<vwc-alert id="copyAlert" text="Icon name copied to clipboard" connotation="success" timeoutms="2000"></vwc-alert>
</div>`;
}

connectedCallback() {
initIconsGallery();
}
});

23 changes: 17 additions & 6 deletions apps/docs/assets/bundled-scripts/live-sample.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@ import { html } from "@codemirror/lang-html"
import { Compartment } from '@codemirror/state'
import { oneDark } from '@codemirror/theme-one-dark'

window.onload = () => {
addSamplesEditors();
addButtonsHandlers();
addLocaleSwitcher();
};

const samplesEditors = new Map();
const theme = new Compartment();

Expand Down Expand Up @@ -159,3 +153,20 @@ function switchLocale(event) {
iframe.contentWindow.setLocale(iframe.contentWindow.locales[select.value]);
iframe.contentWindow.document.documentElement.lang = select.value;
}

function cleanupEditors() {
for (const { view } of samplesEditors.values()) {
view.destroy();
}
samplesEditors.clear();
}

function setupLiveSamples() {
cleanupEditors();
addSamplesEditors();
addButtonsHandlers();
addLocaleSwitcher();
}

window.addEventListener('load', setupLiveSamples);
window.addEventListener('htmx:afterSwap', setupLiveSamples);
31 changes: 31 additions & 0 deletions apps/docs/assets/bundled-scripts/turbolinks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import 'htmx.org';

window.addEventListener('DOMContentLoaded', () => {
const navItems = document.querySelectorAll('vwc-nav-item');
for (const navItem of navItems) {
navItem.setAttribute('hx-get', navItem.href);
navItem.setAttribute('hx-push-url', 'true');
navItem.addEventListener('click', (e) => { e.preventDefault() });
window.htmx.process(navItem);
}
});

const handleLocationChange = () => {
for (const el of document.querySelectorAll('vwc-nav-item[aria-current="page"], vwc-nav-disclosure[aria-current="page"]')) {
el.removeAttribute('aria-current');
}

let current = document.querySelector(`
vwc-nav-item[href="${location.pathname}"],
vwc-nav-item[href="${location.pathname.replace(/\/$/, '')}"]
`);
while (current) {
if (current.tagName === 'VWC-NAV-ITEM' || current.tagName === 'VWC-NAV-DISCLOSURE') {
current.setAttribute('aria-current', 'page');
}
current = current.parentElement;
}
}

window.addEventListener("popstate", handleLocationChange);
window.addEventListener("htmx:pushedIntoHistory", handleLocationChange);
45 changes: 28 additions & 17 deletions apps/docs/assets/scripts/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,13 @@ const codeBlockButtonClick = (button) => {
button.ariaExpanded = details.open;
};

const onloadIframe = (iFrame) => {
const toggle = document.querySelector('vwc-button#dark-mode-toggle');
const menu = document.querySelector('vwc-menu#dark-mode-menu');

setCurrentIframeTheme(toggle, iFrame);
menu.addEventListener('click', () => {
setCurrentIframeTheme(toggle, iFrame);
});
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => setCurrentIframeTheme(toggle, iFrame));
const getCurrentTheme = () =>
document.querySelector('vwc-button#dark-mode-toggle').icon === 'dark-mode-solid' ? 'dark' : 'light';

const onloadIframe = (iFrame) => {
console.log('onloadIframe');
iFrame.setAttribute('data-vivid-iframe', '');
setCurrentIframeTheme(getCurrentTheme(), iFrame);
autoResize(iFrame);
};

Expand All @@ -51,16 +48,30 @@ const autoResize = (iFrame) => {
}).observe(iFrame.contentWindow.document.documentElement);
};

const setCurrentIframeTheme = (toggle, iFrame) => {
const setCurrentIframeTheme = (displayMode, iFrame) => {
const iframeHead = iFrame.contentWindow.document.head;

const displayMode = toggle.icon === "dark-mode-solid" ? 'dark' : 'light';
const theme = `<link id="theme-link" rel="stylesheet" href="/assets/styles/tokens/theme-${displayMode}.css" media="all">`;
const theme = `<link id="theme-link" rel="stylesheet" href="/assets/styles/tokens/theme-${displayMode}.css" data-theme="${displayMode}" media="all">`;

const themeLink = iframeHead.querySelector('#theme-link');
if (themeLink) {
themeLink.outerHTML = theme;
} else {
iframeHead.insertAdjacentHTML("beforeend", theme);
}
if (!themeLink) {
iframeHead.insertAdjacentHTML("beforeend", theme);
} else if (themeLink.dataset.theme !== displayMode) {
themeLink.outerHTML = theme;
}
}

const updateThemeOfAllIframes = () => {
const newTheme = getCurrentTheme();
for (const iframe of document.querySelectorAll('[data-vivid-iframe]')) {
setCurrentIframeTheme(newTheme, iframe);
}
}

const setupIframeThemeUpdates = () => {
document
.querySelector('vwc-menu#dark-mode-menu')
.addEventListener('change', updateThemeOfAllIframes);
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', updateThemeOfAllIframes);
}
window.addEventListener('load', setupIframeThemeUpdates);
14 changes: 0 additions & 14 deletions apps/docs/assets/scripts/scroll-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,13 @@ const onScroll = () => {
const isWindowScrolled = window.scrollY > 0;
const isSideDrawerScrolled = getSideDrawerBase().scrollTop > 0;
updateHeaderElevationShadow(isWindowScrolled || isSideDrawerScrolled);
// save sideDrawer's scroll in sessionStorage
if (getSideDrawerBase().scrollTop) {
sessionStorage.setItem("scroll", getSideDrawerBase().scrollTop);
}
}

const setScrollFromSessionStorage = () => {
// set sideDrawer's scroll from sessionStorage
if (getSideDrawerBase().offsetHeight > 0) {
getSideDrawerBase().scrollTop = sessionStorage.getItem('scroll') ?? 0;
} else {
requestAnimationFrame(setScrollFromSessionStorage);
}
}

(() => {
// hook window scroll
window.addEventListener('scroll', onScroll);

customElements.whenDefined('vwc-side-drawer').then(() => {
setScrollFromSessionStorage();
getSideDrawerBase().addEventListener('scroll', onScroll);
});
})();
2 changes: 2 additions & 0 deletions apps/docs/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,14 @@ const DIRS = [
'./dist/apps/docs/assets/scripts/',
'./dist/apps/docs/assets/scripts/',
'./dist/apps/docs/assets/scripts/',
'./dist/apps/docs/assets/scripts/',
'./dist/apps/docs',
];
export default [
'./apps/docs/assets/bundled-scripts/live-sample.js',
'./apps/docs/assets/bundled-scripts/cache-assets.js',
'./apps/docs/assets/bundled-scripts/icons-gallery.js',
'./apps/docs/assets/bundled-scripts/turbolinks.js',
'vivid-components',
'./apps/docs/assets/bundled-scripts/sw.js',
].map((input, index) => {
Expand Down
31 changes: 3 additions & 28 deletions docs/icon/icons-gallery.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,7 @@ As an example, you can use it as follows:

<link rel="stylesheet" href="../../assets/styles/icons-gallery.css">

<div class="div-wrapper">
<vwc-action-group shape="pill">
<vwc-text-field id="searchIcons" icon="search-line" placeholder="Search" appearance='ghost' shape="pill" oninput="onClickFilter()" aria-label="Search Icons"></vwc-text-field>
<vwc-divider orientation="vertical"></vwc-divider>
<vwc-select id="selectCategory" appearance='ghost' shape="pill" aria-label="Category" onchange="onClickFilter()">
<vwc-option text="Category"></vwc-option>
</vwc-select>
</vwc-action-group>
<div class="tag-wrapper">
<vwc-tag-group class="tag-group" onclick="onClickFilter()">
Filter By Style:
<vwc-tag id="solidTag" label="Solid" selectable shape="pill"></vwc-tag>
<vwc-tag id="linearTag" label="Line" selectable shape="pill"></vwc-tag>
</vwc-tag-group>
<vwc-tag-group class="tag-group" onclick="onClickFilter()">
Filter By Color:
<vwc-tag id="singleTag" label="Single Color" selectable shape="pill"></vwc-tag>
<vwc-tag id="multiTag" label="Multi Color" selectable shape="pill"></vwc-tag>
</vwc-tag-group>
</div>
<vwc-layout id="iconsLayout" gutters="small">
</vwc-layout>
<div class="button-wrapper">
<vwc-button id="showMoreButton" label="Show More" appearance='filled' onclick="showMore()" shape="pill"></vwc-button>
</div>
<vwc-alert id="copyAlert" text="Icon name copied to clipboard" connotation="success" timeoutms="2000"></vwc-alert>
</div>
<vivid-icons-gallery></vivid-icons-gallery>

<script type="module" src="../../assets/scripts/icons-gallery.js"></script>

<script src="../../assets/scripts/icons-gallery.js" async></script>
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"expr-eval": "^2.0.2",
"glob": "^7.2.0",
"highlight.js": "^11.5.1",
"htmx.org": "^1.9.10",
"http-server": "^14.1.0",
"jasmine-core": "4.1.1",
"jasmine-spec-reporter": "~5.0.0",
Expand Down

0 comments on commit 2a7300d

Please sign in to comment.