add project files

This commit is contained in:
zombieFox 2022-05-21 17:52:23 +01:00
parent 29d9e2e9b5
commit f8df65f2dc
66 changed files with 19256 additions and 0 deletions

24
.github/workflows/gh-pages-deploy.yml vendored Normal file
View File

@ -0,0 +1,24 @@
name: gh-pages-deploy
on:
push:
branches:
- main
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2.3.1
with:
persist-credentials: false
- name: Install and Build
run: |
npm install
npm run build
- name: Deploy
uses: JamesIves/github-pages-deploy-action@4.1.3
with:
branch: gh-pages
folder: dist/web

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.DS_Store
dist
node_modules

8814
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

43
package.json Normal file
View File

@ -0,0 +1,43 @@
{
"name": "Volt Tab",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack serve --open --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
},
"keywords": [
"startpage",
"start-page",
"newtabpage",
"new-tab-page",
"tab",
"chrome-extension",
"extension",
"bookmarks",
"links",
"gridTab"
],
"author": "zombieFox",
"license": "GPL-3",
"bugs": {
"url": "https://github.com/zombieFox/gridTab/issues"
},
"homepage": "https://github.com/zombieFox/gridTab#readme",
"devDependencies": {
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.7.1",
"css-minimizer-webpack-plugin": "^4.0.0",
"html-webpack-plugin": "^5.5.0",
"mini-css-extract-plugin": "^2.6.0",
"sortablejs": "^1.15.0",
"style-loader": "^3.3.1",
"webfontloader": "^1.6.28",
"webpack": "^5.72.1",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.9.0",
"webpack-merge": "^5.8.0",
"zip-webpack-plugin": "^4.0.1"
}
}

5
src/app/index.css Normal file
View File

@ -0,0 +1,5 @@
.app {
min-width: 100vw;
min-height: 100vh;
display: grid;
}

42
src/app/index.js Normal file
View File

@ -0,0 +1,42 @@
import { Base } from '../component/Base';
import { Body } from '../component/Body';
import { Background } from '../component/Background';
import { Bookmark } from '../component/Bookmark';
import { Theme } from '../component/Theme';
import { Fontawesome } from '../component/Fontawesome';
import './index.css';
export const App = function() {
this.node = {
app: document.createElement('div')
}
this.base = new Base();
this.body = new Body();
this.theme = new Theme();
this.fontawesome = new Fontawesome();
this.background = new Background();
this.bookmark = new Bookmark();
this.render = () => {
this.node.app.classList.add('app');
this.theme.render();
this.background.render(this.node.app);
this.bookmark.render(this.node.app);
document.querySelector('body').appendChild(this.node.app);
}
};

View File

