initial commit
This commit is contained in:
commit
062fc37c80
|
@ -0,0 +1,157 @@
|
||||||
|
:root {
|
||||||
|
--clarity: 1;
|
||||||
|
|
||||||
|
--theme: #c3202f;
|
||||||
|
--white: #FFF;
|
||||||
|
--black: #000;
|
||||||
|
--tint: #ACACAC;
|
||||||
|
--background: #EEE;
|
||||||
|
--surface: #FFF;
|
||||||
|
--primary: var(--theme);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CSS Reset */
|
||||||
|
|
||||||
|
html {
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: "Roboto", georgia, serif;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.4em;
|
||||||
|
color: #474747;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*:before,
|
||||||
|
*:after {
|
||||||
|
box-sizing: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body,
|
||||||
|
html,
|
||||||
|
span,
|
||||||
|
div {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol,
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
img,
|
||||||
|
embed,
|
||||||
|
iframe,
|
||||||
|
object,
|
||||||
|
audio,
|
||||||
|
video {
|
||||||
|
height: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"],
|
||||||
|
input[type="radio"] {
|
||||||
|
margin-right: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nav */
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
background: var(--theme);
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav a {color: var(--white)}
|
||||||
|
|
||||||
|
/* Layout */
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
direction: row;
|
||||||
|
align-items: center;
|
||||||
|
align-content: space-between;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col, .col-1, .col-2, .col-3, .col-4, .col-5 {
|
||||||
|
display: flex;
|
||||||
|
direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-1 {flex: 1}
|
||||||
|
.col-2 {flex: 2}
|
||||||
|
.col-3 {flex: 3}
|
||||||
|
.col-4 {flex: 4}
|
||||||
|
.col-5 {flex: 5}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
padding: .5em;
|
||||||
|
margin: .5em;
|
||||||
|
border: 1px solid var(--primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weak {color: #727272}
|
||||||
|
|
||||||
|
|
||||||
|
h1 {font-size: 2.4em}
|
||||||
|
h2 {font-size: 1.8em}
|
||||||
|
h3 {font-size: 1.6em}
|
||||||
|
h4 {font-size: 1.4em}
|
||||||
|
h5 {font-size: 1.2em}
|
||||||
|
h6 {font-size: 1em}
|
||||||
|
|
||||||
|
/* utility */
|
||||||
|
|
||||||
|
.capitalized {text-transform: capitalize}
|
||||||
|
.uppercased {text-transform: uppercase}
|
||||||
|
.lowercased {text-transform: lowercase}
|
||||||
|
.inline {display: inline;}
|
||||||
|
|
||||||
|
|
||||||
|
.shadowed {
|
||||||
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.surfaced {
|
||||||
|
background-color: var(--surface);
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
border-bottom: 1px solid var(--tint);
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {float: right}
|
||||||
|
.left {float: left}
|
||||||
|
.centered {text-align: center;}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
|
||||||
|
const html = (content) => {
|
||||||
|
let template = document.createElement("template");
|
||||||
|
template.innerHTML = content;
|
||||||
|
return template.content
|
||||||
|
};
|
||||||
|
|
||||||
|
class NewsSummary extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.cache = true;
|
||||||
|
this.state = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
async read(part, id) {
|
||||||
|
let hn = "https://hacker-news.firebaseio.com/v0";
|
||||||
|
|
||||||
|
switch(part) {
|
||||||
|
case "list":
|
||||||
|
return await fetch(`${hn}/topstories.json`).then(r => r.json()).then(r => r);
|
||||||
|
case "details":
|
||||||
|
return await fetch(`${hn}/item/${id}.json`).then(r => r.json()).then(r => r);
|
||||||
|
default:
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a value or false
|
||||||
|
*
|
||||||
|
* useful for truthy expressions where objects or arrays are defined, but empty
|
||||||
|
*
|
||||||
|
* @param {Any} val
|
||||||
|
*/
|
||||||
|
_exists(val) {
|
||||||
|
|
||||||
|
// console.log('typeof', val, typeof val);
|
||||||
|
|
||||||
|
if(typeof val !== 'object' || val === null) {
|
||||||
|
return !!val ? val : false;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if(typeof val === "object") {
|
||||||
|
|
||||||
|
if(val.length !== 'undefined') {
|
||||||
|
return !!val.length ? val : false;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return (Object.getOwnPropertyNames(val).length > 0) ? val : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Storage Helper
|
||||||
|
*/
|
||||||
|
_store() {
|
||||||
|
return {
|
||||||
|
get: (key) => {
|
||||||
|
return this._exists(JSON.parse(window.localStorage.getItem(key)));
|
||||||
|
},
|
||||||
|
set: (key, val) => {
|
||||||
|
return this._exists(window.localStorage.setItem(key, JSON.stringify(val)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async connectedCallback() {
|
||||||
|
console.log('connected');
|
||||||
|
|
||||||
|
// get identifiers list
|
||||||
|
if(this.cache) {
|
||||||
|
console.log('cache enabled...');
|
||||||
|
|
||||||
|
if(this._store().get("list")) {
|
||||||
|
console.log('found in cache...');
|
||||||
|
this.state.list = this._store().get("list");
|
||||||
|
} else {
|
||||||
|
console.log('building cache...');
|
||||||
|
let list = await this.read("list");
|
||||||
|
this.state.list = list;
|
||||||
|
this._store().set("list", list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get details from idenifiers list
|
||||||
|
if (this.cache) {
|
||||||
|
console.log('cache enabled...');
|
||||||
|
if (this._store().get("details")) {
|
||||||
|
console.log('found in cache...');
|
||||||
|
this.state.details = this._store().get("details");
|
||||||
|
} else {
|
||||||
|
console.log('building cache...');
|
||||||
|
this.state.details = [];
|
||||||
|
|
||||||
|
for (let i =0; i < 15; i++) {
|
||||||
|
let item = await this.read("details", this.state.list[i]);
|
||||||
|
this.state.details.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._store().set("details", this.state.details);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('...done');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._render();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// _template() {
|
||||||
|
// return html`
|
||||||
|
// <section class="surfaced">
|
||||||
|
// <h6 class="inline capitalized title"><a href="${item.url}">${item.title}</a></h6>
|
||||||
|
// <div class="weak is-sm">[ hype: ${item.score} | topic: <a href="">${item.type}</a> | source: <a href="">${item.by}</a> | <a href="">${item.kids.length} comments</a> ]</div>
|
||||||
|
// </section>
|
||||||
|
// `;
|
||||||
|
// }
|
||||||
|
|
||||||
|
_render() {
|
||||||
|
this.innerHTML = `
|
||||||
|
${this.state.details.map(item => `
|
||||||
|
<div class="surfaced" style="margin-bottom: 8px;">
|
||||||
|
<h6 class="inline capitalized title"><a href="${item.url}">${item.title}</a></h6>
|
||||||
|
<div>
|
||||||
|
<small class="weak">[ hype: ${item.score} | topic: <a href="">${item.type}</a> | source: <a href="">${item.by}</a> | <a href="">${(item.kids || []).length} comments</a> ]</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('news-summary', NewsSummary);
|
|
@ -0,0 +1,42 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>Bootleg</title>
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Roboto&display=swap" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.2/css/all.css">
|
||||||
|
<link rel="stylesheet" href="bootleg.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<header>
|
||||||
|
<nav class="nav content row">
|
||||||
|
<div>
|
||||||
|
<a class="content" href=""><strong>[H]YPE</strong></a>
|
||||||
|
<a href="">new</a> |
|
||||||
|
<a href="">past</a> |
|
||||||
|
<a href="">comments</a> |
|
||||||
|
<a href="">ask</a> |
|
||||||
|
<a href="">show</a> |
|
||||||
|
<a href="">jobs</a> |
|
||||||
|
<button>
|
||||||
|
<i class="fa fa-check"></i>
|
||||||
|
submit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<a class="content right" href="">login</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<div class="content">
|
||||||
|
<news-summary item="{}"></news-summary>
|
||||||
|
</div>
|
||||||
|
<footer>
|
||||||
|
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="components/news-summary.js"></script>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue