Update dependencies and component paths

This commit is contained in:
Rgebee 2023-12-07 22:12:44 +00:00
commit 23641c16e2
15 changed files with 92 additions and 115 deletions

29
src/lib/Banner.svelte Normal file
View file

@ -0,0 +1,29 @@
<script>
export let title = "Quartznet";
</script>
<style>
.overlay {
display: flex;
background-image: url("/img/bluenebula.webp");
background-size: cover;
background-position: center;
min-height: 200px;
text-align: center;
align-items: center;
justify-content: center;
}
.title {
display: inline-block;
font-size: 3rem;
text-decoration: none;
}
</style>
<div class="overlay">
<div class="description col-md-5">
<h1 class="title">{title}</h1>
<p>Software, Games, Science, Space!</p>
</div>
</div>

274
src/lib/Modal.svelte Normal file
View file

@ -0,0 +1,274 @@
<script lang="ts">
//@ts-nocheck
import {
setContext as baseSetContext,
createEventDispatcher,
} from "svelte";
import { fade } from "svelte/transition";
export let key = "simple-modal";
export let closeButton = true;
export let closeOnEsc = true;
export let closeOnOuterClick = true;
export let transitionBg = fade;
export let transitionBgProps = { duration: 250 };
export let transitionWindow = transitionBg;
export let transitionWindowProps = transitionBgProps;
export let styleBg = { top: 0, left: 0 };
export let styleWindow = {};
export let styleContent = {};
export let setContext = baseSetContext;
export let show: boolean = false;
let Component = null;
let props = null;
let background;
let wrap;
let customStyleBg = {};
let customStyleWindow = {};
let customStyleContent = {};
let Callback = (props) => {};
$: Component,
() => {
show = !!Component;
};
const dispatch = createEventDispatcher();
const camelCaseToDash = (str) =>
str.replace(/([a-zA-Z])(?=[A-Z])/g, "$1-").toLowerCase();
const toCssString = (props) =>
Object.keys(props).reduce(
(str, key) => `${str}; ${camelCaseToDash(key)}: ${props[key]}`,
""
);
$: cssBg = toCssString(Object.assign({}, styleBg, customStyleBg));
$: cssWindow = toCssString(
Object.assign({}, styleWindow, customStyleWindow)
);
$: cssContent = toCssString(
Object.assign({}, styleContent, customStyleContent)
);
const open = (
NewComponent,
newProps = {},
style = { bg: {}, window: {}, content: {} },
newCallback = () => {}
) => {
Component = NewComponent;
props = newProps;
Callback = newCallback;
customStyleBg = style.bg || {};
customStyleWindow = style.window || {};
customStyleContent = style.content || {};
};
const close = () => {
Callback(props);
Component = null;
props = null;
customStyleBg = {};
customStyleWindow = {};
customStyleContent = {};
};
const handleKeyup = ({ key }) => {
if (closeOnEsc && Component && key === "Escape") {
event.preventDefault();
close();
}
};
const handleOuterClick = (event) => {
if (
closeOnOuterClick &&
(event.target === background || event.target === wrap)
) {
event.preventDefault();
close();
}
};
setContext(key, { open: show, close });
</script>
<svelte:window on:keyup={handleKeyup} />
<div>
{#if Component}
<div
class="bg"
on:click={handleOuterClick}
bind:this={background}
transition:transitionBg={transitionBgProps}
style={cssBg}
>
<div class="window-wrap" bind:this={wrap}>
<div
class="window"
transition:transitionWindow={transitionWindowProps}
style={cssWindow}
>
{#if closeButton}
<button on:click={close} class="close" />
{/if}
<div class="content" style={cssContent}>
<Component {...props} {close} />
</div>
</div>
</div>
</div>
{/if}
<slot />
</div>
<!--
** LICENSE **
MIT License
Copyright (c) 2019 Fritz Lekschas
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
https://github.com/flekschas/svelte-simple-moda
-->
<style>
* {
box-sizing: border-box;
}
.bg {
position: fixed;
z-index: 1000;
display: flex;
flex-direction: column;
justify-content: center;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.66);
}
.window-wrap {
position: relative;
margin: 2rem;
max-height: 100%;
}
.window {
position: relative;
width: 40rem;
max-width: 100%;
max-height: 100%;
margin: 2rem auto;
color: black;
border-radius: 0.5rem;
background: white;
}
.content {
position: relative;
padding: 1rem;
max-height: calc(100vh - 4rem);
overflow: auto;
}
.close {
display: block;
box-sizing: border-box;
position: absolute;
z-index: 1000;
top: 1rem;
right: 1rem;
margin: 0;
padding: 0;
width: 1.5rem;
height: 1.5rem;
border: 0;
color: black;
border-radius: 1.5rem;
background: white;
box-shadow: 0 0 0 1px black;
transition: transform 0.2s cubic-bezier(0.25, 0.1, 0.25, 1),
background 0.2s cubic-bezier(0.25, 0.1, 0.25, 1);
-webkit-appearance: none;
}
.close:before,
.close:after {
content: "";
display: block;
box-sizing: border-box;
position: absolute;
top: 50%;
width: 1rem;
height: 1px;
background: black;
transform-origin: center;
transition: height 0.2s cubic-bezier(0.25, 0.1, 0.25, 1),
background 0.2s cubic-bezier(0.25, 0.1, 0.25, 1);
}
.close:before {
-webkit-transform: translate(0, -50%) rotate(45deg);
-moz-transform: translate(0, -50%) rotate(45deg);
transform: translate(0, -50%) rotate(45deg);
left: 0.25rem;
}
.close:after {
-webkit-transform: translate(0, -50%) rotate(-45deg);
-moz-transform: translate(0, -50%) rotate(-45deg);
transform: translate(0, -50%) rotate(-45deg);
left: 0.25rem;
}
.close:hover {
background: black;
}
.close:hover:before,
.close:hover:after {
height: 2px;
background: white;
}
.close:focus {
border-color: #3399ff;
box-shadow: 0 0 0 2px #3399ff;
}
.close:active {
transform: scale(0.9);
}
.close:hover,
.close:focus,
.close:active {
outline: none;
}
</style>

53
src/lib/Nav.svelte Normal file
View file

@ -0,0 +1,53 @@
<style>
a {
font-size: 1rem;
text-align: center;
}
nav {
display: flex;
justify-content: space-between;
max-width: 1400px;
margin: 0 auto;
padding-left: 1rem;
padding-right: 1rem;
}
ul {
display: flex;
font-weight: bold;
text-align: center;
list-style: none;
margin-top: 8px;
margin-bottom: 8px;
padding: 0;
}
ul li a {
text-decoration: none;
transition: color 0.1s linear;
padding: 4px 12px;
}
ul li a:hover {
border-bottom: 2px solid var(--line-color);
}
</style>
<header>
<nav>
<ul>
<li>
<a href="/">Quartznet</a>
</li>
<li>
<a href="/about">About</a>
</li>
</ul>
<ul>
<li>
<a href="/admin">Admin</a>
</li>
</ul>
</nav>
</header>

56
src/lib/Sidebar.svelte Normal file
View file

@ -0,0 +1,56 @@
<script lang="ts">
import { fly } from "svelte/transition";
import Modal from "./Modal.svelte";
const click = () => {
modal_show = true;
show = false;
};
function overlay_click(e: MouseEvent) {
//@ts-ignore
if ("close" in e.target.dataset) show = false;
}
export let show = false;
let modal_show = false;
</script>
{#if show}
<div class="overlay" data-close on:click={overlay_click}>
<nav transition:fly={{ x: -250, opacity: 1 }}>
<slot>
<button on:click={click}>About</button>
</slot>
</nav>
</div>
{/if}
<Modal bind:show={modal_show} />
<style>
.overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0);
z-index: 10;
display: flex;
flex-direction: column;
justify-content: center;
}
nav {
position: fixed;
top: 0;
left: 0;
height: 100%;
padding: 2rem 1rem 0.6rem;
border-right: 1px solid #aaa;
background: #fff;
overflow-y: auto;
width: 20rem;
}
</style>