@ -0,0 +1,45 @@
:root {
--background-color-hsl:
var(--background-color-hsl-h),
calc(var(--background-color-hsl-s) * 1%),
calc(var(--background-color-hsl-l) * 1%);
}
.background {
display: block;
position: relative;
grid-column: 1 / -1;
grid-row: 1 / -1;
pointer-events: none;
z-index: var(--z-index-background);
}
.background-color,
.background-image,
.background-gradient {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.background-color {
background-color: hsl(var(--background-color-hsl));
z-index: 1;
}
.background-image {
background-image: var(--background-image-url);
background-attachment: fixed;
background-size: cover;
background-position: center;
opacity: var(--background-image-opacity);
filter: blur(calc(var(--background-image-blur) * 1px)) grayscale(var(--background-image-grayscale));
z-index: 2;
}
.background-gradient {
background: linear-gradient(var(--background-gradient-degree), var(--background-gradient-color));
z-index: 3;
}

View File

@ -0,0 +1,80 @@
import { config } from '../../config';
import { isValidString } from '../utility/isValidString';
import { applyCSSVar } from '../utility/applyCSSVar';
import './index.css';
export const Background = function() {
this.node = {
background: document.createElement('div'),
color: document.createElement('div'),
image: document.createElement('div'),
gradient: document.createElement('div')
}
this.style = () => {
applyCSSVar('--background-color-hsl-h', config.background.color.hsl[0]);
applyCSSVar('--background-color-hsl-s', config.background.color.hsl[1]);
applyCSSVar('--background-color-hsl-l', config.background.color.hsl[2]);
if (isValidString(config.background.image.url)) {
applyCSSVar('--background-image-url', `url(${config.background.image.url})`);
applyCSSVar('--background-image-opacity', config.background.image.opacity);
applyCSSVar('--background-image-grayscale', config.background.image.grayscale);
applyCSSVar('--background-image-blur', config.background.image.blur);
}
if (config.background.gradient.color.length > 0) {
applyCSSVar('--background-gradient-degree', `${config.background.gradient.degree}deg`);
let gradientColor = '';
config.background.gradient.color.forEach((gradientColorItem, index) => {
gradientColor = gradientColor + `hsla(${gradientColorItem.hsla[0]}, ${gradientColorItem.hsla[1]}%, ${gradientColorItem.hsla[2]}%, ${gradientColorItem.hsla[3]}) ${gradientColorItem.position}%`;
if (index < config.background.gradient.color.length - 1) {
gradientColor = gradientColor + ', ';
};
});
applyCSSVar('--background-gradient-color', gradientColor);
}
}
this.render = (element) => {
this.style();
this.node.background.classList.add('background');
this.node.color.classList.add('background-color');
this.node.image.classList.add('background-image');
this.node.gradient.classList.add('background-gradient');
this.node.background.appendChild(this.node.color);
this.node.background.appendChild(this.node.image);
this.node.background.appendChild(this.node.gradient);
element.appendChild(this.node.background);
}
}

View File

@ -0,0 +1,8 @@
// must be loaded first
import '../../style/reset/index.css';
// base styles for all components
import '../../style/typography/index.css';
import '../../style/zindex/index.css';
export const Base = function() {}

View File

@ -0,0 +1,28 @@
:root {
--font-size: calc(var(--theme-scale) * 0.025vmax);
}
::selection {
background-color: rgb(var(--theme-accent));
color: hsl(var(--theme-text));
}
html,
body {
background-color: hsl(var(--background-color-hsl));
font-size: var(--font-size);
line-height: 1.6;
font-family: var(--theme-font);
font-weight: var(--theme-font-ui-weight);
font-style: var(--theme-font-ui-style);
color: hsl(var(--theme-text));
transition: background-color var(--layout-transition-extra-fast);
}
body {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}

View File

@ -0,0 +1,3 @@
import './index.css';
export const Body = function() {}

View File

@ -0,0 +1,22 @@
.bookmark {
grid-column: 1 / -1;
grid-row: 1 / -1;
display: grid;
grid-template-columns: calc(var(--bookmark-panel-size) * 1vmax) 1fr;
align-items: center;
z-index: var(--z-index-bookmark);
}
.bookmark-panel {
/* margin: 2em 0 2em 2em; */
/* border-radius: 1em; */
grid-column: 1 / 2;
grid-row: 1 / -1;
align-self: normal;
background-color:
hsla(var(--theme-bookmark-background-color-hsla-h),
calc(var(--theme-bookmark-background-color-hsla-s) * 1%),
calc(var(--theme-bookmark-background-color-hsla-l) * 1%),
var(--theme-bookmark-background-color-hsla-a));
backdrop-filter: blur(calc(var(--theme-bookmark-group-background-blur) * 1px));
}

View File

@ -0,0 +1,74 @@
import { config } from '../../config';
import { BookmarkGroup } from '../BookmarkGroup';
import { applyCSSVar } from '../utility/applyCSSVar';
import './index.css';
export const Bookmark = function() {
this.node = {
bookmark: document.createElement('div'),
group: document.createElement('div'),
panel: document.createElement('div'),
allGroup: []
}
this.style = () => {
applyCSSVar('--bookmark-panel-size', config.bookmark.panel.size);
}
this.populateGroup = () => {
config.bookmark.group.set.forEach(groupItem => {
const bookmarkGroup = new BookmarkGroup(groupItem, this.node.allGroup);
bookmarkGroup.render();
this.node.allGroup.push(bookmarkGroup);
this.node.group.appendChild(bookmarkGroup.group());
});
}
this.render = (element) => {
this.style();
this.populateGroup();
this.node.bookmark.classList.add('bookmark');
this.node.group.classList.add('bookmark-group');
this.node.group.addEventListener('mouseleave', () => {
config.bookmark.group.set.forEach(bookmarkGroup => {
bookmarkGroup.active = false;
});
this.node.allGroup.forEach(group => {
group.renderActive();
});
});
this.node.panel.classList.add('bookmark-panel');
this.node.bookmark.appendChild(this.node.panel);
this.node.bookmark.appendChild(this.node.group);
element.appendChild(this.node.bookmark);
}
}

View File

@ -0,0 +1,125 @@
.bookmark-group {
grid-column: 1 / -1;
grid-row: 1 / -1;
display: flex;
flex-direction: column;
gap: 3em;
padding: 3em 0;
}
.bookmark-group-item {
display: grid;
grid-template-columns: calc(var(--bookmark-panel-size) * 1vmax) 1fr;
position: relative;
}
.bookmark-group-tab {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
text-align: right;
color: hsl(var(--bookmark-group-color-primary-hsl-h),
calc(var(--bookmark-group-color-primary-hsl-s) * 1%),
calc(var(--bookmark-group-color-primary-hsl-l) * 1%));
gap: 3em;
padding: 0 3em;
}
.bookmark-group-label {
display: flex;
flex-direction: column;
justify-content: center;
overflow: hidden;
user-select: none;
}
.bookmark-group-name {
font-size: 2em;
margin: 0;
padding: 0;
font-family: "Ubuntu", sans-serif;
font-weight: 100;
color: hsl(var(--bookmark-group-color-primary-hsl-h),
calc((var(--bookmark-group-color-primary-hsl-s) - 30) * 1%),
calc((var(--bookmark-group-color-primary-hsl-l) - 20) * 1%));
overflow: hidden;
text-overflow: ellipsis;
transition: color var(--theme-transition-fast-ease);
}
.bookmark-group-active .bookmark-group-name {
color: hsl(var(--bookmark-group-color-primary-hsl-h),
calc(var(--bookmark-group-color-primary-hsl-s) * 1%),
calc(var(--bookmark-group-color-primary-hsl-l) * 1%));
}
.bookmark-group-description {
font-size: 1em;
margin: 0;
padding: 0;
font-family: "Ubuntu", sans-serif;
font-weight: 500;
color: hsl(var(--bookmark-group-color-secondary-hsl-h),
calc((var(--bookmark-group-color-secondary-hsl-s) - 30) * 1%),
calc((var(--bookmark-group-color-secondary-hsl-l) - 20) * 1%));
overflow: hidden;
text-overflow: ellipsis;
transition: color var(--theme-transition-fast-ease);
}
.bookmark-group-active .bookmark-group-description {
color: hsl(var(--bookmark-group-color-secondary-hsl-h),
calc(var(--bookmark-group-color-secondary-hsl-s) * 1%),
calc(var(--bookmark-group-color-secondary-hsl-l) * 1%));
}
.bookmark-group-indicator {
flex-shrink: 0;
position: relative;
display: block;
width: 0.25em;
height: 100%;
}
.bookmark-group-indicator-top,
.bookmark-group-indicator-bottom {
width: 100%;
height: 0;
display: block;
position: absolute;
left: 50%;
border-radius: 1em;
transform: translateX(-50%);
background-color: hsl(var(--bookmark-group-color-secondary-hsl-h),
calc((var(--bookmark-group-color-secondary-hsl-s) - 30) * 1%),
calc((var(--bookmark-group-color-secondary-hsl-l) - 20) * 1%));
transition: height var(--theme-transition-fast-ease), background-color var(--theme-transition-medium-ease);
}
.bookmark-group-indicator-top {
bottom: calc(50% + 1.5em);
}
.bookmark-group-indicator-bottom {
top: calc(50% + 1.5em);
}
.bookmark-group-item:focus-within .bookmark-group-indicator-top,
.bookmark-group-item:focus-within .bookmark-group-indicator-bottom,
.bookmark-group-active .bookmark-group-indicator-top,
.bookmark-group-active .bookmark-group-indicator-bottom {
background-color: hsl(var(--bookmark-group-color-secondary-hsl-h),
calc(var(--bookmark-group-color-secondary-hsl-s) * 1%),
calc(var(--bookmark-group-color-secondary-hsl-l) * 1%));
height: 50%;
transition: height var(--theme-transition-medium-bounce) calc((var(--theme-transition-speed-xfast) / 2) * 1s), background-color var(--theme-transition-medium-ease);
}
.bookmark-group-list {
display: flex;
flex-wrap: wrap;
gap: 1em;
padding: 0 1em;
align-items: center;
}

View File

@ -0,0 +1,134 @@
import { config } from '../../config';
import { BookmarkLink } from '../BookmarkLink';
import { BookmarkOpenAll } from '../BookmarkOpenAll';
import './index.css';
export const BookmarkGroup = function(bookmarkGroupData, allBookmarkGroup) {
this.node = {
groupItem: document.createElement('div'),
tab: document.createElement('div'),
label: document.createElement('div'),
name: document.createElement('p'),
description: document.createElement('p'),
indicator: document.createElement('div'),
indicatorTop: document.createElement('span'),
indicatorBottom: document.createElement('span'),
list: document.createElement('div'),
openAll: null,
allList: []
}
this.style = () => {
this.node.groupItem.style.setProperty('--bookmark-group-color-primary-hsl-h', bookmarkGroupData.color.primary.hsl[0]);
this.node.groupItem.style.setProperty('--bookmark-group-color-primary-hsl-s', bookmarkGroupData.color.primary.hsl[1]);
this.node.groupItem.style.setProperty('--bookmark-group-color-primary-hsl-l', bookmarkGroupData.color.primary.hsl[2]);
this.node.groupItem.style.setProperty('--bookmark-group-color-secondary-hsl-h', bookmarkGroupData.color.secondary.hsl[0]);
this.node.groupItem.style.setProperty('--bookmark-group-color-secondary-hsl-s', bookmarkGroupData.color.secondary.hsl[1]);
this.node.groupItem.style.setProperty('--bookmark-group-color-secondary-hsl-l', bookmarkGroupData.color.secondary.hsl[2]);
}
this.toggleActiveState = () => {
config.bookmark.group.set.forEach(bookmarkGroup => {
bookmarkGroup.active = false;
});
bookmarkGroupData.active = true;
}
this.renderActive = () => {
bookmarkGroupData.active ? this.node.groupItem.classList.add('bookmark-group-active') : this.node.groupItem.classList.remove('bookmark-group-active');
}
this.render = () => {
this.node.groupItem.classList.add('bookmark-group-item');
this.node.groupItem.addEventListener('mouseenter', () => {
this.toggleActiveState();
allBookmarkGroup.forEach(group => {
group.renderActive();
});
});
this.node.tab.classList.add('bookmark-group-tab');
this.node.list.classList.add('bookmark-group-list');
this.node.tab.href = "#";
this.renderActive();
this.style();
this.node.label.classList.add('bookmark-group-label');
this.node.name.classList.add('bookmark-group-name');
this.node.description.classList.add('bookmark-group-description');
this.node.indicator.classList.add('bookmark-group-indicator');
this.node.indicatorTop.classList.add('bookmark-group-indicator-top');
this.node.indicatorBottom.classList.add('bookmark-group-indicator-bottom');
this.node.name.textContent = bookmarkGroupData.name;
this.node.description.textContent = bookmarkGroupData.description;
bookmarkGroupData.list.forEach((listItem, index) => {
const bookmarkLink = new BookmarkLink(listItem, (bookmarkGroupData.list.length - index));
bookmarkLink.render();
this.node.allList.push(bookmarkLink.link());
this.node.list.appendChild(bookmarkLink.link());
});
this.node.openAll = new BookmarkOpenAll(bookmarkGroupData);
this.node.openAll.render();
this.node.label.appendChild(this.node.name);
this.node.label.appendChild(this.node.description);
this.node.tab.appendChild(this.node.label);
this.node.indicator.appendChild(this.node.openAll.button());
this.node.indicator.appendChild(this.node.indicatorTop);
this.node.indicator.appendChild(this.node.indicatorBottom);
this.node.tab.appendChild(this.node.indicator);
this.node.groupItem.appendChild(this.node.tab);
this.node.groupItem.appendChild(this.node.list);
}
this.group = () => this.node.groupItem;
}

View File

@ -0,0 +1,49 @@
.bookmark-link:link,
.bookmark-link:visited,
.bookmark-link:hover,
.bookmark-link:focus,
.bookmark-link:active {
color: hsl(var(--bookmark-group-color-primary-hsl-h),
calc(var(--bookmark-group-color-primary-hsl-s) * 1%),
calc(var(--bookmark-group-color-primary-hsl-l) * 1%));
text-decoration: none;
transform: scale(0);
transition: transform var(--theme-transition-medium-ease) calc(var(--bookmark-link-delay) * 1s);
}
.bookmark-group-item:focus-within .bookmark-link,
.bookmark-group-active .bookmark-link {
transform: scale(1);
transition: transform var(--theme-transition-xslow-bounce) 0s;
}
.bookmark-group-item:focus-within .bookmark-link:hover,
.bookmark-group-item:focus-within .bookmark-link:focus,
.bookmark-group-active .bookmark-link:hover,
.bookmark-group-active .bookmark-link:focus {
transform: scale(1.4);
transition: transform var(--theme-transition-fast-bounce);
}
.bookmark-group-item:focus-within .bookmark-link:active,
.bookmark-group-active .bookmark-link:active {
transform: scale(1);
transition: transform var(--theme-transition-fast-bounce);
}
.bookmark-visual {
font-size: 2em;
min-width: 2em;
min-height: 2em;
display: flex;
align-items: center;
justify-content: center;
}
.bookmark-letter {
line-height: 1;
}
.bookmark-image {
max-height: 1em;
}

View File

@ -0,0 +1,73 @@
import { config } from '../../config';
import './index.css';
export const BookmarkLink = function(linkData, delay) {
this.node = {
link: document.createElement('a'),
visual: document.createElement('div'),
letter: document.createElement('div'),
icon: document.createElement('span'),
image: document.createElement('img')
}
this.render = () => {
this.node.link.classList.add('bookmark-link');
this.node.link.style.setProperty('--bookmark-link-delay', (delay / 20));
this.node.link.href = linkData.url;
if (config.bookmark.newTab) {
this.node.link.setAttribute('target', '_blank');
};
this.node.visual.classList.add('bookmark-visual');
this.node.letter.classList.add('bookmark-letter');
this.node.icon.classList.add('bookmark-icon');
this.node.image.classList.add('bookmark-image');
if ('letter' in linkData) {
this.node.letter.textContent = linkData.letter;
this.node.visual.appendChild(this.node.letter);
};
if ('icon' in linkData) {
const iconClassList = linkData.icon.split(' ');
iconClassList.forEach(className => {
this.node.icon.classList.add(className);
});
this.node.visual.appendChild(this.node.icon);
};
if ('image' in linkData) {
this.node.image.src = linkData.image;
this.node.visual.appendChild(this.node.image);
};
this.node.link.appendChild(this.node.visual);
}
this.link = () => this.node.link;
}

View File

@ -0,0 +1,36 @@
.bookmark-open-all {
background-color: transparent;
border: 0;
position: absolute;
top: 50%;
left: 50%;
font-size: 1.5em;
color: hsl(var(--bookmark-group-color-secondary-hsl-h),
calc(var(--bookmark-group-color-secondary-hsl-s) * 1%),
calc(var(--bookmark-group-color-secondary-hsl-l) * 1%));
cursor: pointer;
transform-origin: center;
transform: translate(-50%, -50%) scale(0);
transition: color var(--theme-transition-xfast-ease), transform var(--theme-transition-fast-ease) calc(var(--theme-transition-speed-fast) * 1s);
}
.bookmark-group-item:focus-within .bookmark-open-all,
.bookmark-group-active .bookmark-open-all {
transform: translate(-50%, -50%) scale(1);
transition: color var(--theme-transition-xfast-ease), transform var(--theme-transition-xslow-bounce) 0s;
}
.bookmark-group-item:focus-within .bookmark-open-all:hover,
.bookmark-group-item:focus-within .bookmark-open-all:focus,
.bookmark-group-active .bookmark-open-all:hover,
.bookmark-group-active .bookmark-open-all:focus {
outline: none;
transform: translate(-50%, -50%) scale(1.4);
transition: transform var(--theme-transition-fast-bounce);
}
.bookmark-group-item:focus-within .bookmark-open-all:active,
.bookmark-group-active .bookmark-open-all:active {
transform: translate(-50%, -50%) scale(1);
transition: transform var(--theme-transition-fast-bounce);
}

View File

@ -0,0 +1,58 @@
import { config } from '../../config';
import './index.css';
export const BookmarkOpenAll = function(bookmarkGroupData) {
this.node = {
button: document.createElement('button'),
icon: document.createElement('span')
}
this.open = () => {
if ('tabs' in chrome) {
if (config.bookmark.newTab) {
bookmarkGroupData.list.forEach(item => {
chrome.tabs.create({ url: item.url, active: false });
});
} else {
const first = bookmarkGroupData.list.shift();
bookmarkGroupData.list.forEach(item => {
chrome.tabs.create({ url: item.url, active: false });
});
window.location.href = first.url;
}
}
}
this.render = () => {
this.node.button.classList.add('bookmark-open-all');
this.node.button.addEventListener('click', () => {
this.open();
});
this.node.icon.classList.add('fa-bolt');
this.node.icon.classList.add('fa-solid');
this.node.button.appendChild(this.node.icon);
}
this.button = () => this.node.button;
}

View File

@ -0,0 +1,26 @@
:root {
--theme-accent:
hsl(var(--theme-accent-hsl-h),
calc(var(--theme-accent-hsl-s) * 1%),
calc(var(--theme-accent-hsl-l) * 1%));
--theme-text:
hsl(var(--theme-text-hsl-h),
calc(var(--theme-text-hsl-s) * 1%),
calc(var(--theme-text-hsl-l) * 1%));
}
:root {
--theme-transition-xfast-bounce: calc(var(--theme-transition-speed-xfast) * 1s) cubic-bezier(var(--theme-easing-bounce));
--theme-transition-fast-bounce: calc(var(--theme-transition-speed-fast) * 1s) cubic-bezier(var(--theme-easing-bounce));
--theme-transition-medium-bounce: calc(var(--theme-transition-speed-medium) * 1s) cubic-bezier(var(--theme-easing-bounce));
--theme-transition-slow-bounce: calc(var(--theme-transition-speed-slow) * 1s) cubic-bezier(var(--theme-easing-bounce));
--theme-transition-xslow-bounce: calc(var(--theme-transition-speed-xslow) * 1s) cubic-bezier(var(--theme-easing-bounce));
}
:root {
--theme-transition-xfast-ease: calc(var(--theme-transition-speed-xfast) * 1s) ease-in-out;
--theme-transition-fast-ease: calc(var(--theme-transition-speed-fast) * 1s) ease-in-out;
--theme-transition-medium-ease: calc(var(--theme-transition-speed-medium) * 1s) ease-in-out;
--theme-transition-slow-ease: calc(var(--theme-transition-speed-slow) * 1s) ease-in-out;
--theme-transition-xslow-ease: calc(var(--theme-transition-speed-xslow) * 1s) ease-in-out;
}

View File

@ -0,0 +1,58 @@
import { config } from '../../config';
import { applyCSSVar } from '../utility/applyCSSVar';
import { trimString } from '../utility/trimString';
import WebFont from 'webfontloader';
import './index.css';
export const Theme = function() {
this.node = {
html: document.querySelector('html')
}
this.style = () => {
applyCSSVar('--theme-scale', config.theme.scale);
applyCSSVar('--theme-scale', config.theme.scale);
applyCSSVar('--theme-text-hsl-h', config.theme.text.hsl[0]);
applyCSSVar('--theme-text-hsl-s', config.theme.text.hsl[1]);
applyCSSVar('--theme-text-hsl-l', config.theme.text.hsl[2]);
applyCSSVar('--theme-accent-hsl-h', config.theme.accent.hsl[0]);
applyCSSVar('--theme-accent-hsl-s', config.theme.accent.hsl[1]);
applyCSSVar('--theme-accent-hsl-l', config.theme.accent.hsl[2]);
applyCSSVar('--theme-transition-speed-xfast', (config.theme.transition.speed.xfast / 100));
applyCSSVar('--theme-transition-speed-fast', (config.theme.transition.speed.fast / 100));
applyCSSVar('--theme-transition-speed-medium', (config.theme.transition.speed.medium / 100));
applyCSSVar('--theme-transition-speed-slow', (config.theme.transition.speed.slow / 100));
applyCSSVar('--theme-transition-speed-xslow', (config.theme.transition.speed.xslow / 100));
applyCSSVar('--theme-easing-bounce', `${config.theme.easing.bounce[0]}, ${config.theme.easing.bounce[1]}, ${config.theme.easing.bounce[2]}, ${config.theme.easing.bounce[3]}`);
applyCSSVar('--theme-font', config.theme.font);
applyCSSVar('--theme-bookmark-background-color-hsla-h', config.theme.bookmark.background.color.hsla[0]);
applyCSSVar('--theme-bookmark-background-color-hsla-s', config.theme.bookmark.background.color.hsla[1]);
applyCSSVar('--theme-bookmark-background-color-hsla-l', config.theme.bookmark.background.color.hsla[2]);
applyCSSVar('--theme-bookmark-background-color-hsla-a', config.theme.bookmark.background.color.hsla[3]);
applyCSSVar('--theme-bookmark-group-background-blur', config.theme.bookmark.background.blur);
}
this.render = () => {
this.style();
WebFont.load({
// fontloading: (familyName, fvd) => { console.log('fontloading:', familyName); },
google: { families: [trimString(config.theme.font) + ':100,100i,200,200i,300,300i,400,400i,500,500i,600,600i,700,700i,800,800i,900,900i'] }
});
}
}

7825
src/component/fontawesome/index.css vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
import './index.css';
export const Fontawesome = function() {}

View File

@ -0,0 +1,7 @@
export const applyCSSVar = (name, value) => {
const html = document.querySelector('html');
html.style.setProperty(name, value);
};

View File

@ -0,0 +1,9 @@
export const averageColor = function(rgb1, rgb2) {
return {
r: Math.round(Math.sqrt(Math.pow(rgb1.r, 1.75) + Math.pow(rgb2.r, 1.75) / 2)),
g: Math.round(Math.sqrt(Math.pow(rgb1.g, 1.75) + Math.pow(rgb2.g, 1.75) / 2)),
b: Math.round(Math.sqrt(Math.pow(rgb1.b, 1.75) + Math.pow(rgb2.b, 1.75) / 2))
};
};

View File

@ -0,0 +1,7 @@
export const clearChildNode = (element) => {
while (element.lastChild) {
element.removeChild(element.lastChild);
}
};

View File

@ -0,0 +1,61 @@
export const complexNode = ({
tag = 'div',
text = false,
complexText = false,
attr = [],
node = []
} = {}) => {
const element = document.createElement(tag);
if (text) {
if (complexText) {
element.innerHTML = text;
} else {
let textNode = document.createTextNode(text);
element.appendChild(textNode);
}
}
if (attr.length > 0) {
attr.forEach((item) => {
if ('key' in item && 'value' in item) {
element.setAttribute(item.key, item.value);
} else if ('key' in item) {
element.setAttribute(item.key, '');
}
});
}
if (node) {
if (typeof node != 'string') {
if (node.length > 0) {
node.forEach((item) => {
if (item instanceof HTMLElement) {
element.appendChild(item);
}
});
} else {
if (node instanceof HTMLElement) {
element.appendChild(node);
}
}
}
}
return element;
};

View File

@ -0,0 +1,147 @@
export const convertColor = {
rgb: {},
hsl: {},
hex: {}
};
convertColor.rgb.hsl = (rgb) => {
var r = rgb.r / 255;
var g = rgb.g / 255;
var b = rgb.b / 255;
var min = Math.min(r, g, b);
var max = Math.max(r, g, b);
var delta = max - min;
var h;
var s;
if (max === min) {
h = 0;
} else if (r === max) {
h = (g - b) / delta;
} else if (g === max) {
h = 2 + (b - r) / delta;
} else if (b === max) {
h = 4 + (r - g) / delta;
}
h = Math.min(h * 60, 360);
if (h < 0) {
h += 360;
}
var l = (min + max) / 2;
if (max === min) {
s = 0;
} else if (l <= 0.5) {
s = delta / (max + min);
} else {
s = delta / (2 - max - min);
}
return {
h: Math.round(h),
s: Math.round(s * 100),
l: Math.round(l * 100)
};
};
convertColor.rgb.hex = (args) => {
var integer = ((Math.round(args.r) & 0xFF) << 16) +
((Math.round(args.g) & 0xFF) << 8) +
(Math.round(args.b) & 0xFF);
var string = integer.toString(16);
return '#' + '000000'.substring(string.length) + string;
};
convertColor.hsl.rgb = (hsl) => {
var h = hsl.h / 360;
var s = hsl.s / 100;
var l = hsl.l / 100;
var t2;
var t3;
var val;
if (s === 0) {
val = l * 255;
return {
r: Math.round(val),
g: Math.round(val),
b: Math.round(val)
};
}
if (l < 0.5) {
t2 = l * (1 + s);
} else {
t2 = l + s - l * s;
}
var t1 = 2 * l - t2;
var rgb = [0, 0, 0];
for (var i = 0; i < 3; i++) {
t3 = h + 1 / 3 * -(i - 1);
if (t3 < 0) {
t3++;
}
if (t3 > 1) {
t3--;
}
if (6 * t3 < 1) {
val = t1 + (t2 - t1) * 6 * t3;
} else if (2 * t3 < 1) {
val = t2;
} else if (3 * t3 < 2) {
val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
} else {
val = t1;
}
rgb[i] = val * 255;
}
return {
r: Math.round(rgb[0]),
g: Math.round(rgb[1]),
b: Math.round(rgb[2])
};
};
convertColor.hex.rgb = (args) => {
var match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);
if (!match) {
return {
r: 0,
g: 0,
b: 0
};
}
var colorString = match[0];
if (match[0].length === 3) {
colorString = colorString.split('').map((char) => {
return char + char;
}).join('');
}
var integer = parseInt(colorString, 16);
var r = (integer >> 16) & 0xFF;
var g = (integer >> 8) & 0xFF;
var b = integer & 0xFF;
return {
r: r,
g: g,
b: b
};
};

View File

@ -0,0 +1,21 @@
export const dateTime = () => {
const date = new Date();
const month = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
return {
// string: date.constructor(),
// time: date.getTime(),
date: date.getDate(),
day: date.getDay(),
year: date.getFullYear(),
hours: date.getHours(),
milliseconds: date.getMilliseconds(),
minutes: date.getMinutes(),
month: date.getMonth(),
monthString: month[date.getMonth()],
seconds: date.getSeconds()
};
};

View File

@ -0,0 +1,48 @@
import { makePath } from './makePath.js';
export const get = ({
object = null,
path = null
} = {}) => {
const address = makePath(path);
const getValue = () => {
while (address.length > 1) {
// shift off and store the first key
let currentKey = address.shift();
// if the key is not found make a new object
if (!(currentKey in object)) {
// make an empty object in the current object level
if (isNaN(currentKey)) {
object[currentKey] = {};
} else {
object[currentKey] = [];
}
}
// drill down the object with the first key
object = object[currentKey];
}
let finalKey = address.shift();
if (!(finalKey in object)) {
return '';
} else {
return object[finalKey];
}
};
if (object != null && path != null) {
return getValue();
} else {
return false;
}
};

View File

@ -0,0 +1,31 @@
export const isElementVisible = (element) => {
var rect = element.getBoundingClientRect();
const vWidth = window.innerWidth;
const vHeight = window.innerHeight;
const efp = (x, y) => {
return document.elementFromPoint(x, y);
};
// Return false if element is not in the viewport
if (
rect.right < 0 ||
rect.bottom < 0 ||
rect.left > vWidth ||
rect.top > vHeight
) {
return false;
}
// Return true if any of the element four corners are visible
return (
element.contains(efp(rect.left, rect.top)) ||
element.contains(efp(rect.right, rect.top)) ||
element.contains(efp(rect.right, rect.bottom)) ||
element.contains(efp(rect.left, rect.bottom))
);
};

View File

@ -0,0 +1,11 @@
export const isJson = (string) => {
try {
JSON.parse(string);
} catch (error) {
return false;
}
return true;
};

View File

@ -0,0 +1,12 @@
export const isValidString = (value) => {
let result = false;
if (typeof value == 'string') {
value = value.trim().replace(/\s/g, '');
if (value != '') {
result = true;
}
}
return result;
};

View File

@ -0,0 +1,34 @@
export const makePath = (string) => {
if (string) {
let array;
if (string.indexOf('[') != -1 && string.indexOf(']') != -1) {
array = string.split('.').join(',').split('[').join(',').split(']').join(',').split(',');
for (var i = 0; i < array.length; i++) {
if (array[i] == '') {
array.splice(i, 1);
}
if (!isNaN(parseInt(array[i], 10))) {
array[i] = parseInt(array[i], 10);
}
}
} else {
array = string.split('.');
}
return array;
} else {
return false;
}
};

View File

@ -0,0 +1,25 @@
export const minMax = ({
min = 0,
max = 0,
value = 0
} = {}) => {
if (value > max) {
return max;
} else if (value < min) {
return min;
} else if (isNaN(value)) {
return min;
} else {
return value;
}
};

View File

@ -0,0 +1,110 @@
export const node = (string, node) => {
// set element
let tag;
if (string.indexOf('|') > 0) {
tag = string.slice(0, string.indexOf('|'));
} else {
tag = string;
}
let text = false;
if (tag.indexOf(':') > 0) {
// regex
// find all : and split
// ignore all \:
let pair = tag.split(/:(?!.*:\\)/);
tag = pair[0];
// replace \: with :
text = pair[1].replace('\\', ':');
}
let element = document.createElement(tag);
if (text && text != '') {
element.innerHTML = text;
}
let attributes = string.slice(string.indexOf('|') + 1, string.length).split(',');
// set attributes
if (string.indexOf('|') > 0 && string.indexOf('|') < string.length - 1) {
attributes.forEach((item, i) => {
if (item.indexOf(':') > 0) {
// if key and value
var pair = item.substring(0, item.indexOf(':')) + ',' + item.substring(item.indexOf(':') + 1, item.length);
pair = pair.split(',');
attributes[i] = {
key: pair[0],
value: pair[1]
};
} else {
// if key only
attributes[i] = {
key: item,
value: undefined
};
}
});
attributes.forEach((item) => {
if ('key' in item && item.key != undefined && 'value' in item && item.value != undefined) {
element.setAttribute(item.key, item.value);
} else if ('key' in item && item.key != undefined) {
element.setAttribute(item.key, '');
}
});
}
if (node) {
if (typeof node != 'string') {
if (node.length > 0) {
node.forEach((item) => {
if (item instanceof HTMLElement) {
element.appendChild(item);
} else {
let div = document.createElement('div');
div.innerHTML = item;
element.appendChild(div.firstChild);
}
});
} else {
if (node instanceof HTMLElement) {
element.appendChild(node);
} else {
let div = document.createElement('div');
div.innerHTML = node;
element.appendChild(div.firstChild);
}
}
}
}
return element;
};

View File

@ -0,0 +1,21 @@
export const ordinalNumber = (number) => {
var j = number % 10;
var k = number % 100;
if (j == 1 && k != 11) {
return number + 'st';
}
if (j == 2 && k != 12) {
return number + 'nd';
}
if (j == 3 && k != 13) {
return number + 'rd';
}
return number + 'th';
};

View File

@ -0,0 +1,44 @@
export const ordinalWord = (word) => {
const endsWithDoubleZeroPattern = /(hundred|thousand|(m|b|tr|quadr)illion)$/;
const endsWithTeenPattern = /teen$/;
const endsWithYPattern = /y$/;
const endsWithZeroThroughTwelvePattern = /(Zero|One|Two|Three|Four|Five|Six|Seven|Eight|Nine|Ten|Eleven|Twelve)$/;
const ordinalLessThanThirteen = {
Zero: 'Zeroth',
One: 'First',
Two: 'Second',
Three: 'Third',
Four: 'Fourth',
Five: 'Fifth',
Six: 'Sixth',
Seven: 'Seventh',
Eight: 'Eighth',
Nine: 'Ninth',
Ten: 'Tenth',
Eleven: 'Eleventh',
Twelve: 'Twelfth'
};
const replaceWithOrdinalVariant = (match, numberWord) => {
return ordinalLessThanThirteen[numberWord];
};
// Ends with *00 (100, 1000, etc.) or *teen (13, 14, 15, 16, 17, 18, 19)
if (endsWithDoubleZeroPattern.test(word) || endsWithTeenPattern.test(word)) {
return word + 'th';
// Ends with *y (20, 30, 40, 50, 60, 70, 80, 90)
} else if (endsWithYPattern.test(word)) {
return word.replace(endsWithYPattern, 'ieth');
// Ends with one through twelve
} else if (endsWithZeroThroughTwelvePattern.test(word)) {
return word.replace(endsWithZeroThroughTwelvePattern, replaceWithOrdinalVariant);
}
return word;
};

View File

@ -0,0 +1,5 @@
export const randomNumber = (min, max) => {
return Math.floor(Math.random() * (max - min + 1) + min);
};

View File

@ -0,0 +1,162 @@
export const randomString = ({
letter = false,
adjectivesCount = false
} = {}) => {
const alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
const adjectives = {
a: ['Aback', 'Abaft', 'Abandoned', 'Abashed', 'Aberrant', 'Abhorrent', 'Abiding', 'Abject', 'Ablaze', 'Able', 'Abnormal', 'Aboriginal', 'Abortive', 'Abounding', 'Abrasive', 'Abrupt', 'Absent', 'Absorbed', 'Absorbing', 'Abstracted', 'Absurd', 'Abundant', 'Abusive', 'Acceptable', 'Accessible', 'Accidental', 'Accurate', 'Acid', 'Acidic', 'Acoustic', 'Acrid', 'Adamant', 'Adaptable', 'Adhesive', 'Adjoining', 'Adorable', 'Adventurous', 'Afraid', 'Aggressive', 'Agonizing', 'Agreeable', 'Ahead', 'Ajar', 'Alert', 'Alike', 'Alive', 'Alleged', 'Alluring', 'Aloof', 'Amazing', 'Ambiguous', 'Ambitious', 'Amuck', 'Amused', 'Amusing', 'Ancient', 'Angry', 'Animated', 'Annoyed', 'Annoying', 'Anxious', 'Apathetic', 'Aquatic', 'Aromatic', 'Arrogant', 'Ashamed', 'Aspiring', 'Assorted', 'Astonishing', 'Attractive', 'Auspicious', 'Automatic', 'Available', 'Average', 'Aware', 'Awesome', 'Axiomatic'],
b: ['Bad', 'Barbarous', 'Bashful', 'Bawdy', 'Beautiful', 'Befitting', 'Belligerent', 'Beneficial', 'Bent', 'Berserk', 'Bewildered', 'Big', 'Billowy', 'Bitter', 'Bizarre', 'Black', 'Bloody', 'Blue', 'Blushing', 'Boiling', 'Boorish', 'Bored', 'Boring', 'Bouncy', 'Boundless', 'Brainy', 'Brash', 'Brave', 'Brawny', 'Breakable', 'Breezy', 'Brief', 'Bright', 'Broad', 'Broken', 'Brown', 'Bumpy', 'Burly', 'Bustling', 'Busy'],
c: ['Cagey', 'Calculating', 'Callous', 'Calm', 'Capable', 'Capricious', 'Careful', 'Careless', 'Caring', 'Cautious', 'Ceaseless', 'Certain', 'Changeable', 'Charming', 'Cheap', 'Cheerful', 'Chemical', 'Chief', 'Childlike', 'Chilly', 'Chivalrous', 'Chubby', 'Chunky', 'Clammy', 'Classy', 'Clean', 'Clear', 'Clever', 'Cloistered', 'Cloudy', 'Closed', 'Clumsy', 'Cluttered', 'Coherent', 'Cold', 'Colorful', 'Colossal', 'Combative', 'Comfortable', 'Common', 'Complete', 'Complex', 'Concerned', 'Condemned', 'Confused', 'Conscious', 'Cooing', 'Cool', 'Cooperative', 'Coordinated', 'Courageous', 'Cowardly', 'Crabby', 'Craven', 'Crazy', 'Creepy', 'Crooked', 'Crowded', 'Cruel', 'Cuddly', 'Cultured', 'Cumbersome', 'Curious', 'Curly', 'Curved', 'Curvy', 'Cut', 'Cute', 'Cynical'],
d: ['Daffy', 'Daily', 'Damaged', 'Damaging', 'Damp', 'Dangerous', 'Dapper', 'Dark', 'Dashing', 'Dazzling', 'Deadpan', 'Deafening', 'Dear', 'Debonair', 'Decisive', 'Decorous', 'Deep', 'Deeply', 'Defeated', 'Defective', 'Defiant', 'Delicate', 'Delicious', 'Delightful', 'Demonic', 'Delirious', 'Dependent', 'Depressed', 'Deranged', 'Descriptive', 'Deserted', 'Detailed', 'Determined', 'Devilish', 'Didactic', 'Different', 'Difficult', 'Diligent', 'Direful', 'Dirty', 'Disagreeable', 'Disastrous', 'Discreet', 'Disgusted', 'Disgusting', 'Disillusioned', 'Dispensable', 'Distinct', 'Disturbed', 'Divergent', 'Dizzy', 'Domineering', 'Doubtful', 'Drab', 'Draconian', 'Dramatic', 'Dreary', 'Drunk', 'Dry', 'Dull', 'Dusty', 'Dynamic', 'Dysfunctional'],
e: ['Eager', 'Early', 'Earsplitting', 'Earthy', 'Easy', 'Eatable', 'Economic', 'Educated', 'Efficacious', 'Efficient', 'Elastic', 'Elated', 'Elderly', 'Electric', 'Elegant', 'Elfin', 'Elite', 'Embarrassed', 'Eminent', 'Empty', 'Enchanted', 'Enchanting', 'Encouraging', 'Endurable', 'Energetic', 'Enormous', 'Entertaining', 'Enthusiastic', 'Envious', 'Equable', 'Equal', 'Erratic', 'Ethereal', 'Evanescent', 'Evasive', 'Even', 'Excellent', 'Excited', 'Exciting', 'Exclusive', 'Exotic', 'Expensive', 'Exuberant', 'Exultant'],
f: ['Fabulous', 'Faded', 'Faint', 'Fair', 'Faithful', 'Fallacious', 'False', 'Familiar', 'Famous', 'Fanatical', 'Fancy', 'Fantastic', 'Far', 'Fascinated', 'Fast', 'Fat', 'Faulty', 'Fearful', 'Fearless', 'Feeble', 'Feigned', 'Fertile', 'Festive', 'Few', 'Fierce', 'Filthy', 'Fine', 'Finicky', 'First', 'Fixed', 'Flagrant', 'Flaky', 'Flashy', 'Flat', 'Flawless', 'Flimsy', 'Flippant', 'Flowery', 'Fluffy', 'Fluttering', 'Foamy', 'Foolish', 'Foregoing', 'Forgetful', 'Fortunate', 'Frail', 'Fragile', 'Frantic', 'Free', 'Freezing', 'Frequent', 'Fresh', 'Fretful', 'Friendly', 'Frightened', 'Frightening', 'Full', 'Fumbling', 'Functional', 'Funny', 'Furry', 'Furtive', 'Future', 'Futuristic', 'Fuzzy'],
g: ['Gabby', 'Gainful', 'Gamy', 'Garrulous', 'Gaudy', 'General', 'Gentle', 'Giant', 'Giddy', 'Gifted', 'Gigantic', 'Glamorous', 'Gleaming', 'Glib', 'Glistening', 'Glorious', 'Glossy', 'Good', 'Goofy', 'Gorgeous', 'Graceful', 'Grandiose', 'Grateful', 'Gratis', 'Gray', 'Greasy', 'Great', 'Greedy', 'Green', 'Grey', 'Grieving', 'Groovy', 'Grotesque', 'Grouchy', 'Grubby', 'Gruesome', 'Grumpy', 'Guarded', 'Guiltless', 'Gullible', 'Gusty', 'Guttural'],
h: ['Habitual', 'Half', 'Hallowed', 'Halting', 'Handsome', 'Handy', 'Hapless', 'Happy', 'Hard', 'Harmonious', 'Harsh', 'Hateful', 'Heady', 'Healthy', 'Heartbreaking', 'Heavenly', 'Heavy', 'Hellish', 'Helpful', 'Helpless', 'Hesitant', 'Hideous', 'High', 'Highfalutin', 'Hilarious', 'Hissing', 'Historical', 'Holistic', 'Hollow', 'Homeless', 'Homely', 'Honorable', 'Horrible', 'Hospitable', 'Hot', 'Huge', 'Hulking', 'Humdrum', 'Humorous', 'Hungry', 'Hurried', 'Hurt', 'Hushed', 'Husky', 'Hypnotic', 'Hysterical'],
i: ['Icky', 'Icy', 'Idiotic', 'Ignorant', 'Ill', 'Illegal', 'Illustrious', 'Imaginary', 'Immense', 'Imminent', 'Impartial', 'Imperfect', 'Impolite', 'Important', 'Imported', 'Impossible', 'Incandescent', 'Incompetent', 'Inconclusive', 'Industrious', 'Incredible', 'Inexpensive', 'Infamous', 'Innate', 'Innocent', 'Inquisitive', 'Insidious', 'Instinctive', 'Intelligent', 'Interesting', 'Internal', 'Invincible', 'Irate', 'Irritating', 'Itchy'],
j: ['Jaded', 'Jagged', 'Jazzy', 'Jealous', 'Jesting', 'Jinxed', 'Jittery', 'Jobless', 'Jolly', 'Joyous', 'Judicious', 'Juicy', 'Jumbled', 'Jumpy', 'Juvenile'],
k: ['Keen', 'Kind', 'Kindhearted', 'Kindly', 'Knotty', 'Knowing', 'Knowledgeable', 'Known'],
l: ['Labored', 'Lackadaisical', 'Lacking', 'Lame', 'Lamentable', 'Languid', 'Large', 'Last', 'Late', 'Laughable', 'Lavish', 'Lazy', 'Lean', 'Learned', 'Left', 'Legal', 'Lethal', 'Level', 'Lewd', 'Light', 'Like', 'Likeable', 'Limping', 'Literate', 'Little', 'Lively', 'Living', 'Lonely', 'Long', 'Longing', 'Loose', 'Lopsided', 'Loud', 'Loutish', 'Lovely', 'Loving', 'Low', 'Lowly', 'Lucky', 'Ludicrous', 'Lumpy', 'Lush', 'Luxuriant', 'Lying', 'Lyrical'],
m: ['Macabre', 'Macho', 'Maddening', 'Madly', 'Magenta', 'Magical', 'Magnificent', 'Majestic', 'Makeshift', 'Malicious', 'Mammoth', 'Maniacal', 'Many', 'Marked', 'Massive', 'Married', 'Marvelous', 'Material', 'Materialistic', 'Mature', 'Mean', 'Measly', 'Meaty', 'Medical', 'Meek', 'Mellow', 'Melodic', 'Melted', 'Merciful', 'Mere', 'Messy', 'Mighty', 'Military', 'Milky', 'Mindless', 'Miniature', 'Minor', 'Miscreant', 'Misty', 'Mixed', 'Moaning', 'Modern', 'Moldy', 'Momentous', 'Motionless', 'Mountainous', 'Muddled', 'Mundane', 'Murky', 'Mushy', 'Mute', 'Mysterious'],
n: ['Naive', 'Nappy', 'Narrow', 'Nasty', 'Natural', 'Naughty', 'Nauseating', 'Near', 'Neat', 'Nebulous', 'Necessary', 'Needless', 'Needy', 'Neighborly', 'Nervous', 'New', 'Next', 'Nice', 'Nifty', 'Nimble', 'Nippy', 'Noiseless', 'Noisy', 'Nonchalant', 'Nondescript', 'Nonstop', 'Normal', 'Nostalgic', 'Nosy', 'Noxious', 'Numberless', 'Numerous', 'Nutritious', 'Nutty'],
o: ['Oafish', 'Obedient', 'Obeisant', 'Obese', 'Obnoxious', 'Obscene', 'Obsequious', 'Observant', 'Obsolete', 'Obtainable', 'Oceanic', 'Odd', 'Offbeat', 'Old', 'Omniscient', 'Onerous', 'Open', 'Opposite', 'Optimal', 'Orange', 'Ordinary', 'Organic', 'Ossified', 'Outgoing', 'Outrageous', 'Outstanding', 'Oval', 'Overconfident', 'Overjoyed', 'Overrated', 'Overt', 'Overwrought'],
p: ['Painful', 'Painstaking', 'Pale', 'Paltry', 'Panicky', 'Panoramic', 'Parallel', 'Parched', 'Parsimonious', 'Past', 'Pastoral', 'Pathetic', 'Peaceful', 'Penitent', 'Perfect', 'Periodic', 'Permissible', 'Perpetual', 'Petite', 'Phobic', 'Physical', 'Picayune', 'Pink', 'Piquant', 'Placid', 'Plain', 'Plant', 'Plastic', 'Plausible', 'Pleasant', 'Plucky', 'Pointless', 'Poised', 'Polite', 'Political', 'Poor', 'Possessive', 'Possible', 'Powerful', 'Precious', 'Premium', 'Present', 'Pretty', 'Previous', 'Pricey', 'Prickly', 'Private', 'Probable', 'Productive', 'Profuse', 'Protective', 'Proud', 'Psychedelic', 'Psychotic', 'Public', 'Puffy', 'Pumped', 'Puny', 'Purple', 'Purring', 'Pushy', 'Puzzled', 'Puzzling'],
q: ['Quaint', 'Quality', 'Quarrelsome', 'Questionable', 'Questioning', 'Quick', 'Quiet', 'Quirky', 'Quixotic', 'Quizzical'],
r: ['Rabid', 'Ragged', 'Rainy', 'Rambunctious', 'Rampant', 'Rapid', 'Rare', 'Raspy', 'Ratty', 'Ready', 'Real', 'Rebel', 'Receptive', 'Recondite', 'Red', 'Redundant', 'Reflective', 'Regular', 'Relieved', 'Remarkable', 'Reminiscent', 'Repulsive', 'Resolute', 'Resonant', 'Responsible', 'Rhetorical', 'Rich', 'Right', 'Righteous', 'Rightful', 'Rigid', 'Ripe', 'Ritzy', 'Roasted', 'Robust', 'Romantic', 'Roomy', 'Rotten', 'Rough', 'Round', 'Royal', 'Ruddy', 'Rude', 'Rural', 'Rustic', 'Ruthless'],
s: ['Sable', 'Sad', 'Safe', 'Salty', 'Same', 'Sassy', 'Satisfying', 'Savory', 'Scandalous', 'Scarce', 'Scared', 'Scary', 'Scattered', 'Scientific', 'Scintillating', 'Scrawny', 'Screeching', 'Second', 'Secret', 'Secretive', 'Sedate', 'Seemly', 'Selective', 'Selfish', 'Separate', 'Serious', 'Shaggy', 'Shaky', 'Shallow', 'Sharp', 'Shiny', 'Shivering', 'Shocking', 'Short', 'Shrill', 'Shut', 'Shy', 'Sick', 'Silent', 'Silky', 'Silly', 'Simple', 'Simplistic', 'Sincere', 'Skillful', 'Skinny', 'Sleepy', 'Slim', 'Slimy', 'Slippery', 'Sloppy', 'Slow', 'Small', 'Smart', 'Smelly', 'Smiling', 'Smoggy', 'Smooth', 'Sneaky', 'Snobbish', 'Snotty', 'Soft', 'Soggy', 'Solid', 'Somber', 'Sophisticated', 'Sordid', 'Sore', 'Sour', 'Sparkling', 'Special', 'Spectacular', 'Spicy', 'Spiffy', 'Spiky', 'Spiritual', 'Spiteful', 'Splendid', 'Spooky', 'Spotless', 'Spotted', 'Spotty', 'Spurious', 'Squalid', 'Square', 'Squealing', 'Squeamish', 'Staking', 'Stale', 'Standing', 'Statuesque', 'Steadfast', 'Steady', 'Steep', 'Stereotyped', 'Sticky', 'Stiff', 'Stimulating', 'Stingy', 'Stormy', 'Straight', 'Strange', 'Striped', 'Strong', 'Stupendous', 'Sturdy', 'Subdued', 'Subsequent', 'Substantial', 'Successful', 'Succinct', 'Sudden', 'Sulky', 'Super', 'Superb', 'Superficial', 'Supreme', 'Swanky', 'Sweet', 'Sweltering', 'Swift', 'Symptomatic', 'Synonymous'],
t: ['Taboo', 'Tacit', 'Tacky', 'Talented', 'Tall', 'Tame', 'Tan', 'Tangible', 'Tangy', 'Tart', 'Tasteful', 'Tasteless', 'Tasty', 'Tawdry', 'Tearful', 'Tedious', 'Teeny', 'Telling', 'Temporary', 'Ten', 'Tender', 'Tense', 'Tenuous', 'Terrific', 'Tested', 'Testy', 'Thankful', 'Therapeutic', 'Thick', 'Thin', 'Thinkable', 'Third', 'Thirsty', 'Thoughtful', 'Thoughtless', 'Threatening', 'Thundering', 'Tidy', 'Tight', 'Tightfisted', 'Tiny', 'Tired', 'Tiresome', 'Toothsome', 'Torpid', 'Tough', 'Towering', 'Tranquil', 'Trashy', 'Tremendous', 'Tricky', 'Trite', 'Troubled', 'Truculent', 'True', 'Truthful', 'Typical'],
u: ['Ubiquitous', 'Ultra', 'Unable', 'Unaccountable', 'Unadvised', 'Unarmed', 'Unbecoming', 'Unbiased', 'Uncovered', 'Understood', 'Undesirable', 'Unequal', 'Unequaled', 'Uneven', 'Unhealthy', 'Uninterested', 'Unique', 'Unkempt', 'Unknown', 'Unnatural', 'Unruly', 'Unsightly', 'Unsuitable', 'Untidy', 'Unused', 'Unusual', 'Unwieldy', 'Unwritten', 'Upbeat', 'Uppity', 'Upset', 'Uptight', 'Used', 'Useful', 'Useless', 'Utopian'],
v: ['Vacuous', 'Vagabond', 'Vague', 'Valuable', 'Various', 'Vast', 'Vengeful', 'Venomous', 'Verdant', 'Versed', 'Victorious', 'Vigorous', 'Violent', 'Violet', 'Vivacious', 'Voiceless', 'Volatile', 'Voracious', 'Vulgar'],
w: ['Wacky', 'Waggish', 'Waiting', 'Wakeful', 'Wandering', 'Wanting', 'Warlike', 'Warm', 'Wary', 'Wasteful', 'Watery', 'Weak', 'Wealthy', 'Weary', 'Wet', 'Whimsical', 'Whispering', 'White', 'Whole', 'Wholesale', 'Wicked', 'Wide', 'Wiggly', 'Wild', 'Willing', 'Windy', 'Wiry', 'Wise', 'Wistful', 'Witty', 'Woebegone', 'Wonderful', 'Wooden', 'Woozy', 'Workable', 'Worried', 'Worthless', 'Wrathful', 'Wretched', 'Wrong', 'Wry'],
x: ['Xenial', 'Xenodochial', 'Xenophobic'],
y: ['Yellow', 'Yielding', 'Young', 'Youthful', 'Yummy'],
z: ['Zany', 'Zealous', 'Zesty', 'Zippy', 'Zombiesque', 'Zombie', 'Zonked']
};
const animals = {
a: ['Aardvark', 'Albatross', 'Alligator', 'Alpaca', 'Ant', 'Anteater', 'Antelope', 'Ape', 'Armadillo'],
b: ['Baboon', 'Badger', 'Barracuda', 'Bat', 'Bear', 'Beaver', 'Bee', 'Bison', 'Boar', 'Buffalo', 'Butterfly'],
c: ['Camel', 'Capybara', 'Caribou', 'Cassowary', 'Cat', 'Caterpillar', 'Cattle', 'Chamois', 'Cheetah', 'Chicken', 'Chimpanzee', 'Chinchilla', 'Chough', 'Clam', 'Cobra', 'Cockroach', 'Cod', 'Cormorant', 'Coyote', 'Crab', 'Crane', 'Crocodile', 'Crow', 'Curlew'],
d: ['Deer', 'Dinosaur', 'Dog', 'Dogfish', 'Dolphin', 'Donkey', 'Dotterel', 'Dove', 'Dragonfly', 'Duck', 'Dugong', 'Dunlin'],
e: ['Eagle', 'Echidna', 'Eel', 'Eland', 'Elephant', 'Elephant Seal', 'Elk', 'Emu'],
f: ['Falcon', 'Ferret', 'Finch', 'Fish', 'Flamingo', 'Fly', 'Fox', 'Frog'],
g: ['Gaur', 'Gazelle', 'Gerbil', 'Giant Panda', 'Giraffe', 'Gnat', 'Gnu', 'Goat', 'Goose', 'Goldfinch', 'Goldfish', 'Gorilla', 'Goshawk', 'Grasshopper', 'Grouse', 'Guanaco', 'Guinea Fowl', 'Guinea Pig', 'Gull'],
h: ['Hamster', 'Hare', 'Hawk', 'Hedgehog', 'Heron', 'Herring', 'Hippopotamus', 'Hornet', 'Horse', 'Human', 'Hummingbird', 'Hyena'],
i: ['Ibex', 'Ibis', 'Iguana', 'Impala', 'Isopod'],
j: ['Jackal', 'Jaguar', 'Jay', 'Jellyfish'],
k: ['Kangaroo', 'Kingfisher', 'Koala', 'Komodo Dragon', 'Kookabura', 'Kouprey', 'Kudu'],
l: ['Lapwing', 'Lark', 'Lemur', 'Leopard', 'Lima', 'Lion', 'Llama', 'Lobster', 'Locust', 'Loris', 'Louse', 'Lyrebird'],
m: ['Magpie', 'Mallard', 'Manatee', 'Mandrill', 'Mantis', 'Marten', 'Meerkat', 'Mink', 'Mole', 'Mongoose', 'Monkey', 'Moose', 'Mouse', 'Mosquito', 'Mule'],
n: ['Narwhal', 'Newt', 'Nightingale', 'Nyala'],
o: ['Octopus', 'Okapi', 'Opossum', 'Oryx', 'Ostrich', 'Otter', 'Owl', 'Ox', 'Oyster'],
p: ['Panther', 'Parrot', 'Partridge', 'Peafowl', 'Pelican', 'Penguin', 'Pheasant', 'Pig', 'Pigeon', 'Polar Bear', 'Pony', 'Porcupine', 'Porpoise'],
q: ['Quail', 'Quelea', 'Quetzal'],
r: ['Rabbit', 'Raccoon', 'Rail', 'Ram', 'Rat', 'Raven', 'Red Deer', 'Red Panda', 'Reindeer', 'Rhinoceros', 'Rook'],
s: ['Salamander', 'Salmon', 'Sand Dollar', 'Sandpiper', 'Sardine', 'Scorpion', 'Sea Lion', 'Sea Urchin', 'Seahorse', 'Seal', 'Shark', 'Sheep', 'Shrew', 'Skunk', 'Snail', 'Snake', 'Sparrow', 'Spider', 'Spoonbill', 'Squid', 'Squirrel', 'Starling', 'Stingray', 'Stinkbug', 'Stork', 'Swallow', 'Swan'],
t: ['Tapir', 'Tarsier', 'Termite', 'Tiger', 'Toad', 'Trout', 'Turkey', 'Turtle'],
u: ['Uakari', 'Unau', 'Urial', 'Urchin', 'Umbrellabird', 'Unicornfish', 'Uromastyx', 'Uguisu'],
v: ['Vampire Bat', 'Viper', 'Vole', 'Vulture'],
w: ['Wallaby', 'Walrus', 'Wasp', 'Weasel', 'Whale', 'Wolf', 'Wolverine', 'Wombat', 'Woodcock', 'Woodpecker', 'Worm', 'Wren'],
x: ['Xaviers Greenbul', 'Xeme', 'Xingu Corydoras', 'Xolo'],
y: ['Yabby', 'Yak', 'Yellowhammer', 'Yellowjacket'],
z: ['Zebra', 'Zebu', 'Zokor', 'Zorilla']
};
const action = {
alliteration: {
short: () => {
const randomAdjective = adjectives[letter.toLowerCase()][Math.floor(Math.random() * adjectives[letter.toLowerCase()].length)];
const randomAnimal = animals[letter.toLowerCase()][Math.floor(Math.random() * animals[letter.toLowerCase()].length)];
return randomAdjective + ' ' + randomAnimal;
},
long: () => {
let randomAdjective = '';
for (let i = 1; i <= adjectivesCount; i++) {
if (adjectives[letter.toLowerCase()].length > 0) {
if (randomAdjective.length > 0) {
randomAdjective = randomAdjective + ' ';
}
randomAdjective = randomAdjective + adjectives[letter.toLowerCase()].splice(Math.floor(Math.random() * adjectives[letter.toLowerCase()].length), 1);
}
}
const randomAnimal = animals[letter.toLowerCase()][Math.floor(Math.random() * animals[letter.toLowerCase()].length)];
return randomAdjective + ' ' + randomAnimal;
}
},
mix: {
short: () => {
const adjectivesSeed = alphabet[Math.floor(Math.random() * (alphabet.length - 1))];
const animalsSeed = alphabet[Math.floor(Math.random() * (alphabet.length - 1))];
const randomAdjective = adjectives[adjectivesSeed][Math.floor(Math.random() * adjectives[adjectivesSeed].length)];
const randomAnimal = animals[animalsSeed][Math.floor(Math.random() * animals[animalsSeed].length)];
return randomAdjective + ' ' + randomAnimal;
},
long: () => {
var randomAdjective = '';
for (let i = 1; i <= adjectivesCount; i++) {
var adjectiveLetter = alphabet[Math.floor(Math.random() * (alphabet.length - 1))];
if (adjectiveLetter in adjectives && adjectives[adjectiveLetter].length > 0) {
if (randomAdjective.length > 0) {
randomAdjective = randomAdjective + ' ';
}
randomAdjective = randomAdjective + adjectives[adjectiveLetter].splice(Math.floor(Math.random() * adjectives[adjectiveLetter].length), 1);
if (adjectives[adjectiveLetter].length == 0) {
delete adjectives[adjectiveLetter];
}
}
}
var randomAnimalArray = animals[alphabet[Math.floor(Math.random() * (alphabet.length - 1))]];
var randomAnimal = randomAnimalArray[Math.floor(Math.random() * (randomAnimalArray.length - 1))];
return randomAdjective + ' ' + randomAnimal;
}
}
};
if (letter && alphabet.includes(letter.toLowerCase())) {
if (adjectivesCount && adjectivesCount > 0) {
return action.alliteration.long();
} else {
return action.alliteration.short();
}
} else {
if (adjectivesCount && adjectivesCount > 0) {
return action.mix.long();
} else {
return action.mix.short();
}
}
};

View File

@ -0,0 +1,45 @@
import { makePath } from './makePath.js';
export const set = ({
object = null,
path = null,
value = null
} = {}) => {
const address = makePath(path);
const setValue = () => {
while (address.length > 1) {
// shift off and store the first
let currentKey = address.shift();
// if the key is not found make a new object
if (!(currentKey in object)) {
// make an empty object in the current object level
if (isNaN(currentKey)) {
object[currentKey] = {};
} else {
object[currentKey] = [];
}
}
// drill down the object with the first key
object = object[currentKey];
}
let finalKey = address.shift();
object[finalKey] = value;
};
if (object != null && path != null && value != null) {
setValue();
} else {
return false;
}
};

View File

@ -0,0 +1,37 @@
import { get } from './get';
export const sortArrayOfObject = (array, key) => {
array.sort((a, b) => {
let textA = get({
object: a,
path: key
});
if (typeof textA == 'string') {
textA = textA.toLowerCase();
}
let textB = get({
object: b,
path: key
});
if (typeof textB == 'string') {
textB = textB.toLowerCase();
}
if (textA < textB) {
return -1;
} else if (textA > textB) {
return 1;
} else {
return 0;
}
});
return array;
};

View File

@ -0,0 +1,9 @@
export const trimString = (value) => {
if (typeof value == 'string') {
return value.trim().replace(/\s\s+/g, ' ');
} else {
return value;
}
};

