Skip to content

Commit

Permalink
feat(blog): Set up the basic blog post space
Browse files Browse the repository at this point in the history
  • Loading branch information
Marko OLEKSIYENKO committed Sep 12, 2023
1 parent b6866f0 commit 469aa9c
Show file tree
Hide file tree
Showing 11 changed files with 267 additions and 86 deletions.
13 changes: 12 additions & 1 deletion demo/src/lib/layout/Code.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<script lang="ts">
import Svg from '$lib/layout/Svg.svelte';
import {tooltip} from '$lib/tooltip/tooltip';
import clipboard from 'bootstrap-icons/icons/clipboard.svg?raw';
import './code.scss';
import hljs, {languageFromFileName} from './highlight';
Expand All @@ -12,10 +15,18 @@
$: formattedCode = appliedLanguage ? hljs.highlight(code, {language: appliedLanguage}).value : null;
</script>

<div class={`bg-light-subtle ${className}`}>
<div class={`d-flex bg-light-subtle ${className}`}>
<pre class="mb-0"><code bind:this={container}
>{#if formattedCode != null}<!-- eslint-disable-line svelte/no-at-html-tags -->{@html formattedCode}{:else}{code}{/if}</code
></pre>
<div class="ms-auto">
<button
class="btn"
aria-label="copy to clipboard"
use:tooltip={{content: 'Copy to clipboard'}}
on:click={() => navigator.clipboard.writeText(code)}><Svg className={`align-middle icon-20`} svg={clipboard} /></button
>
</div>
</div>

<style lang="scss">
Expand Down
8 changes: 0 additions & 8 deletions demo/src/lib/layout/Sample.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,6 @@
<button class="nav-link" class:active={selectedFileName === file} on:click={() => (selectedFileName = file)}>{file}</button>
</li>
{/each}
<li class="ms-auto">
<button
class="btn"
aria-label="copy to clipboard"
use:tooltip={{content: 'Copy to clipboard'}}
on:click={() => navigator.clipboard.writeText(code)}><Svg className={`align-middle icon-20`} svg={clipboard} /></button
>
</li>
</ul>
<div class="border border-top-0">
<Lazy component={() => import('./Code.svelte')} {code} fileName={selectedFileName} className="py-3 px-2 px-sm-4 code-sample">
Expand Down
97 changes: 97 additions & 0 deletions demo/src/lib/layout/TableOfContents.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<script lang="ts">
export let visibleElements$: any;
export let elements$: any;
function getElementProperties(visibleElements$: any, element: HTMLElement, isVisible: boolean) {
const header = element.querySelector('h1,h2,h3') as HTMLElement;
if (header) {
const classnames = [`toc-link d-inline-block toc-${header.tagName.toLowerCase()}`];
const firstSubSection = element.querySelector('section');
if ((firstSubSection && visibleElements$().has(firstSubSection)) || (!firstSubSection && isVisible)) {
classnames.push('active');
}
return {
label: header.innerText,
href: header.querySelector('a')?.getAttribute('href') ?? '',
classname: classnames.join(' '),
};
} else {
return {
label: '',
href: '',
classname: '',
};
}
}
</script>

<div class="demo-toc col-auto d-none d-lg-flex">
{#if $elements$.length}
<div class="toc-content ms-2 border-start-1">
<div class="toc-title fw-bold pb-2 mb-1">On this page</div>
<ul class="list-unstyled mb-0 pb-0 pb-md-2 pe-lg-2 main-nav-list small">
{#each $elements$ as element}
{@const isVisible = $visibleElements$.has(element)}
{@const {label, classname, href} = getElementProperties(visibleElements$, element, isVisible)}
<li>
<a class={classname} aria-current={isVisible ? 'page' : undefined} {href}>
{label}
</a>
</li>
{/each}
</ul>
</div>
{/if}
</div>

<style lang="scss">
@import '../../../../common/variables';
.main-nav-list {
@include media-breakpoint-down(md) {
display: flex;
flex-direction: row;
justify-content: space-evenly;
}
}
@include media-breakpoint-up(md) {
.demo-toc {
position: sticky;
top: 0;
display: block !important;
height: calc(100vh - 6rem);
overflow-y: auto;
}
}
.toc {
&-link:hover,
&-link:focus {
color: var(--bs-emphasis-color);
background-color: var(--demo-sidebar-link-bg);
}
&-link {
padding: 0.1875rem 0.5rem;
color: var(--bs-body-color);
text-decoration: none;
border-left: 3px solid transparent;
transition: border-color 0.25s;
&.active {
color: var(--bs-emphasis-color);
border-left-color: var(--bs-primary);
transition: none;
}
}
&-h2 {
padding-left: 0.5rem;
}
&-h3 {
padding-left: 1rem;
}
}
</style>
79 changes: 2 additions & 77 deletions demo/src/routes/[framework]/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,9 @@
import 'bootstrap/dist/css/bootstrap.css';
import {pathToRoot$, selectedFramework$, intersectionApi} from '../../lib/stores';
import {menu} from '../navigation';
import TableOfContents from '$lib/layout/TableOfContents.svelte';
const {elements$, visibleElements$} = intersectionApi;
function getElementProperties(element: HTMLElement, isVisible: boolean) {
const header = element.querySelector('h1,h2,h3') as HTMLElement;
if (header) {
const classnames = [`toc-link d-inline-block toc-${header.tagName.toLowerCase()}`];
const firstSubSection = element.querySelector('section');
if ((firstSubSection && visibleElements$().has(firstSubSection)) || (!firstSubSection && isVisible)) {
classnames.push('active');
}
return {
label: header.innerText,
href: header.querySelector('a')?.getAttribute('href') ?? '',
classname: classnames.join(' '),
};
} else {
return {
label: '',
href: '',
classname: '',
};
}
}
</script>

<div class="demo-layout row">
Expand Down Expand Up @@ -60,24 +38,7 @@
<div class="pb-4 col">
<slot />
</div>
<div class="demo-toc col-auto d-none d-lg-flex">
{#if $elements$.length}
<div class="toc-content ms-2 border-start-1">
<div class="toc-title fw-bold pb-2 mb-1">On this page</div>
<ul class="list-unstyled mb-0 pb-0 pb-md-2 pe-lg-2 main-nav-list small">
{#each $elements$ as element}
{@const isVisible = $visibleElements$.has(element)}
{@const {label, classname, href} = getElementProperties(element, isVisible)}
<li>
<a class={classname} aria-current={isVisible ? 'page' : undefined} {href}>
{label}
</a>
</li>
{/each}
</ul>
</div>
{/if}
</div>
<TableOfContents {visibleElements$} {elements$} />
</div>

<style lang="scss">
Expand All @@ -98,41 +59,5 @@
height: calc(100vh - 6rem);
overflow-y: auto;
}
.demo-toc {
position: sticky;
top: 0;
display: block !important;
height: calc(100vh - 6rem);
overflow-y: auto;
}
}
.toc {
&-link:hover,
&-link:focus {
color: var(--bs-emphasis-color);
background-color: var(--demo-sidebar-link-bg);
}
&-link {
padding: 0.1875rem 0.5rem;
color: var(--bs-body-color);
text-decoration: none;
border-left: 3px solid transparent;
transition: border-color 0.25s;
&.active {
color: var(--bs-emphasis-color);
border-left-color: var(--bs-primary);
transition: none;
}
}
&-h2 {
padding-left: 0.5rem;
}
&-h3 {
padding-left: 1rem;
}
}
</style>
24 changes: 24 additions & 0 deletions demo/src/routes/blog/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script lang="ts">
import BlogPreview from './blog-preview.svelte';
import type {BlogPost} from './blog.model';
import Latest from './latest.svelte';
let blogs: BlogPost[] = [
{
header: 'Blog post header 1',
shortDescription: 'Short blog post description with catchy phrases 1',
author: 'Author',
publishDate: '09-11-2023',
href: '/blog/blog-pages/dd-mm-yyyy-template',
},
];
</script>

<Latest blogPost={blogs[blogs.length - 1]} />
<div class="row">
{#each blogs as blog}
<div class="col-4 mb-5">
<BlogPreview blogPost={blog} />
</div>
{/each}
</div>
64 changes: 64 additions & 0 deletions demo/src/routes/blog/blog-pages/yyyy-mm-dd-template/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<script lang="ts">
import Code from '$lib/layout/Code.svelte';
import Section from '$lib/layout/Section.svelte';
import TableOfContents from '$lib/layout/TableOfContents.svelte';
import {intersectionApi} from '$lib/stores';
import {onMount} from 'svelte';
let code = `import { Component } from '@angular/core';
import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap';
@Component({
selector: 'df-demo-accordion-basic',
templateUrl: './accordion-basic.html',
standalone: true,
imports: [NgbAccordionModule]
})
export class NgbdAccordionBasic {}`;
const {elements$, visibleElements$} = intersectionApi;
let container: HTMLElement;
// needed to update the table of contents with scrollspy behavior
onMount(() => {
intersectionApi.patch({
elements: [...container.querySelectorAll('section')] as HTMLElement[],
});
});
</script>

<svelte:head>
<title>Blog post example</title>
<meta name="description" content="Blog post example" />
</svelte:head>

<div class="d-flex demo-layout flex-row mt-3 align-items-baseline" bind:this={container}>
<div class="col-10 mx-auto">
<Section label="Loram Ipsum" id="lorem-ipsum" level={2}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas lobortis dolor quis dui condimentum, ut pharetra velit lobortis. Mauris a
elementum metus. Sed lacinia nisi eu diam venenatis porttitor. Morbi arcu nunc, efficitur vitae sem sed, commodo pulvinar tellus. Donec eu ipsum
consequat, mollis nibh at, pharetra tortor. Fusce sit amet lacus ac mi bibendum molestie a sed ante. In quis justo lorem. Phasellus placerat,
dolor at eleifend iaculis, lorem augue vestibulum risus, a fermentum libero augue vitae sem. Quisque porta turpis nec fermentum consequat.
Suspendisse vel molestie est. Aliquam mollis, nibh a iaculis sollicitudin, massa eros pulvinar massa, in rhoncus lectus nisl at nisi.
Suspendisse euismod vulputate turpis vitae tristique. Aenean tincidunt enim quis ante pellentesque imperdiet.

<Code {code} className="py-3 px-2 px-sm-4 code-sample" />
</Section>

<Section label="Nullam Enim" id="nullam-enim" level={2}>
Quisque molestie lacinia justo eget pharetra. Phasellus et metus mattis libero consequat vestibulum. Nam vitae dignissim sem, eu egestas libero.
Quisque fringilla quis ex vitae auctor. Nullam enim mi, posuere nec tempus a, tristique vel nisi. Nulla volutpat turpis eget turpis tempor
scelerisque. Nunc nec vehicula elit, at molestie nisi.
</Section>

<Section label="Vehicula Felis" id="vehicula-felis" level={2}>
In a ante vehicula felis ullamcorper sagittis. Sed dignissim mi sit amet magna vulputate rutrum. Donec pretium rhoncus posuere. Sed sit amet
erat quam. Mauris eu nulla pharetra, malesuada quam non, vestibulum erat. Sed malesuada elit eu tellus elementum, quis congue dui lacinia. Donec
facilisis erat purus, nec ornare sapien aliquet eget. Aliquam erat volutpat. Duis a eros magna. Donec varius neque non dignissim feugiat. Nullam
pellentesque egestas tempor. Maecenas accumsan turpis est, eu efficitur ex tempor posuere. Nam interdum aliquam nibh, eu ultrices velit pharetra
in. Etiam vitae urna hendrerit nisi ornare imperdiet eget in nisl.
</Section>
</div>

<TableOfContents {visibleElements$} {elements$} />
</div>
22 changes: 22 additions & 0 deletions demo/src/routes/blog/blog-preview.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script lang="ts">
import './blog-styling.scss';
import type {BlogPost} from './blog.model';
export let blogPost: BlogPost;
</script>

<div class="d-flex flex-column">
<div>
<a class="blog-link" href={blogPost.href} aria-label="link to blog post" title="BlogPost">
<img class="blog-preview" src="blog_placeholder.png" alt="Blog placeholder" />
<div>
<h1>{blogPost.header}</h1>
{blogPost.shortDescription}
</div>
</a>
</div>
<div>
{blogPost.author}
{blogPost.publishDate}
</div>
</div>
13 changes: 13 additions & 0 deletions demo/src/routes/blog/blog-styling.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.blog-preview {
width: 100%;
object-fit: contain;
}

a.blog-link {
color: inherit !important;
text-decoration: none !important;
}

img {
border: 1px solid gray;
}
7 changes: 7 additions & 0 deletions demo/src/routes/blog/blog.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface BlogPost {
header: string;
shortDescription: string;
author: string;
publishDate: string;
href: string;
}
Loading

0 comments on commit 469aa9c

Please sign in to comment.