public release
This commit is contained in:
parent
80172f0a17
commit
b2fe50fd4f
12 changed files with 533 additions and 1 deletions
10
README.md
10
README.md
|
|
@ -1 +1,9 @@
|
|||
# LittleHome
|
||||
 <br>
|
||||
|
||||
# How to install
|
||||
1. Install [`this`](https://fonts.google.com/share?selection.family=Fira+Code:wght@300..700|Nunito:ital,wght@0,200..1000;1,200..1000|Playfair+Display:ital,wght@0,400..900;1,400..900) fonts
|
||||
2. Clone repository
|
||||
3. Go to `chrome://extensions`
|
||||
4. Enable `Developer mode`
|
||||
5. Click `Load unpacked` > select repo's folder
|
||||
6. Enjoy your new tab/home page
|
||||
32
manifest.json
Normal file
32
manifest.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"manifest_version": 3,
|
||||
"name": "LittleHome",
|
||||
"version": "0.2",
|
||||
"description": "My personal homepage with bangs support",
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
"storage"
|
||||
],
|
||||
"icons": {
|
||||
"48": "src/icon.svg"
|
||||
},
|
||||
"action": {
|
||||
"default_icon": "src/icon.svg"
|
||||
},
|
||||
"chrome_url_overrides": {
|
||||
"newtab": "src/index.html"
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": [
|
||||
"<all_urls>"
|
||||
],
|
||||
"js": [
|
||||
"src/js/abstract.js",
|
||||
"src/js/storage.js",
|
||||
"src/js/bang.js",
|
||||
"src/js/main.js"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
media/logo.png
Normal file
BIN
media/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
28
src/css/clock.css
Normal file
28
src/css/clock.css
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#clock {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 10px;
|
||||
overflow-y: hidden;
|
||||
align-items: start;
|
||||
justify-content: start;
|
||||
height: 100px;
|
||||
transition: opacity .2s;
|
||||
/* opacity: 0; */
|
||||
mask-image: linear-gradient(transparent, #000 10%, #000 90%, transparent );
|
||||
} #clock > .digit {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: start;
|
||||
justify-content: start;
|
||||
transition: transform .4s;
|
||||
gap: 0;
|
||||
} #clock > .digit > span {
|
||||
font-weight: 800;
|
||||
font-size: 80px;
|
||||
font-family: 'Nunito';
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
} #clock > .digit.l {
|
||||
transform: translateY(-7px);
|
||||
}
|
||||
209
src/css/global.css
Normal file
209
src/css/global.css
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
body {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
overflow-y: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #000;
|
||||
}
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#background {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* https://www.mshr.app/mesh/1727910717365 */
|
||||
@keyframes hero-gradient-animation {
|
||||
0% {
|
||||
--x-0: 85%;
|
||||
--s-start-0: 9%;
|
||||
--s-end-0: 55%;
|
||||
--y-0: 80%;
|
||||
--c-0: hsla(266.99999999999983, 1%, 12%, 1);
|
||||
--c-1: hsla(335.9999999999997, 2%, 22%, 1);
|
||||
--s-start-1: 5%;
|
||||
--s-end-1: 72%;
|
||||
--y-1: 24%;
|
||||
--x-1: 60%;
|
||||
--s-start-2: 5%;
|
||||
--s-end-2: 52%;
|
||||
--y-2: 82%;
|
||||
--c-2: hsla(53.999999999999886, 0%, 0%, 0.49);
|
||||
--x-2: 13%;
|
||||
--s-start-3: 13%;
|
||||
--s-end-3: 68%;
|
||||
--c-3: hsla(299, 4%, 36%, 1);
|
||||
--x-3: 24%;
|
||||
--y-3: 7%;
|
||||
}
|
||||
|
||||
100% {
|
||||
--x-0: 31%;
|
||||
--s-start-0: 9%;
|
||||
--s-end-0: 55%;
|
||||
--y-0: 94%;
|
||||
--c-0: hsla(266.99999999999943, 0%, 12%, 1);
|
||||
--c-1: hsla(0, 4%, 19%, 1);
|
||||
--s-start-1: 5%;
|
||||
--s-end-1: 72%;
|
||||
--y-1: 25%;
|
||||
--x-1: 2%;
|
||||
--s-start-2: 5%;
|
||||
--s-end-2: 52%;
|
||||
--y-2: 20%;
|
||||
--c-2: hsla(54.000000000000036, 0%, 0%, 0.49);
|
||||
--x-2: 98%;
|
||||
--s-start-3: 13%;
|
||||
--s-end-3: 68%;
|
||||
--c-3: hsla(298.99999999999994, 3%, 41%, 1);
|
||||
--x-3: 95%;
|
||||
--y-3: 92%;
|
||||
}
|
||||
}
|
||||
|
||||
@property --x-0 {
|
||||
syntax: '<percentage>';
|
||||
inherits: false;
|
||||
initial-value: 85%
|
||||
}
|
||||
|
||||
@property --s-start-0 {
|
||||
syntax: '<percentage>';
|
||||
inherits: false;
|
||||
initial-value: 9%
|
||||
}
|
||||
|
||||
@property --s-end-0 {
|
||||
syntax: '<percentage>';
|
||||
inherits: false;
|
||||
initial-value: 55%
|
||||
}
|
||||
|
||||
@property --y-0 {
|
||||
syntax: '<percentage>';
|
||||
inherits: false;
|
||||
initial-value: 80%
|
||||
}
|
||||
|
||||
@property --c-0 {
|
||||
syntax: '<color>';
|
||||
inherits: false;
|
||||
initial-value: hsla(266.99999999999983, 1%, 12%, 1)
|
||||
}
|
||||
|
||||
@property --c-1 {
|
||||
syntax: '<color>';
|
||||
inherits: false;
|
||||
initial-value: hsla(335.9999999999997, 2%, 22%, 1)
|
||||
}
|
||||
|
||||
@property --s-start-1 {
|
||||
syntax: '<percentage>';
|
||||
inherits: false;
|
||||
initial-value: 5%
|
||||
}
|
||||
|
||||
@property --s-end-1 {
|
||||
syntax: '<percentage>';
|
||||
inherits: false;
|
||||
initial-value: 72%
|
||||
}
|
||||
|
||||
@property --y-1 {
|
||||
syntax: '<percentage>';
|
||||
inherits: false;
|
||||
initial-value: 24%
|
||||
}
|
||||
|
||||
@property --x-1 {
|
||||
syntax: '<percentage>';
|
||||
inherits: false;
|
||||
initial-value: 60%
|
||||
}
|
||||
|
||||
@property --s-start-2 {
|
||||
syntax: '<percentage>';
|
||||
inherits: false;
|
||||
initial-value: 5%
|
||||
}
|
||||
|
||||
@property --s-end-2 {
|
||||
syntax: '<percentage>';
|
||||
inherits: false;
|
||||
initial-value: 52%
|
||||
}
|
||||
|
||||
@property --y-2 {
|
||||
syntax: '<percentage>';
|
||||
inherits: false;
|
||||
initial-value: 82%
|
||||
}
|
||||
|
||||
@property --c-2 {
|
||||
syntax: '<color>';
|
||||
inherits: false;
|
||||
initial-value: hsla(53.999999999999886, 0%, 0%, 0.49)
|
||||
}
|
||||
|
||||
@property --x-2 {
|
||||
syntax: '<percentage>';
|
||||
inherits: false;
|
||||
initial-value: 13%
|
||||
}
|
||||
|
||||
@property --s-start-3 {
|
||||
syntax: '<percentage>';
|
||||
inherits: false;
|
||||
initial-value: 13%
|
||||
}
|
||||
|
||||
@property --s-end-3 {
|
||||
syntax: '<percentage>';
|
||||
inherits: false;
|
||||
initial-value: 68%
|
||||
}
|
||||
|
||||
@property --c-3 {
|
||||
syntax: '<color>';
|
||||
inherits: false;
|
||||
initial-value: hsla(299, 4%, 36%, 1)
|
||||
}
|
||||
|
||||
@property --x-3 {
|
||||
syntax: '<percentage>';
|
||||
inherits: false;
|
||||
initial-value: 24%
|
||||
}
|
||||
|
||||
@property --y-3 {
|
||||
syntax: '<percentage>';
|
||||
inherits: false;
|
||||
initial-value: 7%
|
||||
}
|
||||
|
||||
#background {
|
||||
--x-0: 85%;
|
||||
--y-0: 80%;
|
||||
--c-0: hsla(266.99999999999983, 1%, 12%, 1);
|
||||
--c-1: hsla(335.9999999999997, 2%, 22%, 1);
|
||||
--y-1: 24%;
|
||||
--x-1: 60%;
|
||||
--y-2: 82%;
|
||||
--c-2: hsla(53.999999999999886, 0%, 0%, 0.49);
|
||||
--x-2: 13%;
|
||||
--c-3: hsla(299, 4%, 36%, 1);
|
||||
--x-3: 24%;
|
||||
--y-3: 7%;
|
||||
;
|
||||
background-color: hsla(0, 0%, 0%, 1);
|
||||
background-image: radial-gradient(circle at var(--x-0) var(--y-0), var(--c-0) var(--s-start-0), transparent var(--s-end-0)), radial-gradient(circle at var(--x-1) var(--y-1), var(--c-1) var(--s-start-1), transparent var(--s-end-1)), radial-gradient(circle at var(--x-2) var(--y-2), var(--c-2) var(--s-start-2), transparent var(--s-end-2)), radial-gradient(circle at var(--x-3) var(--y-3), var(--c-3) var(--s-start-3), transparent var(--s-end-3));
|
||||
animation: hero-gradient-animation 10s linear infinite alternate;
|
||||
background-blend-mode: normal, normal, normal, normal;
|
||||
}
|
||||
44
src/css/search.css
Normal file
44
src/css/search.css
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#search_ddd {
|
||||
z-index: 10;
|
||||
position: fixed;
|
||||
color: #000;
|
||||
/* visibility: hidden */
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#searcher {
|
||||
background: rgba(0,0,0,.2);
|
||||
transition: opacity .2s;
|
||||
opacity: 0;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 5;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
#searcher > h1 {
|
||||
font-family: 'Playfair Display';
|
||||
font-weight: normal;
|
||||
font-size: 70px;
|
||||
text-align: center;
|
||||
} #searcher > h1 > span {
|
||||
transition: background .2s;
|
||||
font-size: 33px;
|
||||
font-family: 'Fira Code';
|
||||
background: rgba(255,255,255,.1);
|
||||
padding: 0 5px 0;
|
||||
border-radius: 10px;
|
||||
vertical-align:middle;
|
||||
|
||||
} #searcher > h1 > span.error {
|
||||
background: rgba(255,100,100,.2);
|
||||
} #searcher > p {
|
||||
font-family: 'Nunito';
|
||||
}
|
||||
1
src/icon.svg
Normal file
1
src/icon.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M240-200h120v-240h240v240h120v-360L480-740 240-560v360Zm-80 80v-480l320-240 320 240v480H520v-240h-80v240H160Zm320-350Z"/></svg>
|
||||
|
After Width: | Height: | Size: 243 B |
26
src/index.html
Normal file
26
src/index.html
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Home</title>
|
||||
<link rel="shortcut icon" href="icon.svg" type="image/x-icon">
|
||||
|
||||
<link rel="stylesheet" href="css/global.css">
|
||||
<link rel="stylesheet" href="css/clock.css">
|
||||
<link rel="stylesheet" href="css/search.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="background"></div>
|
||||
<div id="searcher">
|
||||
<h1></h1>
|
||||
<p>Search via Google</p>
|
||||
</div>
|
||||
<input type="text" id="search_ddd" autocorrect="off" autocomplete="off" autofocus>
|
||||
|
||||
<script src="js/abstract.js"></script>
|
||||
<script src="js/storage.js"></script>
|
||||
<script src="js/bang.js"></script>
|
||||
<script src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
67
src/js/abstract.js
Normal file
67
src/js/abstract.js
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* @typedef {Object} $
|
||||
* @property {function(object=, ...HTMLElement): HTMLElement} DOCS - creates element with this tagname
|
||||
*/
|
||||
|
||||
/**
|
||||
* ### Create element
|
||||
*
|
||||
* @type {$}
|
||||
*/
|
||||
const $ = new Proxy(
|
||||
class {
|
||||
/**
|
||||
* ### Creates `$` element
|
||||
* @param {string} type element type
|
||||
* @param {object} props element properties (onclick, class, ...)
|
||||
* @param {...HTMLElement} children
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
static createElement(type, props, ...children) {
|
||||
const element = document.createElement(type)
|
||||
|
||||
if (props) {
|
||||
try {
|
||||
if (
|
||||
props instanceof Node
|
||||
|| typeof props === 'string'
|
||||
|| typeof props === 'number'
|
||||
) children = [props, ...children]
|
||||
else {throw Error()}
|
||||
} catch {
|
||||
for (const [key, value] of Object.entries(props)) {
|
||||
if (key.startsWith('on') && typeof value === 'function') {
|
||||
element.addEventListener(key.slice(2).toLowerCase(), value)
|
||||
} else if (key === 'className') {
|
||||
element.className = value
|
||||
} else {
|
||||
element.setAttribute(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
children.flat().forEach(child => {
|
||||
if (typeof child === 'string' || typeof child === 'number') {
|
||||
element.innerHTML += child
|
||||
} else if (child instanceof Node) {
|
||||
element.appendChild(child)
|
||||
}
|
||||
});
|
||||
|
||||
element[Symbol.toPrimitive] = function(hint) {
|
||||
if (hint === 'string') return this.outerHTML
|
||||
return this
|
||||
};
|
||||
|
||||
return element
|
||||
}
|
||||
},
|
||||
{
|
||||
get(target, element) {
|
||||
return function(props, ...children) {
|
||||
return target.createElement(element, props, ...children)
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
1
src/js/bang.js
Normal file
1
src/js/bang.js
Normal file
File diff suppressed because one or more lines are too long
83
src/js/main.js
Normal file
83
src/js/main.js
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
const clock = async () => {
|
||||
const render = async () => {
|
||||
const baseOffset = 109.12
|
||||
const tsp = number => (number < 10 ? `0${number}` : `${number}`).split('').map(e => parseInt(e)*baseOffset)
|
||||
const time = new Date()
|
||||
var ft = [tsp(time.getHours()), tsp(time.getMinutes()), tsp(time.getSeconds())].flat()
|
||||
var fe = [
|
||||
document.querySelectorAll('.digit.h')[0],
|
||||
document.querySelectorAll('.digit.h')[1],
|
||||
document.querySelectorAll('.digit.m')[0],
|
||||
document.querySelectorAll('.digit.m')[1],
|
||||
document.querySelectorAll('.digit.s')[0],
|
||||
document.querySelectorAll('.digit.s')[1]
|
||||
]
|
||||
var _ = [...Array(6).keys()].map(i => {
|
||||
const value = ft[i]
|
||||
const element = fe[i]
|
||||
element.style = `transform: translateY(-${value}px)`
|
||||
})
|
||||
}
|
||||
|
||||
document.querySelector('body').appendChild(
|
||||
$.div(
|
||||
{id: 'clock'},
|
||||
$.div({class: 'digit h'}, [...Array(3).keys()].map(_ => $.span(_.toString()))),
|
||||
$.div({class: 'digit h'}, [...Array(11).keys()].map(_ => $.span(_ < 10 ? _.toString() : '0'))),
|
||||
$.div({class: 'digit l'}, $.span(':')),
|
||||
$.div({class: 'digit m'}, [...Array(7).keys()].map(_ => $.span(_ < 10 ? _.toString() : '0'))),
|
||||
$.div({class: 'digit m'}, [...Array(11).keys()].map(_ => $.span(_ < 10 ? _.toString() : '0'))),
|
||||
$.div({class: 'digit l'}, $.span(':')),
|
||||
$.div({class: 'digit s'}, [...Array(7).keys()].map(_ => $.span(_ < 10 ? _.toString() : '0'))),
|
||||
$.div({class: 'digit s'}, [...Array(11).keys()].map(_ => $.span(_ < 10 ? _.toString() : '0'))),
|
||||
)
|
||||
)
|
||||
render()
|
||||
setInterval(() => render(), 1000);
|
||||
}
|
||||
|
||||
|
||||
searcher = () => {
|
||||
const findbang = query => {
|
||||
if (query.indexOf('!') == -1) return {found: false, valid: false}
|
||||
const inputed = query.split('!')[1]
|
||||
for (const bang of bangs) {
|
||||
if (bang.t == inputed) return {found: true, valid: true, inputed: inputed, data: bang}
|
||||
}
|
||||
return {found: true, valid: false, inputed: inputed}
|
||||
|
||||
}
|
||||
var lastquery = ''
|
||||
const proceed = query => {
|
||||
if (query == lastquery) return
|
||||
lastquery = query
|
||||
document.querySelector('#clock').style.opacity = query == '' ? 1 : 0
|
||||
document.querySelector('#searcher').style.opacity = query == '' ? 0 : 1
|
||||
const fb = findbang(query)
|
||||
if (fb.found) query = query.replace('!'+fb.inputed, `<span class="${fb.valid? '' : 'error'}">!${fb.inputed}</span>`)
|
||||
console.log(query)
|
||||
document.querySelector('#searcher > h1').innerHTML = query
|
||||
document.querySelector('#searcher > p').innerHTML = `Search via ${fb.valid? fb.data.s : 'Google'}`
|
||||
|
||||
}
|
||||
const find = element => {
|
||||
const query = element.target.value
|
||||
const fb = findbang(query)
|
||||
const url = fb.valid ? fb.data.u : 'https://www.google.com/search?q={{{s}}}'
|
||||
window.location.href = url.replace('{{{s}}}', encodeURI(fb.found ? query.replace('!'+fb.inputed, '').trim() : query.trim()))
|
||||
}
|
||||
document.querySelector('#search_ddd').addEventListener('change', find)
|
||||
document.querySelector('#search_ddd').addEventListener('input', (e) => {proceed(e.target.value.trim())})
|
||||
setInterval(() => {
|
||||
document.querySelector('#search_ddd').focus()
|
||||
proceed(document.querySelector('#search_ddd').value.trim())
|
||||
}, 100);
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', async () => {
|
||||
clock()
|
||||
searcher()
|
||||
})
|
||||
|
||||
|
||||
setInterval()
|
||||
33
src/js/storage.js
Normal file
33
src/js/storage.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
const CookieManager = {
|
||||
get: (cname) => {
|
||||
let name = cname + "=";
|
||||
let decodedCookie = decodeURIComponent(document.cookie);
|
||||
let ca = decodedCookie.split(';');
|
||||
for(let i = 0; i <ca.length; i++) {
|
||||
let c = ca[i];
|
||||
while (c.charAt(0) == ' ') {
|
||||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) == 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
},
|
||||
set: (cname, cvalue) => {
|
||||
const d = new Date();
|
||||
d.setTime(d.getTime() + (999*24*60*60*1000));
|
||||
let expires = "expires="+ d.toUTCString();
|
||||
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getFromStorage(variable_name) {
|
||||
const c = CookieManager.get(variable_name)
|
||||
return c === '' ? null : c
|
||||
}
|
||||
|
||||
function setToStorage(variable_name, value) {
|
||||
CookieManager.set(variable_name, value)
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue