kopia lustrzana https://github.com/learn-awesome/learndb
masonry layout works
rodzic
61cecff6cc
commit
ea86eef1f3
|
@ -3,4 +3,8 @@ physics,Physics
|
|||
mathematics,Maths,,physics,
|
||||
language.english,English
|
||||
programming.java,Java,,,,
|
||||
history,History,,language.english,
|
||||
history,History,,language.english,
|
||||
programming.java,Ruby,,,,
|
||||
programming.java,Rust,,,,
|
||||
programming.java,JS,,,,
|
||||
programming.java,Golang,,,,
|
|
BIN
learn.db
BIN
learn.db
Plik binarny nie jest wyświetlany.
|
@ -1,34 +1,29 @@
|
|||
<script>
|
||||
let dataPromise = getData();
|
||||
async function getData() {
|
||||
const res = await fetch(`/learn.json?_shape=array&sql=select+distinct(substr(links%2C1%2Cinstr(links%2C'|')-1))+as+name+from+items`)
|
||||
if(res.ok){
|
||||
return await res.json();
|
||||
} else {
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
{#await dataPromise}
|
||||
<p>Fetching data...</p>
|
||||
{:then formats}
|
||||
<div class="max-w-lg mx-auto grid gap-5 lg:grid-cols-3 lg:max-w-none">
|
||||
|
||||
<div class="mt-6" style="columns: 6 240px; column-gap: 1rem;">
|
||||
{#each formats as format}
|
||||
<div tabindex="0" class="inline-block w-full mt-4 bg-white rounded-lg mt-4 px-4 py-4 shadow-lg focus:outline-none">
|
||||
<a href="#/format/{format.name}"><h4 class="mt-1 p-1 text-gray-900 font-semibold text-lg">{ format.name }</h4></a>
|
||||
|
||||
<div class="mt-2 flex flex-wrap text-sm text-gray-900">
|
||||
</div>
|
||||
|
||||
<p class="mt-2 text-sm text-right"><span>and 37 more.</span></p>
|
||||
|
||||
<a href="#/format/podcast" class="flex flex-col rounded-lg shadow-lg overflow-hidden transform transition ease-out duration-300 hover:scale-105 hover:shadow-xl">
|
||||
<div class="flex-shrink-0">
|
||||
<img class="h-48 w-full object-cover" src="https://images.unsplash.com/photo-1496128858413-b36217c2ce36?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1679&q=80" alt="">
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<h1 class="text-2xl font-bold p-2 bg-indigo-500 text-white">Podcasts</h1>
|
||||
</a>
|
||||
|
||||
{:catch error}
|
||||
<p>{error.message}</p>
|
||||
{/await}
|
||||
<a href="#/format/book" class="flex flex-col rounded-lg shadow-lg overflow-hidden transform transition ease-out duration-300 hover:scale-105 hover:shadow-xl">
|
||||
<div class="flex-shrink-0">
|
||||
<img class="h-48 w-full object-cover" src="https://images.unsplash.com/photo-1547586696-ea22b4d4235d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1679&q=80" alt="">
|
||||
</div>
|
||||
<h1 class="text-2xl font-bold p-2 bg-indigo-500 text-white">Books</h1>
|
||||
</a>
|
||||
|
||||
<a href="#/format/video" class="flex flex-col rounded-lg shadow-lg overflow-hidden transform transition ease-out duration-300 hover:scale-105 hover:shadow-xl">
|
||||
<div class="flex-shrink-0">
|
||||
<img class="h-48 w-full object-cover" src="https://images.unsplash.com/photo-1492724441997-5dc865305da7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1679&q=80" alt="">
|
||||
</div>
|
||||
<h1 class="text-2xl font-bold p-2 bg-indigo-500 text-white">Videos</h1>
|
||||
</a>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,136 @@
|
|||
<!--
|
||||
From https://svelte.dev/repl/d5ff70834832498882d1570b9355561e?version=3.24.1
|
||||
An almost direct copy and paste of: https://css-tricks.com/a-lightweight-masonry-solution
|
||||
Usage:
|
||||
- stretchFirst stretches the first item across the top
|
||||
<Masonry stretchFirst={true} >
|
||||
{#each data as o}
|
||||
<div class="_card _padding">
|
||||
Here's some stuff {o.name}
|
||||
<header>
|
||||
<h3>{o.name}</h3>
|
||||
</header>
|
||||
<section>
|
||||
<p>{o.text}</p>
|
||||
</section>
|
||||
</div>
|
||||
{/each}
|
||||
</Masonry>
|
||||
-->
|
||||
|
||||
|
||||
|
||||
<div bind:this={masonryElement}
|
||||
class={`__grid--masonry ${stretchFirst ? '__stretch-first' : ''}`}
|
||||
style={`--grid-gap: ${gridGap}; --col-width: ${colWidth};`}
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
import { onMount, onDestroy, getContext, setContext, tick } from 'svelte'
|
||||
export let stretchFirst = false,
|
||||
gridGap = '0.5em',
|
||||
colWidth = 'minmax(Min(20em, 100%), 1fr)',
|
||||
items = [] // pass in data if it's dynamically updated
|
||||
let grids = [], masonryElement
|
||||
|
||||
const refreshLayout = async () => {
|
||||
grids.forEach(async grid => {
|
||||
/* get the post relayout number of columns */
|
||||
let ncol = getComputedStyle(grid._el).gridTemplateColumns.split(' ').length
|
||||
|
||||
grid.items.forEach(c => {
|
||||
let new_h = c.getBoundingClientRect().height;
|
||||
|
||||
if(new_h !== +c.dataset.h) {
|
||||
c.dataset.h = new_h
|
||||
grid.mod++
|
||||
}
|
||||
});
|
||||
|
||||
/* if the number of columns has changed */
|
||||
if(grid.ncol !== ncol || grid.mod) {
|
||||
/* update number of columns */
|
||||
grid.ncol = ncol;
|
||||
/* revert to initial positioning, no margin */
|
||||
grid.items.forEach(c => c.style.removeProperty('margin-top'))
|
||||
/* if we have more than one column */
|
||||
if(grid.ncol > 1) {
|
||||
grid.items.slice(ncol).forEach((c, i) => {
|
||||
let prev_fin = grid.items[i].getBoundingClientRect().bottom /* bottom edge of item above */,
|
||||
curr_ini = c.getBoundingClientRect().top /* top edge of current item */;
|
||||
|
||||
c.style.marginTop = `${prev_fin + grid.gap - curr_ini}px`
|
||||
})
|
||||
}
|
||||
|
||||
grid.mod = 0
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const calcGrid = async (_masonryArr) => {
|
||||
await tick()
|
||||
if(_masonryArr.length && getComputedStyle(_masonryArr[0]).gridTemplateRows !== 'masonry') {
|
||||
grids = _masonryArr.map(grid => {
|
||||
return {
|
||||
_el: grid,
|
||||
gap: parseFloat(getComputedStyle(grid).gridRowGap),
|
||||
items: [...grid.childNodes].filter(c => c.nodeType === 1 && +getComputedStyle(c).gridColumnEnd !== -1),
|
||||
ncol: 0,
|
||||
mod: 0
|
||||
}
|
||||
})
|
||||
refreshLayout() /* initial load */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
let _window
|
||||
onMount(() => {
|
||||
_window = window
|
||||
_window.addEventListener('resize', refreshLayout, false) /* on resize */
|
||||
})
|
||||
onDestroy(() => {
|
||||
if(_window) {
|
||||
_window.removeEventListener('resize', refreshLayout, false) /* on resize */
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
$: if(masonryElement) {
|
||||
calcGrid([masonryElement])
|
||||
}
|
||||
|
||||
$: if(items) { // update if items are changed
|
||||
masonryElement = masonryElement // refresh masonryElement
|
||||
}
|
||||
</script>
|
||||
|
||||
<!--
|
||||
$w: var(--col-width); // minmax(Min(20em, 100%), 1fr);
|
||||
$s: var(--grid-gap); // .5em;
|
||||
-->
|
||||
|
||||
<style>
|
||||
:global(.__grid--masonry) {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, var(--col-width));
|
||||
grid-template-rows: masonry;
|
||||
justify-content: center;
|
||||
grid-gap: var(--grid-gap);
|
||||
padding: var(--grid-gap);
|
||||
|
||||
}
|
||||
:global(.__grid--masonry > *) {
|
||||
align-self: start
|
||||
}
|
||||
:global(.__grid--masonry.__stretch-first > *:first-child) {
|
||||
grid-column: 1/ -1;
|
||||
}
|
||||
</style>
|
|
@ -1,5 +1,6 @@
|
|||
<script>
|
||||
import TopicCard from "./TopicCard.svelte"
|
||||
import Masonry from './Masonry.svelte'
|
||||
|
||||
let dataPromise = getData();
|
||||
async function getData() {
|
||||
|
@ -24,26 +25,24 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
|
||||
{#await dataPromise}
|
||||
<p>Fetching data...</p>
|
||||
{:then topics}
|
||||
|
||||
<div class="mt-6" style="columns: 6 240px; column-gap: 1rem;">
|
||||
<Masonry gridGap={'0.75rem'}>
|
||||
{#each [...hierarchy(topics).keys()] as parent}
|
||||
<div tabindex="0" class="inline-block w-full mt-4 bg-white rounded-lg mt-4 px-4 py-4 shadow-lg focus:outline-none">
|
||||
<div class="bg-white rounded-lg px-4 py-4 shadow-lg focus:outline-none">
|
||||
<h4 class="mt-1 p-1 text-gray-900 font-semibold text-lg">{ parent.display_name }</h4>
|
||||
|
||||
<div class="mt-2 flex flex-wrap text-sm text-gray-900">
|
||||
{#each hierarchy(topics).get(parent) as child}
|
||||
<a href={"#/topic/" + child.id} class="text-purple-600 no-underline hover:underline hover:text-purple-900 px-2">{child.display_name}</a>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<p class="mt-2 text-sm text-right"><span>and 37 more.</span></p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</Masonry>
|
||||
|
||||
{:catch error}
|
||||
<p>{error.message}</p>
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
h1.svelte-b0hmqh{background-color:yellow}
|
||||
.__grid--masonry{display:grid;grid-template-columns:repeat(auto-fit, var(--col-width));grid-template-rows:masonry;justify-content:center;grid-gap:var(--grid-gap);padding:var(--grid-gap)}.__grid--masonry > *{align-self:start
|
||||
}.__grid--masonry.__stretch-first > *:first-child{grid-column:1/ -1}._padding.svelte-1wlh87t{padding:12px}._card.svelte-1wlh87t{border:1px solid #ccc
|
||||
}._sticky.svelte-1wlh87t{position:sticky;top:12px}
|
1223
static/bundle.js
1223
static/bundle.js
Plik diff jest za duży
Load Diff
File diff suppressed because one or more lines are too long
Ładowanie…
Reference in New Issue