View File

@ -0,0 +1,87 @@
export const wordNumber = (number) => {
const ten = 10;
const oneHundred = 100;
const oneThousand = 1000;
const oneMillion = 1000000;
const oneBillion = 1000000000; // 1,000,000,000 (9)
const oneTrillion = 1000000000000; // 1,000,000,000,000 (12)
const oneQuadrillion = 1000000000000000; // 1,000,000,000,000,000 (15)
const max = 9007199254740992; // 9,007,199,254,740,992 (15)
const lessThanTwenty = ['Zero', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten', 'Eleven', 'Twelve', 'Thirteen', 'Fourteen', 'Fifteen', 'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen'];
const tenthsLessThanHundred = ['Zero', 'Ten', 'Twenty', 'Thirty', 'Forty', 'Fifty', 'Sixty', 'Seventy', 'Eighty', 'Ninety'];
const generateWords = function(number) {
let remainder;
let word;
let words = arguments[1];
// Were done
if (number === 0) {
return !words ? 'Zero' : words.join(' ').replace(/,$/, '');
}
// First run
if (!words) {
words = [];
}
// If negative, prepend “minus”
if (number < 0) {
words.push('minus');
number = Math.abs(number);
}
if (number < 20) {
remainder = 0;
word = lessThanTwenty[number];
} else if (number < oneHundred) {
remainder = number % ten;
word = tenthsLessThanHundred[Math.floor(number / ten)];
// In case of remainder, we need to handle it here to be able to add the “-”
if (remainder) {
word += '-' + lessThanTwenty[remainder];
remainder = 0;
}
} else if (number < oneThousand) {
remainder = number % oneHundred;
word = generateWords(Math.floor(number / oneHundred)) + ' Hundred';
} else if (number < oneMillion) {
remainder = number % oneThousand;
word = generateWords(Math.floor(number / oneThousand)) + ' Thousand,';
} else if (number < oneBillion) {
remainder = number % oneMillion;
word = generateWords(Math.floor(number / oneMillion)) + ' Million,';
} else if (number < oneTrillion) {
remainder = number % oneBillion;
word = generateWords(Math.floor(number / oneBillion)) + ' Billion,';
} else if (number < oneQuadrillion) {
remainder = number % oneTrillion;
word = generateWords(Math.floor(number / oneTrillion)) + ' Trillion,';
} else if (number <= max) {
remainder = number % oneQuadrillion;
word = generateWords(Math.floor(number / oneQuadrillion)) + ' Quadrillion,';
}
words.push(word);
return generateWords(remainder, words);
};
var num = parseInt(number, 10);
return generateWords(num);
};

75
src/config.js Normal file
View File

@ -0,0 +1,75 @@
export const config = {
bookmark: {
newTab: true,
panel: { size: 35 },
group: {
set: [{
active: false,
name: 'Productivity',
description: 'Daily apps',
color: { primary: { hsl: [0, 0, 100] }, secondary: { hsl: [200, 60, 70] } },
list: [
{ icon: 'fa-solid fa-envelope', url: 'https://mail.google.com/' },
{ icon: 'fa-brands fa-slack', url: 'https://slack.com/signin/' },
{ icon: 'fa-brands fa-github', url: 'https://github.com/' },
{ icon: 'fa-brands fa-codepen', url: 'https://codepen.io/' },
{ icon: 'fa-solid fa-diamond', url: 'https://whimsical.com/login/' },
{ icon: 'fa-brands fa-figma', url: 'https://figma.com/' },
{ icon: 'fa-brands fa-dropbox', url: 'https://dropbox.com/' },
{ icon: 'fa-brands fa-google-drive', url: 'https://drive.google.com/' },
{ icon: 'fa-solid fa-calendar-day', url: 'https://calendar.google.com/calendar/' },
]
}, {
active: false,
name: 'Cool stuff',
description: 'Downtime and media',
color: { primary: { hsl: [0, 0, 100] }, secondary: { hsl: [250, 60, 70] } },
list: [
{ icon: 'fa-brands fa-reddit-alien', url: 'https://reddit.com/' },
{ icon: 'fa-brands fa-deviantart', url: 'https://www.deviantart.com/' },
{ icon: 'fa-brands fa-discord', url: 'https://discord.com/' },
{ icon: 'fa-solid fa-paperclip', url: 'https://www.decisionproblem.com/paperclips/' },
{ icon: 'fa-solid fa-dice-d20', url: 'https://zombiefox.github.io/diceRoller/' },
{ icon: 'fa-brands fa-dribbble', url: 'https://dribbble.com/' },
]
}, {
active: false,
name: 'Entertainment',
description: 'Films and videos',
color: { primary: { hsl: [0, 0, 100] }, secondary: { hsl: [0, 60, 70] } },
list: [
{ icon: 'fa-brands fa-vimeo', url: 'https://vimeo.com/' },
{ icon: 'fa-brands fa-youtube', url: 'https://youtube.com/' },
{ icon: 'fa-solid fa-clapperboard', url: 'https://netflix.com/' },
{ icon: 'fa-brands fa-twitch', url: 'https://www.twitch.tv/' },
]
}, {
active: false,
name: 'Ref',
description: 'Docs, code + specs',
color: { primary: { hsl: [0, 0, 100] }, secondary: { hsl: [40, 60, 70] } },
list: [
{ icon: 'fa-solid fa-code', url: 'https://devdocs.io/' },
{ icon: 'fa-brands fa-css3-alt', url: 'https://developer.mozilla.org/en-US/docs/Learn/CSS/' },
{ icon: 'fa-brands fa-stack-overflow', url: 'https://stackoverflow.com/' },
{ icon: 'fa-brands fa-bootstrap', url: 'https://getbootstrap.com/docs/5.2/getting-started/introduction/' },
{ icon: 'fa-brands fa-npm', url: 'https://www.npmjs.com/' },
]
}]
}
},
theme: {
scale: 38,
accent: { hsl: [204, 100, 72] },
text: { hsl: [0, 0, 0] },
font: 'Ubuntu',
transition: { speed: { xfast: 10, fast: 20, medium: 30, slow: 40, xslow: 50 } },
easing: { bounce: [0.8, 0.5, 0.2, 2] },
bookmark: { background: { blur: 14, color: { hsla: [200, 180, 25, 0.2] } } }
},
background: {
color: { hsl: [220, 30, 50] },
image: { url: 'https://i.redd.it/niecy4jmlmh81.png', opacity: 1, grayscale: 0.1, blur: 0 },
gradient: { degree: 90, color: [{ hsla: [220, 80, 18, 0.6], position: 30 }, { hsla: [240, 85, 25, 0.4], position: 40 }, { hsla: [280, 40, 25, 0.1], position: 100 }] }
}
};

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

5
src/icon/favicon.svg Normal file
View File

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path
d="M9.52158 6.99999H13.0087C13.4246 6.99999 13.7999 7.25936 13.9188 7.64686C14.0908 8.03749 13.9813 8.47811 13.6686 8.75311L5.66231 15.7531C5.30891 16.0594 4.79194 16.0844 4.41414 15.8094C4.03603 15.5344 3.89843 15.0344 4.08263 14.6062L6.48795 8.99999H2.9727C2.58396 8.99999 2.21063 8.74061 2.06399 8.35311C1.91734 7.96249 2.02804 7.52186 2.34189 7.24686L10.3472 0.247427C10.7006 -0.0600103 11.2167 -0.0834165 11.5951 0.191052C11.9735 0.465615 12.1111 0.964677 11.9266 1.39405L9.52158 6.99999Z"
fill="#85C2E0"/>
</svg>

After

Width:  |  Height:  |  Size: 633 B

BIN
src/icon/icon-128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
src/icon/icon-16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 B

BIN
src/icon/icon-48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 859 B

BIN
src/icon/icon-512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

35
src/icon/icon-512.svg Normal file
View File

@ -0,0 +1,35 @@
<svg viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg">
<style>
.cross {
fill: #939BAE;
}
.hex {
fill: #252931;
}
@media (prefers-color-scheme: light) {
.cross {
fill: #939BAE;
}
.hex {
fill: #252931;
}
}
@media (prefers-color-scheme: dark) {
.cross {
fill: #252931;
}
.hex {
fill: #939BAE;
}
}
</style>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M507.885 271.42C513.372 261.948 513.372 250.263 507.885 240.79L395.206 46.2423C389.742 36.8083 379.665 31 368.763 31H143.237C132.335 31 122.258 36.8083 116.794 46.2423L4.11494 240.79C-1.37164 250.263 -1.37165 261.948 4.11494 271.42L116.794 465.968C122.258 475.402 132.335 481.21 143.237 481.21H368.763C379.665 481.21 389.742 475.402 395.206 465.968L507.885 271.42Z"
class="hex"/>
<path d="M374 224H138C132.477 224 128 228.477 128 234V278C128 283.523 132.477 288 138 288H374C379.523 288 384 283.523 384 278V234C384 228.477 379.523 224 374 224Z" class="cross"/>
<path d="M278 128H234C228.477 128 224 132.477 224 138V374C224 379.523 228.477 384 234 384H278C283.523 384 288 379.523 288 374V138C288 132.477 283.523 128 278 128Z" class="cross"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

15
src/index.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<title>Volt Tab</title>
<link rel="icon" type="image/svg+xml" href="icon/favicon.svg"/>
<style media="screen" type="text/css">html,body {background-color: rgb(0, 0, 0);}</style>
</head>
<body></body>
</html>

5
src/index.js Normal file
View File

@ -0,0 +1,5 @@
import { App } from './app';
const app = new App();
app.render();

16
src/manifest.json Normal file
View File

@ -0,0 +1,16 @@
{
"name": "Volt Tab",
"short_name": "Volt Tab",
"description": "",
"version": "1.0.0",
"manifest_version": 2,
"chrome_url_overrides": {
"newtab": "index.html"
},
"icons": {
"16": "icon/icon-16.png",
"48": "icon/icon-48.png",
"128": "icon/icon-128.png",
"512": "icon/icon-512.png"
}
}

313
src/style/reset/index.css Normal file
View File

@ -0,0 +1,313 @@
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
line-height: 1.15;
-webkit-text-size-adjust: 100%;
-ms-overflow-style: scrollbar;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
display: block;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, Noto Sans, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #212529;
text-align: left;
background-color: #000;
}
[tabindex="-1"]:focus {
outline: none !important;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 0.5rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-original-title] {
text-decoration: underline;
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
border-bottom: 0;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: .5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 80%;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -.25em;
}
sup {
top: -.5em;
}
a {
color: #007bff;
text-decoration: none;
background-color: transparent;
}
a:hover {
color: #0056b3;
text-decoration: underline;
}
a:not([href]):not([tabindex]) {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):focus {
outline: none;
}
pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 1em;
}
pre {
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
-ms-overflow-style: scrollbar;
}
figure {
margin: 0 0 1rem;
}
img {
vertical-align: middle;
border-style: none;
}
svg {
overflow: hidden;
vertical-align: middle;
}
table {
border-collapse: collapse;
}
caption {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
color: #6c757d;
text-align: left;
caption-side: bottom;
}
th {
text-align: inherit;
}
label {
display: inline-block;
margin-bottom: 0;
}
button {
border-radius: 0;
}
button:focus {
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type="radio"],
input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
-webkit-appearance: listbox;
}
textarea {
overflow: auto;
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
display: block;
width: 100%;
max-width: 100%;
padding: 0;
margin-bottom: .5rem;
font-size: 1.5rem;
line-height: inherit;
color: inherit;
white-space: normal;
}
progress {
vertical-align: baseline;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
outline-offset: -2px;
-webkit-appearance: none;
}
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
summary {
display: list-item;
cursor: pointer;
}
template {
display: none;
}
[hidden] {
display: none !important;
}