255
src/lib/SortableList.svelte Normal file
View file

@ -0,0 +1,255 @@
<script lang="ts">
//@ts-nocheck
import { quintOut } from "svelte/easing";
import { crossfade } from "svelte/transition";
import { flip } from "svelte/animate";
// FLIP ANIMATION
const [send, receive] = crossfade({
duration: (d) => Math.sqrt(d * 200),
fallback(node, params) {
const style = getComputedStyle(node);
const transform = style.transform === "none" ? "" : style.transform;
return {
duration: 600,
easing: quintOut,
css: (t) => `
transform: ${transform} scale(${t});
opacity: ${t}
`,
};
},
});
// DRAG AND DROP
let isOver = false;
let isDragging = false;
const getDraggedParent = (node) => {
return node.dataset && node.dataset.index
? node.dataset
: getDraggedParent(node.parentNode);
};
const click = (ev) => {
dispatch("slotclick", {
source: ev.target.parentElement.dataset.index,
sourceItem: list[ev.target.parentElement.dataset.index],
});
};
const start = (ev) => {
isDragging = true;
ev.dataTransfer.setData("source", ev.target.dataset.index);
};
const over = (ev) => {
ev.preventDefault();
let dragged = getDraggedParent(ev.target);
if (isOver !== dragged.id) isOver = JSON.parse(dragged.id);
};
const leave = (ev) => {
let dragged = getDraggedParent(ev.target);
if (isOver === dragged.id) isOver = false;
};
const drop = (ev) => {
isOver = false;
ev.preventDefault();
let dragged = getDraggedParent(ev.target);
let from = ev.dataTransfer.getData("source");
let to = dragged.index;
reorder({ from, to });
isDragging = false;
};
// DISPATCH REORDER
import {
createEventDispatcher,
onMount,
afterUpdate,
beforeUpdate,
tick,
} from "svelte";
const dispatch = createEventDispatcher();
const reorder = ({ from, to }) => {
let newList = [...list];
let temp = newList[from];
newList[from] = newList[to];
newList[to] = temp;
//newList[from] = [newList[to], (newList[to] = newList[from])][0];
dispatch("sort", { data: newList, from: from, to: to });
};
// UTILS
const getKey = (item) => (key ? item[key] : item);
type ListItem = {
displayTileSize: number;
endsGroup: boolean;
startsNewGroup: boolean;
};
// PROPS
export let list: ListItem[][];
export let key;
export let ulclass;
export let breakon: string | null = null;
export let breakComponent;
// return `<><li class='${breakClass}' style='height:100%; grid-column: span 5;'><div style='width:100%;height:inherit;'></li>`;
// export let breakPosition = "beforebegin";
let breakClass = "group-break";
const Elements = () => document.getElementsByClassName(key);
const removeOldBreaks = (parent) => {
if (breakon == null) return;
if (isDragging) return;
if (parent.length) {
const old = parent[0].getElementsByClassName(breakClass);
for (let i = 0; i < old.length; i = 0) {
old[i].remove(); // removing the node from the DOM also removes it from this array (WTF??)
}
}
};
let lastCollection;
let updatingBreakPoints = false;
const updateBreak = () => {
if (isDragging || updatingBreakPoints) return;
if (breakon == null) return;
try {
updatingBreakPoints = true;
let breaks = 0;
let last = null;
let carry = 0;
let elements = Elements();
for (let x = 0; x < list.length; x++) {
if (last != null) {
if (list[x][breakon] > last) {
if (elements.length) {
let targetIndex = x + breaks;
if (
list.length !==
elements[0].children.length - breaks
) {
if (lastCollection)
if (lastCollection.length)
targetIndex += lastCollection.length;
}
// elements[0].children[targetIndex].insertAdjacentHTML(breakPosition, breakHtml(carry + 1));
breaks++;
carry = 0;
}
} else {
carry++;
}
}
last = list[x][breakon] > last ? list[x][breakon] : last;
}
lastCollection = list;
} finally {
updatingBreakPoints = false;
}
};
//beforeUpdate(() => {updateBreak()});
let updating = false;
afterUpdate(async () => {
if (isDragging) return;
if (breakon == null) return;
updating = true;
removeOldBreaks(Elements());
await tick();
updateBreak();
updating = false;
});
const getClass = () => {
let ret = "";
if (key) ret += ` ${key}`;
if (ulclass) ret += ` ${ulclass}`;
return ret;
};
</script>
{#if list && list.length}
<ul class={getClass()}>
{#each list as item, index (getKey(item))}
<li
class:small={item.displayTileSize === 2}
class:medium={item.displayTileSize === 3}
class:large={item.displayTileSize === 4}
class:startsNewGroup={item.startsNewGroup}
class:endsGroup={item.endsGroup}
data-index={index}
data-item={JSON.stringify(item)}
data-id={JSON.stringify(getKey(item))}
draggable="true"
on:dragstart={start}
on:dragover={over}
on:dragleave={leave}
on:drop={drop}
on:click={click}
in:receive={{ key: getKey(item) }}
out:send={{ key: getKey(item) }}
animate:flip={{ duration: 300 }}
class:over={getKey(item) === isOver}
>
<slot {item} {index}>
<p>{getKey(item)}</p>
</slot>
</li>
{/each}
</ul>
{/if}
<style>
ul {
display: inline-grid;
list-style: none;
padding: 0;
width: 100%;
}
li {
display: inline-block;
border: 2px dotted transparent;
transition: border 0.1s linear;
width: 100%;
height: 100%;
margin: 0.5%;
}
.startsNewGroup {
grid-column-start: 1;
}
.small {
grid-column-end: span 1;
grid-row: span 1;
}
.medium {
grid-column-end: span 2;
grid-row: span 1;
}
.large {
grid-column-end: span 2;
/*grid-row: span 2; large buttons are double height, but they also push the row below them down (they dont fit around eachother like css-grid) */
}
.over {
border-color: rgba(48, 12, 200, 0.2);
}
</style>

43
src/lib/Thumbnail.svelte Normal file
View file

@ -0,0 +1,43 @@
<script lang="ts">
export let name: string;
export let link: string;
export let img = "https://placehold.it/600x300";
export let size = { width: 600, height: 300 };
export let description: string;
</script>
<div class="card">
<div class="back">
<a href={link}>
<img src={img} alt={name} width={size.width} height={size.height} />
</a>
</div>
<div class="description">
<h2>{name}</h2>
<p>{description}</p>
</div>
</div>
<br />
<style>
.card {
display: flex;
gap: 2.5rem;
}
.back a img {
max-width: 100%;
height: auto;
}
.description {
width: 500px;
}
@media screen and (max-width: 978px) {
.card {
flex-wrap: wrap;
gap: 0.25rem;
}
}
</style>

View file

@ -0,0 +1,16 @@
<script>
export const name = "%USER%";
export let icon;
export let onClick;
</script>
<style>
img {
display: inline-block;
position: relative;
width: 100%;
height: 100%;
}
</style>
<a href="/admin">Admin</a>