Changes brought over from the blog post.

main
Zed A. Shaw 1 year ago
parent 986b4321d4
commit 6c54f5a9d5
  1. 2
      .gitignore
  2. 4
      client/components/Darkmode.svelte
  3. 10
      client/components/IconImage.svelte
  4. 2
      client/components/Markdown.svelte
  5. 8
      commands/templates/client/Footer.svelte
  6. 19
      commands/templates/client/Header.svelte
  7. 1
      commands/templates/client/config.js
  8. 8
      commands/templates/rendered/Footer.svelte
  9. 87
      commands/templates/rendered/Header.svelte
  10. 216
      rendered/index.svelte
  11. 142
      rendered/pages/blog/[slug]/index.svelte
  12. 138
      rendered/pages/blog/index.svelte
  13. 6
      rendered/pages/test_large_card.svelte
  14. 6
      rendered/pages/test_og_card.svelte
  15. 6
      rendered/pages/test_video_card.svelte
  16. 14
      rendered/posts/01-sample.md
  17. 1
      static/admin/index.html
  18. 7
      static/color.css
  19. 32
      static/global.css
  20. 4529
      static/js/prism.cjs
  21. 2
      static/prod_icons.json

2
.gitignore vendored

@ -13,8 +13,6 @@ secrets/*
coverage/ coverage/
.coverage .coverage
static/module static/module
client/config.js
emails/config.js
media media
tests/fixtures tests/fixtures
rendered/wip rendered/wip

@ -30,10 +30,10 @@
{#if theme == 'dark'} {#if theme == 'dark'}
<span style="cursor: pointer;" on:click={ () => toggle() }> <span style="cursor: pointer;" on:click={ () => toggle() }>
<Icon name="sunrise" color={ dark_icon_color } tip_position="bottom-left" tooltip="Light mode." size="32" /> <Icon name="sun" color={ dark_icon_color } tip_position="bottom-left" tooltip="Light mode." size="32" />
</span> </span>
{:else} {:else}
<span style="cursor: pointer;" on:click={ () => toggle() }> <span style="cursor: pointer;" on:click={ () => toggle() }>
<Icon name="sunset" color={ light_icon_color } size="32" tip_position="bottom-left" tooltip="Dark mode."/> <Icon name="moon" color={ light_icon_color } size="32" tip_position="bottom-left" tooltip="Dark mode."/>
</span> </span>
{/if} {/if}

@ -11,6 +11,8 @@
export let pattern="dots-sm"; export let pattern="dots-sm";
export let height="100%"; export let height="100%";
export let width="100%"; export let width="100%";
export let icon_height="unset";
export let icon_width="unset";
export let thickness="2"; export let thickness="2";
export let testid=`iconimage-default-${name}`; export let testid=`iconimage-default-${name}`;
export let hue='blue'; export let hue='blue';
@ -33,16 +35,12 @@
align-content: center; align-content: center;
text-align: center; text-align: center;
} }
.feather {
width: 70%;
height: 70%;
}
</style> </style>
<div style="aspect-ratio: { aspect_ratio }; color: {pattern_color || random_pattern}; background-color: {background || random_background}; width: { width }; height: { height }; filter: grayscale({ grayscale });" data-testid={testid} class="pattern-{pattern} iconimage-container"> <div style="aspect-ratio: { aspect_ratio }; color: {pattern_color || random_pattern}; background-color: {background || random_background}; width: { width }; height: { height }; filter: grayscale({ grayscale });" data-testid={testid} class="pattern-{pattern} iconimage-container">
{#if name} {#if name}
<svg class="icon-{name} feather" <svg class="icon-{name}"
style="width: {icon_width}; height: {icon_height}"
fill="{fill_color}" fill="{fill_color}"
stroke="{color}" stroke="{color}"
stroke-width="{thickness}" stroke-width="{thickness}"

@ -2,7 +2,7 @@
import snarkdown from "snarkdown"; import snarkdown from "snarkdown";
export let content = "<b>Markdown:</b> No content? Forgot to #await?"; export let content = "<b>Markdown:</b> No content? Forgot to #await?";
export let with_p = true; export let with_p = false;
export let using = snarkdown; export let using = snarkdown;
const render = () => { const render = () => {

@ -13,7 +13,7 @@
} }
footer a { footer a {
color: var(--value9); color: var(--color-text-header);
} }
footer > column { footer > column {
@ -35,7 +35,7 @@
<footer> <footer>
<column> <column>
<a id="logo" style="color: var(--value9);" href="/">BIG CO</a> <a id="logo" href="/">LCTHW</a>
<p> <p>
BIG CO, a BIG CO, a
@ -52,7 +52,7 @@
<h5>COMPANY</h5> <h5>COMPANY</h5>
<ol> <ol>
<li><a href="/curriculum/">PRODUCT</a></li> <li><a href="/">PRODUCT</a></li>
<li><a href="/#pricing">PRICING</a></li> <li><a href="/#pricing">PRICING</a></li>
<li><a href="/client/#/login/">LOGIN</a></li> <li><a href="/client/#/login/">LOGIN</a></li>
<li><a href="mailto:{ support_email }">{ support_email }</a></li> <li><a href="mailto:{ support_email }">{ support_email }</a></li>
@ -64,7 +64,7 @@
<ol> <ol>
<li><a href="/client/#/live/">LIVE STREAMS</a></li> <li><a href="/client/#/live/">LIVE STREAMS</a></li>
<li><a href="/curriculum/">CURRICULUM</a></li> <li><a href="/">CURRICULUM</a></li>
<li><a href="/blog/">BLOG</a></li> <li><a href="/blog/">BLOG</a></li>
</ol> </ol>

@ -49,24 +49,24 @@
<header class:fixed> <header class:fixed>
<nav> <nav>
{#if $user.authenticated} {#if $user.authenticated}
<a href="/intro/" use:link id="logo">The Bandolier</a> <a href="/" use:link id="logo">The Bandolier</a>
<ul> <ul>
<li><a href="/" on:click|preventDefault={ logout_user } data-testid="logout-link"><Icon color="var(--value7)" name="log-out" tooltip="Log out."/></a></li> <li><a href="/" on:click|preventDefault={ logout_user } data-testid="logout-link"><Icon color="var(--value7)" name="log-out" tooltip="Log out."/></a></li>
<li><a data-testid="user-profile-button" href="/profile/" use:link><Icon color="var(--value7)" name="settings" tooltip="Settings."/></a></li> <li><a data-testid="user-profile-button" href="/profile/" use:link><Icon color="var(--value7)" name="settings" tooltip="Settings."/></a></li>
<li><a href="/feed.rss"><Icon color="var(--value7)" name="rss" tooltip="RSS Feed." tip_position="bottom-left" /></a></li> <li><a href="/feed.rss"><Icon color="var(--color-text-header)" name="rss" tooltip="RSS Feed." tip_position="bottom-left" /></a></li>
{#if $user.admin } {#if $user.admin }
<li><a href="/admin/#/"><Icon color="var(--value7)" name="keyboard" tooltip="Admin database."/></a></li> <li><a href="/admin/#/"><Icon color="var(--color-text-header)" name="keyboard" tooltip="Admin database."/></a></li>
{/if} {/if}
<li><Darkmode dark_icon_color="var(--value7)" light_icon_color="var(--value7)" /></li> <li><Darkmode dark_icon_color="var(--color-text-header)" light_icon_color="var(--color-text-header)" /></li>
</ul> </ul>
{:else} {:else}
<!-- don't use:link because we want them to go to the landing page if they aren't logged in. --> <!-- don't use:link because we want them to go to the landing page if they aren't logged in. -->
<a href="/intro/" use:link id="logo">The Bandolier</a> <a href="/" use:link id="logo">The Bandolier</a>
<ul> <ul>
{#if register_enabled} {#if register_enabled}
<li><a id="register-button" href="/client/#/register/"> <li><a id="register-button" href="/client/#/register/">
<span class="mobile"> <span class="mobile">
<Icon color="var(--value7)" name="dollar-sign" tooltip="Register."/> <Icon color="var(--color-text-header)" name="dollar-sign" tooltip="Register."/>
</span> </span>
<span class="mobile-hide"> <span class="mobile-hide">
@ -75,9 +75,10 @@
</a> </a>
</li> </li>
{/if} {/if}
<li><a href="/login/" use:link><Icon color="var(--value7)" name="log-in" tooltip="Log in." /></a></li> <li><a href="/login/" use:link><Icon color="var(--color-text-header)" name="log-in" tooltip="Log in." /></a></li>
<li><a href="/client/#/"><Icon color="var(--value7)" name="book" tooltip="Docs" /></a></li> <li><a href="/blog/"><Icon color="var(--color-text-header)" name="book" tooltip="Blog." /></a></li>
<li><Darkmode dark_icon_color="var(--value7)" light_icon_color="var(--value7)" /></li> <li><a href="/client/#/live/"><Icon color="var(--color-text-header)" name="video" tooltip="Livestreams." tip_position="bottom-left" /></a></li>
<li><Darkmode dark_icon_color="var(--color-text-header)" light_icon_color="var(--color-text-header)" /></li>
</ul> </ul>
{/if} {/if}
</nav> </nav>

@ -63,6 +63,7 @@ export const product_id = 1;
*/ */
export const base_host = 'http://127.0.0.1:5001'; export const base_host = 'http://127.0.0.1:5001';
export const og_base_host = "http://127.0.0.1:5001";
/* /*
Used in emails and pages to tell people who to email. Used in emails and pages to tell people who to email.
*/ */

@ -14,7 +14,7 @@
} }
footer a { footer a {
color: var(--value9); color: var(--color-text-header);
} }
footer > column { footer > column {
@ -36,7 +36,7 @@
<footer> <footer>
<column> <column>
<a id="logo" style="color: var(--value9);" href="/blockstart/demos/">LJSTHW</a> <a id="logo" href="/">LCTHW</a>
<p> <p>
BIG CO, a BIG CO, a
@ -53,7 +53,7 @@
<h5>COMPANY</h5> <h5>COMPANY</h5>
<ol> <ol>
<li><a href="/curriculum/">PRODUCT</a></li> <li><a href="/">PRODUCT</a></li>
<li><a href="/#pricing">PRICING</a></li> <li><a href="/#pricing">PRICING</a></li>
<li><a href="/client/#/login/">LOGIN</a></li> <li><a href="/client/#/login/">LOGIN</a></li>
<li><a href="mailto:help@learnjsthehardway.com">help@learnjsthehardway.com</a></li> <li><a href="mailto:help@learnjsthehardway.com">help@learnjsthehardway.com</a></li>
@ -65,7 +65,7 @@
<ol> <ol>
<li><a href="/client/#/live/">LIVE STREAMS</a></li> <li><a href="/client/#/live/">LIVE STREAMS</a></li>
<li><a href="/curriculum/">CURRICULUM</a></li> <li><a href="/">CURRICULUM</a></li>
<li><a href="/blog/">BLOG</a></li> <li><a href="/blog/">BLOG</a></li>
</ol> </ol>

@ -1,5 +1,8 @@
<script> <script>
import { logout_user } from '$/client/api.js';
import Icon from '$/client/components/Icon.svelte'; import Icon from '$/client/components/Icon.svelte';
import {link} from 'svelte-spa-router';
import { user } from "$/client/stores.js";
import Darkmode from '$/client/components/Darkmode.svelte'; import Darkmode from '$/client/components/Darkmode.svelte';
import { Hydrate } from '@jamcart/7ty/components'; import { Hydrate } from '@jamcart/7ty/components';
import { register_enabled } from "$/client/config.js"; import { register_enabled } from "$/client/config.js";
@ -8,33 +11,79 @@
</script> </script>
<style> <style>
img.logo { #logo {
width: 120px; font-family: fancy;
} font-size: 2em;
}
header {
background-color: var(--value0);
}
header a {
color: var(--value7);
}
nav {
background-color: var(--value0);
color: var(--value7);
}
nav * {
color: var(--value7);
}
@media only screen and (max-width: 600px) {
#logo {
font-size: 1.5em;
}
}
@media only screen and (max-width: 390px) {
#logo {
font-size: 1.4em;
}
}
</style> </style>
<header class:fixed> <header class:fixed>
<nav> <nav>
<a href="/"><img class="logo" src="/logo.svg" alt="LJSTHW" aria-label="LJSTHW" ></a> {#if $user.authenticated}
<ul> <a href="/" use:link id="logo">The Bandolier</a>
{#if register_enabled} <ul>
<li> <li><a href="/" on:click|preventDefault={ logout_user } data-testid="logout-link"><Icon color="var(--value7)" name="log-out" tooltip="Log out."/></a></li>
<a id="register-button" href="/client/#/register/"> <li><a data-testid="user-profile-button" href="/profile/" use:link><Icon color="var(--value7)" name="settings" tooltip="Settings."/></a></li>
<li><a href="/feed.rss"><Icon color="var(--value7)" name="rss" tooltip="RSS Feed." tip_position="bottom-left" /></a></li>
{#if $user.admin }
<li><a href="/admin/#/"><Icon color="var(--value7)" name="keyboard" tooltip="Admin database."/></a></li>
{/if}
</ul>
{:else}
<!-- don't use:link because we want them to go to the landing page if they aren't logged in. -->
<a href="/" use:link id="logo">The Bandolier</a>
<ul>
{#if register_enabled}
<li><a id="register-button" href="/client/#/register/">
<span class="mobile"> <span class="mobile">
<Icon name="dollar-sign" tooltip="Register." /> <Icon color="var(--value7)" name="dollar-sign" tooltip="Register."/>
</span> </span>
<span class="mobile-hide"> <span class="mobile-hide">
<button type="button">Register</button> <button type="button" class="inverted">Register</button>
</span> </span>
</a> </a>
</li> </li>
{/if} {/if}
<li><a href="/client/#/login/"><Icon name="log-in" tooltip="Log in."/></a></li> <li><a href="/login/" use:link><Icon color="var(--value7)" name="log-in" tooltip="Log in." /></a></li>
<li><a href="/blog/"><Icon name="book" tooltip="Blog posts." /></a></li> <li><a href="/blog/"><Icon color="var(--value7)" name="book" tooltip="Blog." /></a></li>
<li><a href="/client/#/live/"><Icon name="video" tooltip="Livestreams." tip_position="bottom-left" /></a></li> <li><a href="/client/#/live/"><Icon color="var(--value7)" name="video" tooltip="Livestreams." tip_position="bottom-left" /></a></li>
<li><a href="/feed.rss"><Icon name="rss" tooltip="RSS Feed." tip_position="bottom-left" /></a></li> <li><Hydrate
<li><Hydrate component={ Darkmode } /></li> component={ Darkmode }
</ul> props={{
light_icon_color: "var(--color-text-header)",
dark_icon_color: "var(--color-text-header)"}}/></li>
</ul>
{/if}
</nav> </nav>
</header> </header>

@ -1,216 +0,0 @@
<script>
import Layout from '../Layout.svelte';
import IconImage from '$/client/components/IconImage.svelte';
import { developer_admin } from "$/lib/api.js";
const components = [
{title: "Accordion", icon: "align-justify"},
{title: "AspectRatio", icon: "copy"},
{title: "Badge", icon: "award"},
{title: "ButtonGroup", icon: "server"},
{title: "Calendar", icon: "calendar"},
{title: "Callout", icon: "file-plus"},
{title: "Cards", icon: "credit-card"},
{title: "Carousel", icon: "repeat"},
{title: "Chat", icon: "message-circle"},
{title: "Code", icon: "code"},
{title: "Countdown", icon: "clock"},
{title: "Darkmode", icon: "sunrise"},
{title: "DataTable", icon: "grid"},
{title: "FairPay", icon: "dollar-sign"},
{title: "Flipper", icon: "layers"},
{title: "Form", icon: "database"},
{title: "Icon", icon: "feather"},
{title: "IconImage", icon: "image"},
{title: "LiveStream", icon: "cast"},
{title: "LoggedIn", icon: "log-out"},
{title: "Login", icon: "log-in"},
{title: "Markdown", icon: "file"},
{title: "Modal", icon: "maximize"},
{title: "Pagination", icon: "skip-forward"},
{title: "Progress", icon: "thermometer"},
{title: "Sidebar", icon: "sidebar"},
{title: "SnapImage", icon: "camera"},
{title: "Spinner", icon: "rotate-cw"},
{title: "StackLayer", icon: "layers"},
{title: "Switch", icon: "check-square"},
{title: "Tabs", icon: "folder"},
{title: "Tiles", icon: "camera"},
{title: "Toast", icon: "message-square"},
{title: "Tooltip", icon: "help-circle"},
{title: "Video", icon: "video"},
{title: "WTVideo", icon: "video"},
];
</script>
<style>
hero.middle {
border-radius: 0px 0px var(--border-radius) var(--border-radius);
}
callout.hero {
background: var(--color-bg-inverted);
color: var(--color-text-inverted);
border-radius: 10px 10px 0px 0px;
margin-bottom: 0px;
}
hero.main:hover {
filter: brightness(1.05);
}
hero > cover {
background: none;
color: black;
text-shadow: none;
opacity: 1;
}
main h2 {
text-align: center;
}
main {
font-size: 1.3em;
}
main hero.quote {
margin-left: -10px;
margin-right: -10px;
display: flex;
flex-direction: row;
}
span#slogan {
font-family: var(--font-computer);
font-size: 1.5em;
}
section {
margin-right: 2rem;
margin-left: 2rem;
font-size: 1.2em;
}
components {
display: grid;
grid-template-columns: repeat(6, 1fr);
}
components component {
background-color: var(--value0);
}
components component icon:hover {
opacity: 0.1;
}
components component name {
display: flex;
justify-content: center;
align-items: center;
color: var(--value8);
min-width: 150px;
}
@media only screen and (max-width: 900px) {
components {
grid-template-columns: repeat(4, 1fr);
}
}
@media only screen and (max-width: 600px) {
components {
grid-template-columns: repeat(3, 1fr);
}
}
</style>
<Layout bare={ true }>
<hero class="main">
<figure>
<img src="/images/header.svg" />
</figure>
<cover class="pattern-dots-sm">
<h1>Learn JavaScript the Hard Way</h1>
<span id="slogan">Bandolier</span>
<br/>
{#if developer_admin}
<a href="#components"><i>Browse The Components</i></a>
{/if}
</cover>
</hero>
<main>
<h2>A Collection of Learnable Components</h2>
<section>
<p>This is a collection of components that are both useable and learnable. Each component is feature complete, does what you need, but is small enough to understand in a day. You can start your project quickly, and alter them as you need, or replace them entirely if you outgrow them.</p>
<p>These aren't simple static user interface elements. They feature complex difficult to implement features such Video that adapts to HLS live streaming on all platforms, WebTorrent based video support, full feature mini chat, and Bitcoin Payments.</p>
<p>You'll also find various user interfaces found in other components, but with a simpler code base and CSS style that's easier to understand. Useful tools like Stacked Layers, Tabs, Data Tables, Sidebars, and Forms.</p>
</section>
<hero class="main quote">
<blockquote>
All of these components are extracted from real websites I created for real businesses or creative ideas. I also made copies of common components found in other UI component collections so <b>you</b> can learn how they're made.
</blockquote>
</hero>
<h2>The Components</h2>
<p>This list of components is constantly expanding as I work on new websites and extract things I created.</p>
{#if !developer_admin}
<callout id="needs-admin" class="info hero">
<span>
Set environment variable <code>DANGER_ADMIN=1</code> to view
components and use the Bandolier.
</span>
</callout>
{/if}
<components id="components">
{#each components as component}
<component class="stacked">
<name class="layer">
<b>{component.title}</b>
</name>
<icon class="layer">
<a href="{ developer_admin ? `/client/#/bando/components/${ component.title }` : "#needs-admin" }">
<IconImage name={ component.icon } pattern={ false }/>
</a>
</icon>
</component>
{/each}
</components>
<hero class="main quote">
<blockquote>
The "Bandolier" is a belt that holds all your ammo so you can quickly load them when you need to get something done.
</blockquote>
</hero>
<section>
<h2>Documentation</h2>
<p>Every component is fully documented with a complete code demo. No unrealistic abbreviated demos with missing code and settings. If you see the demo or component doing something you can view a tab to see he entire demo code with nothing hidden.
</p>
<h2>Getting Started</h2>
<p>You should have received access to the <a href="https://learnjsthehardway.com">Learn JavaScript the Hard Way</a> course which includes a full module on using this starter project. If you forgot how to forgot how to create your admin account:</p>
<p>After you've made your copy of the project you should <a href="/client/#/register/">register a fake account</a> and then use the <a href="/client/#/admin/table/user/">database admin</a> to give yourself admin. The database admin tool is only open when you've set <code>DANGER_ADMIN=1</code> on the command line, or if you're set as an admin.
</p>
</section>
</main>
</Layout>

@ -1,6 +1,7 @@
<script context="module"> <script context="module">
import markdown from "$/lib/blog.js"; import markdown from "$/lib/blog.js";
import OGPreview from "$/client/components/OGPreview.svelte"; import OGPreview from "$/client/components/OGPreview.svelte";
import Markdown from "$/client/components/Markdown.svelte";
export const getPaths = () => { export const getPaths = () => {
// slug has to be present here to match [slug] directory // slug has to be present here to match [slug] directory
@ -13,19 +14,19 @@
<script> <script>
import Layout from '$/rendered/Layout.svelte'; import Layout from '$/rendered/Layout.svelte';
import IconImage from "$/client/components/IconImage.svelte"; import IconImage from "$/client/components/IconImage.svelte";
import { base_host, twitter_user } from "$/client/config.js"; import { og_base_host, twitter_user } from "$/client/config.js";
export let metadata; export let metadata;
export let toc; export let toc;
export let content; export let content;
export let slug; export let slug;
let related = markdown.load("rendered/posts").slice(0, 5).map(p => p.metadata); let related = markdown.load("rendered/posts").slice(0, 4).map(p => p.metadata);
let og = { let og = {
"title": metadata.title, // title of the article "title": metadata.title, // title of the article
"description": metadata.summary, // description for inside preview "description": metadata.summary, // description for inside preview
"url": `${ base_host }/blog/${ metadata.slug }/`, // URL to article "url": `${ og_base_host }/blog/${ metadata.slug }/`, // URL to article
"type": "website", // not mentioned on linked in but needed "type": "website", // not mentioned on linked in but needed
} }
@ -38,7 +39,7 @@
} }
if(metadata.image) { if(metadata.image) {
og.image = `${base_host}/${metadata.image}`; og.image = `${og_base_host}/${metadata.image}`;
twitter.image = og.image; twitter.image = og.image;
} }
</script> </script>
@ -68,28 +69,66 @@
} }
hero cover { hero cover {
font-size: 2vw; padding: 1rem;
font-size: clamp(1.5em, 2vw, 2em);
}
:global(content > h1) {
margin-top: 2rem;
margin-bottom: 2rem;
}
content info {
display: flex;
flex-direction: column;
gap: 1rem;
margin-top: 1rem;
} }
posts { posts {
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(2, 1fr);
gap: 1rem;
max-width: var(--width-content);
margin-bottom: 1rem;
} }
posts post { posts card {
background-color: var(--value0); border: unset;
border-radius: unset;
} }
posts post icon:hover { posts card top {
opacity: 0.1; max-height: 250px;
} }
posts post name { posts card middle {
padding: 1rem;
}
posts card bottom {
padding: 0.5rem;
}
tags {
display: flex; display: flex;
justify-content: center; margin-top: 1rem;
align-items: center; justify-content: space-between;
color: var(--value8); }
min-width: 150px;
tags tag {
border-radius: 20px;
background-color: var(--value7);
color: var(--value3);
font-size: 0.8em;
padding-left: 0.3rem;
padding-right: 0.3rem;
}
tags info {
font-size: 0.8em;
color: var(--value3);
} }
@media only screen and (min-width: 1285px) { @media only screen and (min-width: 1285px) {
@ -109,6 +148,17 @@
font-size: 1.2rem; font-size: 1.2rem;
flex-direction: column; flex-direction: column;
} }
posts {
max-width: 90vw;
}
}
@media only screen and (max-width: 700px) {
posts {
grid-template-columns: repeat(1, 1fr);
}
} }
@ -120,45 +170,61 @@
<img src={ metadata.image } /> <img src={ metadata.image } />
{:else if metadata.icon} {:else if metadata.icon}
<div> <div>
<IconImage name={ metadata.icon} /> <IconImage name={ metadata.icon} aspect_ratio="16/9" icon_height="70%" icon_width="70%" />
</div> </div>
{/if} {/if}
<cover> <cover>
<h1>{ metadata.title }</h1> <h1>
<Markdown content={ metadata.title } />
</h1>
{#if metadata.summary } {#if metadata.summary }
<span id="slogan">{ metadata.summary }</span> <span id="slogan">
<Markdown content={ metadata.summary } />
</span>
{/if} {/if}
<br/> <br/>
</cover> </cover>
</hero> </hero>
<content> <content>
<info>
<author>
{#if metadata.repost}
<b>Reposted from</b>
<a href={metadata.repost.link}>{metadata.repost.title}</a>
{/if}
<b>By</b> { metadata.author }
</author>
</info>
{@html content} {@html content}
<hr>
<h6>More from Learn Code the Hard Way</h6>
</content> </content>
<posts> <posts>
{#each related as post} {#each related as post}
<post class="stacked"> <card class="stacked">
<name class="layer"> <top>
<b>{post.title}</b> <a href="/blog/{ post.slug }/">
</name> <IconImage name={ post.icon } pattern={ false } aspect_ratio="16/9" />
<icon class="layer">
<a href="/blog/{ post.slug }/">
<IconImage name={ post.icon } pattern={ false }/>
</a>
</icon>
</post>
{/each}
<post class="stacked">
<name class="layer">
<b>See More...</b>
</name>
<icon class="layer">
<a href="/">
<IconImage name="home" pattern={ false }/>
</a> </a>
</icon> </top>
</post> <middle>
<h4><a href="/blog/{post.slug}/">{post.title}</a></h4>
<p>{ post.summary }</p>
</middle>
<bottom>
<tags>
<tag>{ post.tag }</tag>
<info><a href="/blog/{post.slug}/">Published { post.date }</a><info>
</tags>
</bottom>
</card>
{/each}
</posts> </posts>
</Layout> </Layout>

@ -3,6 +3,7 @@
import IconImage from '$/client/components/IconImage.svelte'; import IconImage from '$/client/components/IconImage.svelte';
import Icon from '$/client/components/Icon.svelte'; import Icon from '$/client/components/Icon.svelte';
import markdown from "$/lib/blog.js"; import markdown from "$/lib/blog.js";
import Markdown from "$/client/components/Markdown.svelte";
const posts = markdown.load("rendered/posts"); const posts = markdown.load("rendered/posts");
@ -21,68 +22,121 @@
padding: 3rem; padding: 3rem;
} }
posts card middle { posts tile {
height: 100%; border: none;
flex-direction: row-reverse;
}
posts tile left {
--aspect-ratio: 1/1;
--width: 200px;
--height: unset;
width: var(--width);
min-width: var(--width);
max-width: var(--width);
} }
posts card bottom { posts tile middle {
padding-right: 2rem;
}
tags {
display: flex; display: flex;
flex-direction: row-reverse; margin-top: 1rem;
min-height: min-content; justify-content: space-between;
}
tags tag {
border-radius: 20px;
background-color: var(--value7);
color: var(--value3);
font-size: 0.8em;
padding-left: 0.3rem;
padding-right: 0.3rem;
align-self: center;
max-height: fit-content;
}
tags info {
font-size: 0.8em;
color: var(--value3);
}
posts > hr {
margin-top: 2rem;
margin-bottom: 2rem;
} }
posts { posts {
display: grid; margin-top: 2rem;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto;
grid-gap: 1rem;
} }
@media only screen and (min-width: 1600px) { h1.title {
posts { margin-top: 2rem;
grid-template-columns: repeat(4, 1fr); margin-bottom: 1rem;
}
} }
@media only screen and (max-width: 1100px) { @media only screen and (max-width: 900px) {
main {
overflow: auto;
padding-left: 0.5rem;
padding-right: 0.5rem;
font-size: 1.2rem;
}
posts { posts {
grid-template-columns: repeat(2, 1fr); max-width: 90vw;
} }
} }
@media only screen and (max-width: 800px) {
posts { @media only screen and (max-width: 700px) {
grid-template-columns: repeat(1, 1fr); posts tile {
flex-direction: column;
} }
main { posts tile left {
font-size: 1.3em; --aspect-ratio: unset;
padding: 1rem; --height: 200px;
--width: calc(100vw - 3rem);
margin-bottom: 1rem;
} }
} }
</style> </style>
<Layout bare={ true }> <Layout bare={ true }>
<main> <main>
<posts> <h1 class="title">How To Make A Post</h1>
{#each posts as post} <p>Create a .md file in <code>rendered/posts/</code> and it'll show up here. Look at <code>rendered/posts/01-sample.md</code> for an example header.</p>
<card> <posts>
<top> {#each posts as post}
<a href="/blog/{ post.metadata.slug }/"> <hr>
<IconImage name={ post.metadata.icon } pattern={ false }/> <tile>
</a> <left>
</top> <a href="/blog/{ post.metadata.slug }/">
<middle> <IconImage aspect_ratio="var(--aspect-ratio)" name={ post.metadata.icon } width="var(--width)" height="var(--height)"/>
<h4>{post.metadata.title}</h4> </a>
<p>{ post.metadata.summary }</p> </left>
</middle> <middle>
<bottom> <h4><a class="bare" href="/blog/{ post.metadata.slug }/"><Markdown content={post.metadata.title} /></a></h4>
<button> <p>
<a href="/blog/{ post.metadata.slug }/"><Icon name="arrow-right" light={true} /></a> <Markdown content={ post.metadata.summary } />
</button> </p>
</bottom>
</card> <tags>
{/each} <tag>{ post.metadata.tag }</tag>
{#if post.metadata.repost}
<info><b>Reposted</b> from
<a class="bare" href={post.metadata.repost.link}><Markdown content={post.metadata.repost.title} /></a>
</info>
{:else}
<info>Published <b>{ post.metadata.date }</b></info>
{/if}
</tags>
</middle>
</tile>
{/each}
</posts> </posts>
</main> </main>
</Layout> </Layout>

@ -1,13 +1,13 @@
<script> <script>
import Layout from "$/rendered/Layout.svelte"; import Layout from "$/rendered/Layout.svelte";
import OGPreview from "$/client/components/OGPreview.svelte"; import OGPreview from "$/client/components/OGPreview.svelte";
import { base_host } from "$/client/config.js"; import { og_base_host } from "$/client/config.js";
let og = { let og = {
"title": "LJSTHW OG Card Test", // title of the article "title": "LJSTHW OG Card Test", // title of the article
"description": "A simple test of the OG style of sharing cards.", // description for inside preview "description": "A simple test of the OG style of sharing cards.", // description for inside preview
"image": `${ base_host }/images/zed.png`, // image to display, 5mb/1200/627 max "image": `${ og_base_host }/images/zed.png`, // image to display, 5mb/1200/627 max
"url": `${ base_host }/test_large_card.html`, // URL to article "url": `${ og_base_host }/test_large_card.html`, // URL to article
"type": "website", // not mentioned on linked in but needed "type": "website", // not mentioned on linked in but needed
} }

@ -1,13 +1,13 @@
<script> <script>
import Layout from "$/rendered/Layout.svelte"; import Layout from "$/rendered/Layout.svelte";
import OGPreview from "$/client/components/OGPreview.svelte"; import OGPreview from "$/client/components/OGPreview.svelte";
import { base_host } from "$/client/config.js"; import { og_base_host } from "$/client/config.js";
let og = { let og = {
"title": "LJSTHW OG Card Test", // title of the article "title": "LJSTHW OG Card Test", // title of the article
"description": "A simple test of the OG style of sharing cards.", // description for inside preview "description": "A simple test of the OG style of sharing cards.", // description for inside preview
"image": `${ base_host }/images/zed.png`, // image to display, 5mb/1200/627 max "image": `${ og_base_host }/images/zed.png`, // image to display, 5mb/1200/627 max
"url": `${ base_host }/test_og_card.html`, // URL to article "url": `${ og_base_host }/test_og_card.html`, // URL to article
"type": "website", // not mentioned on linked in but needed "type": "website", // not mentioned on linked in but needed
} }

@ -2,7 +2,7 @@
import Layout from "$/rendered/Layout.svelte"; import Layout from "$/rendered/Layout.svelte";
import OGPreview from "$/client/components/OGPreview.svelte"; import OGPreview from "$/client/components/OGPreview.svelte";
import { Hydrate } from '@jamcart/7ty/components'; import { Hydrate } from '@jamcart/7ty/components';
import { base_host } from "$/client/config.js"; import { og_base_host, base_host } from "$/client/config.js";
import Video from "$/client/components/Video.svelte"; import Video from "$/client/components/Video.svelte";
let source = "/videos/sample.mp4"; let source = "/videos/sample.mp4";
let poster = "/images/sample.jpg"; let poster = "/images/sample.jpg";
@ -18,7 +18,7 @@
"title": "LJSTHW OG/Twitter Video Test", // title of the article "title": "LJSTHW OG/Twitter Video Test", // title of the article
"description": "A simple test of the OG/Twitter style of sharing cards with video.", // description for inside preview "description": "A simple test of the OG/Twitter style of sharing cards with video.", // description for inside preview
"image": poster, // image to display, 5mb/1200/627 max "image": poster, // image to display, 5mb/1200/627 max
"url": `${ base_host }/test_video_card.html`, // URL to article "url": `${ og_base_host }/test_video_card.html`, // URL to article
"type": "website", // not mentioned on linked in but needed "type": "website", // not mentioned on linked in but needed
} }
@ -30,7 +30,7 @@
"image:alt": "A drawing of Zed by Zed.", // max 420 chars image alt "image:alt": "A drawing of Zed by Zed.", // max 420 chars image alt
"site": "@lzsthw", // @username of site "site": "@lzsthw", // @username of site
"title": og.title, "title": og.title,
"player": `${ base_host }/video_container.html`, "player": `${ og_base_host }/video_container.html`,
"player:width": "1280", "player:width": "1280",
"player:height": "720" "player:height": "720"
} }

@ -0,0 +1,14 @@
{
"author": "Zed A. Shaw",
"date": "May 11, 2023",
"has_image": false,
"icon": "help-circle",
"tag": "Announcement",
"summary": "Sample post."
}
------
# Sample Title
You can use other header features.

@ -3,7 +3,6 @@
<head> <head>
<meta charset='utf-8'> <meta charset='utf-8'>
<meta name="description" content="The Bandoler Admin"> <meta name="description" content="The Bandoler Admin">
<meta name="description" content="The Bandolier: A Learn JavaScript the Hard Way Project">
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type' /> <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
<title>The Bandolier Admin</title> <title>The Bandolier Admin</title>

@ -31,7 +31,7 @@
--gray-bg: hsl(0, 0%, 92%); --gray-bg: hsl(0, 0%, 92%);
--border-radius: 5px; --border-radius: 5px;
--box-shadow: 0 2px 2px; --box-shadow: -2px -2px 4px;
--color: var(--value0); --color: var(--value0);
--color-accent: var(--value1); --color-accent: var(--value1);
--color-icon-image: var(--value1); --color-icon-image: var(--value1);
@ -68,7 +68,7 @@
--color-pulse-3: hsla(0, 0%, 53%, 0.1); --color-pulse-3: hsla(0, 0%, 53%, 0.1);
--color-pulse-4: hsla(0, 0%, 53%, 0); --color-pulse-4: hsla(0, 0%, 53%, 0);
--font-family: "Andale Mono", "Monaco", monospace, monospace; --font-family: "Andale Mono", "Monaco", monospace, monospace;
--font-computer: computer, monospace, monospace; --font-title: "Palatino", serif;
--font-size: 1.05em; --font-size: 1.05em;
--font-text-size: 1.4em; /* for paragraphs mostly */ --font-text-size: 1.4em; /* for paragraphs mostly */
--font-heading-size: 1.2em; --font-heading-size: 1.2em;
@ -90,6 +90,9 @@
--fixed-footer-height: 400px; --fixed-footer-height: 400px;
--color-scrollbar-thumb: hsla(0, 0%, 30%, 0.3); --color-scrollbar-thumb: hsla(0, 0%, 30%, 0.3);
--color-scrollbar-track-piece: hsla(0, 0%, 50%, 0.2); --color-scrollbar-track-piece: hsla(0, 0%, 50%, 0.2);
--color-bg-header: var(--dark-blue);
--color-text-header: var(--value8);
} }
[data-theme="dark"] { [data-theme="dark"] {

@ -57,7 +57,8 @@ body {
} }
header { header {
background-color: var(--color-bg); background-color: var(--color-bg-header);
color: var(--color-text-header);
display: flex; display: flex;
justify-content: center; justify-content: center;
text-align: var(--justify-important); text-align: var(--justify-important);
@ -94,7 +95,8 @@ header.fixed + main {
} }
footer { footer {
background-color: var(--color-bg-tertiary); background-color: var(--color-bg-header);
color: var(--color-text-header);
padding: 0px; padding: 0px;
width: 100%; width: 100%;
display: flex; display: flex;
@ -268,7 +270,7 @@ h4,
h5, h5,
h6 { h6 {
line-height: var(--line-height); line-height: var(--line-height);
font-family: var(--font-computer); font-family: var(--font-title);
font-weight: var(--font-heading-weight); font-weight: var(--font-heading-weight);
font-size: var(--font-heading-size); font-size: var(--font-heading-size);
margin-top: 1rem; margin-top: 1rem;
@ -954,21 +956,25 @@ callout a:hover {
callout.alert { callout.alert {
color: var(--invert-red); color: var(--invert-red);
text-shadow: var(--value1) 1px 1px;
background-color: var(--color-error); background-color: var(--color-error);
} }
callout.error { callout.error {
color: var(--invert-red); color: var(--invert-red);
text-shadow: var(--value1) 1px 1px;
background-color: var(--color-error); background-color: var(--color-error);
} }
callout.success { callout.success {
color: var(--invert-green); color: var(--invert-green);
text-shadow: var(--value1) 1px 1px;
background-color: var(--color-good); background-color: var(--color-good);
} }
callout.warning { callout.warning {
color: var(--invert-orange); color: var(--invert-orange);
text-shadow: var(--value1) 1px 1px;
background-color: var(--color-warning); background-color: var(--color-warning);
} }
@ -977,6 +983,10 @@ callout.info {
background-color: var(--color-info); background-color: var(--color-info);
} }
callout.info a {
color: var(--invert-yellow);
}
/* Use this around words you want to tooltip. */ /* Use this around words you want to tooltip. */
word { word {
position: relative; position: relative;
@ -1489,7 +1499,6 @@ grid {
grid-template-rows: var(--rows); grid-template-rows: var(--rows);
} }
#register-button { #register-button {
align-self: baseline; align-self: baseline;
position: relative; position: relative;
@ -1499,9 +1508,9 @@ grid {
#register-button button { #register-button button {
font-size: 0.9em; font-size: 0.9em;
background-color: unset; background-color: unset;
color: var(--value7); color: var(--color-text-header);
padding: 3px; padding: 3px;
border: 2px solid var(--value7); border: 2px solid var(--color-text-header);
} }
#register-button:hover button { #register-button:hover button {
@ -1543,3 +1552,14 @@ grid {
overflow-y: initial; overflow-y: initial;
} }
} }
a.bare em,
a.bare i
{
border: unset;
border-radius: unset;
display: unset;
font-weight: unset;
line-height: unset;
padding: unset;
}

File diff suppressed because it is too large Load Diff

@ -65,6 +65,8 @@
"static/icons/stop-circle.svg", "static/icons/stop-circle.svg",
"static/icons/sunrise.svg", "static/icons/sunrise.svg",
"static/icons/sunset.svg", "static/icons/sunset.svg",
"static/icons/sun.svg",
"static/icons/moon.svg",
"static/icons/trash.svg", "static/icons/trash.svg",
"static/icons/user.svg", "static/icons/user.svg",
"static/icons/video-off.svg", "static/icons/video-off.svg",

Loading…
Cancel
Save