View File

@ -0,0 +1,179 @@
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0 0 1em 0;
font-weight: normal;
line-height: 1.6;
color: hsl(var(--theme-primary-text-010));
}
h1 {
font-size: 1.5em;
font-family: var(--theme-font-display-name);
font-weight: var(--theme-font-display-weight);
font-style: var(--theme-font-display-style);
}
h2 {
font-size: 1.3em;
font-family: var(--theme-font-display-name);
font-weight: var(--theme-font-display-weight);
font-style: var(--theme-font-display-style);
}
h3 {
font-size: 1.1em;
font-family: var(--theme-font-ui-name);
font-weight: var(--theme-font-ui-weight);
font-style: var(--theme-font-ui-style);
}
h4 {
font-size: 1em;
font-family: var(--theme-font-ui-name);
font-weight: var(--theme-font-ui-weight);
font-style: var(--theme-font-ui-style);
}
h5 {
font-size: 1em;
font-family: var(--theme-font-ui-name);
font-weight: var(--theme-font-ui-weight);
font-style: var(--theme-font-ui-style);
font-weight: bold;
}
h6 {
font-size: 0.75em;
font-family: var(--theme-font-ui-name);
font-weight: var(--theme-font-ui-weight);
font-style: var(--theme-font-ui-style);
font-weight: bold;
}
p {
color: hsl(var(--theme-primary-text-010));
margin: 0;
line-height: 1.6;
}
hr {
border: 0;
border-top: var(--layout-horizontal-rule-small);
border-radius: calc(var(--theme-radius) * 0.01em);
margin: calc(var(--wrap-space) * 2) 0;
clear: both;
transition: border-color var(--layout-transition-extra-fast);
}
b,
caption,
strong {
color: hsl(var(--theme-primary-text-010));
font-family: var(--theme-font-ui-name);
font-weight: 600;
}
i {
font-style: italic;
}
a {
color: hsl(var(--theme-primary-text-010));
text-decoration: underline;
transition: text-decoration var(--layout-transition-extra-fast);
}
a:link,
a:visited {
color: hsl(var(--theme-primary-text-010));
}
a:focus {
text-decoration-color: hsl(var(--theme-primary-text-010));
outline: none;
}
a:hover {
color: hsl(var(--theme-primary-text-010));
text-decoration-color: rgb(var(--theme-accent));
}
a:active {
color: hsl(var(--theme-primary-text-010));
text-decoration-color: hsl(var(--theme-primary-text-010));
}
ol,
ul {
margin: 0;
padding: 0 0 0 1.5em;
}
ol:not(:last-child),
ul:not(:last-child) {
margin-bottom: 1em;
}
li {
margin: 0;
}
li>ul,
li>ol {
margin: 0;
}
li:not(:last-child) {
margin-bottom: 0.5em;
}
li>ul:not(:last-child),
li>ol:not(:last-child) {
margin-bottom: 0.5em;
}
table {
border: 0;
margin: 0 0 1em;
padding: 0;
width: 100%;
border-spacing: 0;
}
table thead tr td,
table thead tr th {
background-color: hsl(var(--theme-primary-030));
border: 0;
border-bottom: 1px solid hsl(var(--theme-primary-040));
padding: 0.5em;
margin: 0;
text-align: left;
font-family: var(--theme-font-ui-name);
font-weight: var(--theme-font-ui-weight);
font-style: var(--theme-font-ui-style);
font-weight: bold;
box-sizing: border-box;
}
table tr:nth-child(odd) {
background-color: hsl(var(--theme-primary-020));
}
table tbody tr td,
table tbody tr th {
padding: 0.25em 0.5em;
margin: 0;
border: 0;
text-align: left;
box-sizing: border-box;
}
code {
background-color: hsl(var(--theme-primary-040));
padding: 0.2em 0.5em;
border-radius: calc(var(--theme-radius) * 0.01em);
}

View File

@ -0,0 +1,4 @@
:root {
--z-index-background: 1000;
--z-index-bookmark: 2000;
}

46
webpack.common.js Normal file
View File

@ -0,0 +1,46 @@
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
entry: {
index: path.resolve(__dirname, 'src', 'index.js')
},
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist/web'),
clean: true
},
module: {
rules: [{
test: /\.css$/i,
use: ['style-loader', 'css-loader']
}, {
test: /\.(ttf|woff|woff2)$/,
type: 'asset/resource',
generator: {
filename: 'font/[name][ext]',
}
}, {
test: /\.(jpe?g|png|gif|svg)$/i,
type: 'asset/resource',
generator: {
filename: 'image/[name][ext]',
}
}]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new CopyPlugin({
patterns: [{
from: './src/manifest.json',
to: './manifest.json'
}, {
from: './src/icon/',
to: './icon/'
}]
})
]
};

7
webpack.dev.js Normal file
View File

@ -0,0 +1,7 @@
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map'
});

45
webpack.prod.js Normal file
View File

@ -0,0 +1,45 @@
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const path = require('path');
const ZipPlugin = require('zip-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const version = require('./src/manifest.json').version;
const name = require('./src/manifest.json').name;
module.exports = merge(common, {
mode: 'production',
optimization: {
minimize: true,
minimizer: [
new CssMinimizerPlugin({
minify: CssMinimizerPlugin.cleanCssMinify
}),
new TerserPlugin({
terserOptions: {
format: {
comments: false,
},
},
extractComments: false,
})
]
},
module: {
rules: [{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
}],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css'
}),
new ZipPlugin({
path: path.resolve(__dirname, 'dist/extension'),
filename: name + ' ' + version + '.zip'
})
]
});