Merge remote-tracking branch 'frontend/master'

I am a goofball
This commit is contained in:
EDRipper 2025-12-06 01:33:35 -05:00
commit 524d89573c
23 changed files with 3313 additions and 0 deletions

23
.gitignore vendored Normal file
View file

@ -0,0 +1,23 @@
node_modules
# Output
.output
.vercel
.netlify
.wrangler
/.svelte-kit
/build
# OS
.DS_Store
Thumbs.db
# Env
.env
.env.*
!.env.example
!.env.test
# Vite
vite.config.js.timestamp-*
vite.config.ts.timestamp-*

1
.npmrc Normal file
View file

@ -0,0 +1 @@
engine-strict=true

38
README.md Normal file
View file

@ -0,0 +1,38 @@
# sv
Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```sh
# create a new project in the current directory
npx sv create
# create a new project in my-app
npx sv create my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```sh
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
To create a production version of your app:
```sh
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.

17
app/package.json Normal file
View file

@ -0,0 +1,17 @@
{
"name": "stickers-app",
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^4.0.0",
"@sveltejs/kit": "^2.21.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"svelte": "^5.0.0",
"vite": "^6.0.0"
}
}

12
app/src/app.html Normal file
View file

@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

View file

10
app/svelte.config.js Normal file
View file

@ -0,0 +1,10 @@
import adapter from '@sveltejs/adapter-auto';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter()
}
};
export default config;

6
app/vite.config.js Normal file
View file

@ -0,0 +1,6 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()]
});

1640
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

26
package.json Normal file
View file

@ -0,0 +1,26 @@
{
"name": "stickers",
"private": true,
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"prepare": "svelte-kit sync || echo ''",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^7.0.0",
"@sveltejs/kit": "^2.48.5",
"@sveltejs/vite-plugin-svelte": "^6.2.1",
"svelte": "^5.43.8",
"svelte-check": "^4.3.4",
"typescript": "^5.9.3",
"vite": "^7.2.2"
},
"dependencies": {
"flubber": "^0.4.2"
}
}

13
src/app.d.ts vendored Normal file
View file

@ -0,0 +1,13 @@
// See https://svelte.dev/docs/kit/types#app.d.ts
// for information about these interfaces
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface PageState {}
// interface Platform {}
}
}
export {};

11
src/app.html Normal file
View file

@ -0,0 +1,11 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

View file

@ -0,0 +1,66 @@
<svg width="256" height="256" viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="256" height="256">
<path fill-rule="evenodd" clip-rule="evenodd" d="M128 256C230.4 256 256 230.4 256 128C256 25.6 230.4 0 128 0C25.6 0 0 25.6 0 128C0 230.4 25.6 256 128 256Z" fill="black"/>
</mask>
<g mask="url(#mask0)">
<g filter="url(#filter0_ii)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M128 256C230.4 256 256 230.4 256 128C256 25.6 230.4 0 128 0C25.6 0 0 25.6 0 128C0 230.4 25.6 256 128 256Z" fill="url(#paint0_radial)"/>
</g>
<g filter="url(#filter1_ddii)">
<path d="M115.103 48.3682C115.103 47.1299 113.989 46.1892 112.769 46.3965L81.6652 51.6777C80.7036 51.8409 80 52.6741 80 53.6494V205.085C80 206.189 80.8954 207.085 82 207.085H113.103C114.208 207.085 115.103 206.189 115.103 205.085V148.397C115.103 131.127 124.261 120.429 131.892 120.429C138.76 120.429 140.744 127.307 140.744 137.699V205.085C140.744 206.189 141.639 207.085 142.744 207.085H174C175.105 207.085 176 206.189 176 205.085V132.656C176 109.12 167.148 93.9892 144.102 93.9892C134.852 93.9892 125.825 96.2163 118.633 101.146C117.205 102.125 115.103 101.161 115.103 99.4284V48.3682Z" fill="white"/>
</g>
</g>
</g>
<defs>
<filter id="filter0_ii" x="-6" y="-6" width="268" height="268" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="6" dy="6"/>
<feGaussianBlur stdDeviation="4"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.2 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="-6" dy="-6"/>
<feGaussianBlur stdDeviation="4"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0"/>
<feBlend mode="normal" in2="effect1_innerShadow" result="effect2_innerShadow"/>
</filter>
<filter id="filter1_ddii" x="64" y="42.3677" width="128" height="192.717" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="12"/>
<feGaussianBlur stdDeviation="8"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="4"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.125 0"/>
<feBlend mode="normal" in2="effect1_dropShadow" result="effect2_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="-2"/>
<feGaussianBlur stdDeviation="3"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.125 0"/>
<feBlend mode="normal" in2="shape" result="effect3_innerShadow"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="-2"/>
<feGaussianBlur stdDeviation="3"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.92549 0 0 0 0 0.215686 0 0 0 0 0.313726 0 0 0 0.5 0"/>
<feBlend mode="normal" in2="effect3_innerShadow" result="effect4_innerShadow"/>
</filter>
<radialGradient id="paint0_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="rotate(58.6367) scale(245.935)">
<stop stop-color="#FF8C37"/>
<stop offset="1" stop-color="#EC3750"/>
</radialGradient>
<clipPath id="clip0">
<rect width="256" height="256" fill="white" transform="translate(256) rotate(90)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

View file

@ -0,0 +1,290 @@
<script>
import { onMount } from 'svelte';
let {
corner = 'bottom-right',
peelOnHover = true,
hoverPeelAmount = 0.15,
peelOnClick = false,
peelAwayDuration = 500,
dragEnabled = false,
borderRadius = '0',
class: className = '',
topContent,
backContent,
bottomContent,
onPeel = () => {},
onPeelComplete = () => {},
options = {}
} = $props();
let container = $state(null);
let peel = $state(null);
let isPeeled = $state(false);
let isHovering = $state(false);
let width = $state(0);
let height = $state(0);
let cornerValue = $state(3);
let currentPos = $state(null);
let isActive = $state(false);
let animationId = $state(0);
const cornerMap = {
'top-left': 0,
'top-right': 1,
'bottom-left': 2,
'bottom-right': 3
};
function getRestPosition() {
switch (cornerValue) {
case 0: return { x: 0, y: 0 };
case 1: return { x: width, y: 0 };
case 2: return { x: 0, y: height };
case 3: return { x: width, y: height };
}
}
function getHoverPosition() {
const offset = Math.min(width, height) * hoverPeelAmount;
switch (cornerValue) {
case 0: return { x: offset, y: offset };
case 1: return { x: width - offset, y: offset };
case 2: return { x: offset, y: height - offset };
case 3: return { x: width - offset, y: height - offset };
}
}
function getPeeledPosition() {
switch (cornerValue) {
case 0: return { x: width * 1.5, y: height * 1.5 };
case 1: return { x: -width * 0.5, y: height * 1.5 };
case 2: return { x: width * 1.5, y: -height * 0.5 };
case 3: return { x: -width * 0.5, y: -height * 0.5 };
}
}
function animateTo(targetX, targetY, duration, callback, showLayers = true) {
if (!peel) return;
animationId++;
const thisAnimationId = animationId;
const startTime = performance.now();
const startPos = currentPos || getRestPosition();
let firstFrame = true;
function animate(currentTime) {
if (thisAnimationId !== animationId) return;
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
const eased = 1 - Math.pow(1 - progress, 3);
const x = startPos.x + (targetX - startPos.x) * eased;
const y = startPos.y + (targetY - startPos.y) * eased;
peel.setPeelPosition(x, y);
currentPos = { x, y };
if (firstFrame && showLayers) {
firstFrame = false;
const capturedId = thisAnimationId;
requestAnimationFrame(() => {
requestAnimationFrame(() => {
if (capturedId === animationId) {
isActive = true;
}
});
});
}
if (progress < 1) {
requestAnimationFrame(animate);
} else {
const rest = getRestPosition();
if (Math.abs(x - rest.x) < 1 && Math.abs(y - rest.y) < 1) {
isActive = false;
}
if (callback) callback();
}
}
requestAnimationFrame(animate);
}
function handleClick() {
if (!peelOnClick || !peel) return;
isPeeled = !isPeeled;
if (isPeeled) {
const target = getPeeledPosition();
animateTo(target.x, target.y, peelAwayDuration, () => {
onPeelComplete();
});
} else {
const target = isHovering ? getHoverPosition() : getRestPosition();
animateTo(target.x, target.y, peelAwayDuration);
}
}
function handleMouseEnter() {
if (!peel || !peelOnHover || isPeeled) return;
isHovering = true;
const pos = getHoverPosition();
animateTo(pos.x, pos.y, 200);
}
function handleMouseLeave() {
if (!peel || !peelOnHover || isPeeled) return;
isHovering = false;
const pos = getRestPosition();
animateTo(pos.x, pos.y, 200, null, false);
}
onMount(async () => {
const Peel = (await import('$lib/peel.js')).default;
if (!Peel || !container) return;
cornerValue = typeof corner === 'string' ? cornerMap[corner] ?? 4 : corner;
width = container.offsetWidth;
height = container.offsetHeight;
peel = new Peel(container, {
corner: cornerValue,
setPeelOnInit: false,
...options
});
currentPos = { x: peel.corner.x, y: peel.corner.y };
peel.setPeelPosition(currentPos.x, currentPos.y);
if (dragEnabled) {
peel.handleDrag(function(evt, x, y) {
this.setPeelPosition(x, y);
onPeel({ x, y, amountClipped: this.getAmountClipped() });
});
}
return () => {
if (peel) {
peel.removeEvents();
}
};
});
export function getPeel() {
return peel;
}
export function setPeelPosition(x, y) {
if (peel) peel.setPeelPosition(x, y);
}
export function peelAway() {
if (!peel) return;
isPeeled = true;
const target = getPeeledPosition();
animateTo(target.x, target.y, peelAwayDuration, onPeelComplete);
}
export function reset() {
if (!peel) return;
isPeeled = false;
const target = getRestPosition();
animateTo(target.x, target.y, peelAwayDuration);
}
</script>
<div
bind:this={container}
class="peelable {className}"
class:peelable-active={isActive || isPeeled}
style="--peel-border-radius: {borderRadius}"
onmouseenter={handleMouseEnter}
onmouseleave={handleMouseLeave}
onclick={handleClick}
role="button"
tabindex="0"
>
<div class="peel-top">
{#if topContent}
{@render topContent()}
{/if}
</div>
<div class="peel-back">
{#if backContent}
{@render backContent()}
{/if}
</div>
<div class="peel-bottom">
{#if bottomContent}
{@render bottomContent()}
{/if}
</div>
</div>
<style>
.peelable {
position: relative;
}
.peelable :global(.peel-top),
.peelable :global(.peel-back),
.peelable :global(.peel-bottom) {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: var(--peel-border-radius, 0);
overflow: hidden;
}
.peelable :global(.peel-back),
.peelable :global(.peel-bottom),
.peelable :global(.peel-top-shadow),
.peelable :global(.peel-back-shadow),
.peelable :global(.peel-back-reflection),
.peelable :global(.peel-bottom-shadow) {
opacity: 0;
pointer-events: none;
}
.peelable.peelable-active :global(.peel-back),
.peelable.peelable-active :global(.peel-bottom),
.peelable.peelable-active :global(.peel-top-shadow),
.peelable.peelable-active :global(.peel-back-shadow),
.peelable.peelable-active :global(.peel-back-reflection),
.peelable.peelable-active :global(.peel-bottom-shadow) {
opacity: 1;
pointer-events: auto;
}
.peelable :global(.peel-layer) {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
-webkit-transform-origin: top left;
-moz-transform-origin: top left;
transform-origin: top left;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
.peelable :global(.peel-svg-clip-element) {
position: absolute;
top: -10000px;
left: -10000px;
width: 1px;
height: 1px;
opacity: 0;
}
</style>

1
src/lib/index.ts Normal file
View file

@ -0,0 +1 @@
// place files you want to import through the `$lib` alias in this folder.

987
src/lib/peel.js Normal file
View file

@ -0,0 +1,987 @@
(function(win) {
var PRECISION = 1e2;
var VENDOR_PREFIXES = ['webkit','moz', ''];
var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
var CSS_PREFIX = 'peel-';
var clipProperty, transformProperty, boxShadowProperty, filterProperty;
var backgroundGradientSupport;
var docEl = document.documentElement;
var style = docEl.style;
function getCssProperty(name) {
var prefix, str;
for (var i = 0; i < VENDOR_PREFIXES.length; i++) {
prefix = VENDOR_PREFIXES[i];
str = prefix ? prefix + capitalize(name) : name;
if (str in style) {
return str;
}
}
}
function setCssProperties() {
clipProperty = getCssProperty('clipPath');
transformProperty = getCssProperty('transform');
boxShadowProperty = getCssProperty('boxShadow');
filterProperty = getCssProperty('filter');
setBackgroundGradientSupport();
Peel.supported = !!(clipProperty && transformProperty);
Peel.effectsSupported = backgroundGradientSupport;
}
function setBackgroundGradientSupport() {
var el = document.createElement('div');
var style = el.style;
style.cssText = 'background:linear-gradient(45deg,,white);';
backgroundGradientSupport = (style.backgroundImage || '').indexOf('gradient') > -1;
}
function round(n) {
return Math.round(n * PRECISION) / PRECISION;
}
function clamp(n) {
return Math.max(0, Math.min(1, n));
}
function normalize(n, min, max) {
return (n - min) / (max - min);
}
function distribute(t, mult) {
return (mult || 1) * 2 * (.5 - Math.abs(t - .5));
}
function capitalize(str) {
return str.slice(0,1).toUpperCase() + str.slice(1);
}
function camelize(str) {
return str.replace(/-(\w)/g, function(a, b) {
return b.toUpperCase();
});
}
function prefix(str) {
return CSS_PREFIX + str;
}
function setCSSClip(el, clip) {
el.style[clipProperty] = clip;
}
function setTransform(el, t) {
el.style[transformProperty] = t;
}
function setBoxShadow(el, x, y, blur, spread, intensity) {
el.style[boxShadowProperty] = getShadowCss(x, y, blur, spread, intensity);
}
function setDropShadow(el, x, y, blur, intensity) {
el.style[filterProperty] = 'drop-shadow(' + getShadowCss(x, y, blur, null, intensity) + ')';
}
function getShadowCss(x, y, blur, spread, intensity) {
return round(x) + 'px ' +
round(y) + 'px ' +
round(blur) + 'px ' +
(spread ? round(spread) + 'px ' : '') +
'rgba(0,0,0,' + round(intensity) + ')';
}
function setOpacity(el, t) {
el.style.opacity = t;
}
function setBackgroundGradient(el, rotation, stops) {
if (!backgroundGradientSupport) return;
var css;
if (stops.length === 0) {
css = 'none';
} else {
css = 'linear-gradient(' + round(rotation) + 'deg,' + stops.join(',') + ')';
}
el.style.backgroundImage = css;
}
function addEvent(el, type, fn) {
el.addEventListener(type, fn)
}
function removeEvent(el, type, fn) {
el.removeEventListener(type, fn);
}
function getEventCoordinates(evt, el) {
var pos = evt.changedTouches ? evt.changedTouches[0] : evt;
return {
'x': pos.clientX - el.offsetLeft + window.scrollX,
'y': pos.clientY - el.offsetTop + window.scrollY
}
}
function bindWithEvent(fn, scope, arg1, arg2) {
return function(evt) {
fn.call(scope, evt, arg1, arg2);
}
}
function getBlackStop(a, pos) {
return getColorStop(0, 0, 0, a, pos);
}
function getWhiteStop(a, pos) {
return getColorStop(255, 255, 255, a, pos);
}
function getColorStop(r, g, b, a, pos) {
a = round(clamp(a));
return 'rgba('+ r +','+ g +','+ b +','+ a +') ' + round(pos * 100) + '%';
}
function getElement(obj, node) {
if (typeof obj === 'string') {
obj = (node || document).querySelector(obj);
}
return obj;
}
function createElement(parent, className) {
var el = document.createElement('div');
addClass(el, className);
parent.appendChild(el);
return el;
}
function removeClass(el, str) {
el.classList.remove(str);
}
function addClass(el, str) {
el.classList.add(str);
}
function getZIndex(el) {
return el.style.zIndex;
}
function setZIndex(el, index) {
el.style.zIndex = index;
}
function createSVGElement(tag, parent, attributes) {
parent = parent || docEl;
var el = document.createElementNS(SVG_NAMESPACE, tag);
parent.appendChild(el);
for (var key in attributes) {
if (!attributes.hasOwnProperty(key)) continue;
setSVGAttribute(el, key, attributes[key]);
}
return el;
}
function setSVGAttribute(el, key, value) {
el.setAttributeNS(null, key, value);
}
function Peel (el, opt) {
this.setOptions(opt);
this.el = getElement(el, docEl);
this.constraints = [];
this.events = [];
this.setupLayers();
this.setupDimensions();
this.setCorner(this.getOption('corner'));
this.setMode(this.getOption('mode'));
this.init();
}
Peel.Corners = {
TOP_LEFT: 0x0,
TOP_RIGHT: 0x1,
BOTTOM_LEFT: 0x2,
BOTTOM_RIGHT: 0x3
}
Peel.Defaults = {
'topShadow': true,
'topShadowBlur': 5,
'topShadowAlpha': .5,
'topShadowOffsetX': 0,
'topShadowOffsetY': 1,
'topShadowCreatesShape': true,
'backReflection': false,
'backReflectionSize': .02,
'backReflectionOffset': 0,
'backReflectionAlpha': .15,
'backReflectionDistribute': true,
'backShadow': true,
'backShadowSize': .04,
'backShadowOffset': 0,
'backShadowAlpha': .1,
'backShadowDistribute': true,
'bottomShadow': true,
'bottomShadowSize': 1.5,
'bottomShadowOffset': 0,
'bottomShadowDarkAlpha': .7,
'bottomShadowLightAlpha': .1,
'bottomShadowDistribute': true,
'setPeelOnInit': true,
'clippingBoxScale': 4,
'flipConstraintOffset': 5,
'dragPreventsDefault': true
}
Peel.prototype.setCorner = function() {
var args = arguments;
if (args[0] === undefined) {
args = [Peel.Corners.BOTTOM_RIGHT];
} else if (args[0].length) {
args = args[0];
}
this.corner = this.getPointOrCorner(args);
}
Peel.prototype.setMode = function(mode) {
if (mode === 'book') {
this.addPeelConstraint(Peel.Corners.BOTTOM_LEFT);
this.addPeelConstraint(Peel.Corners.TOP_LEFT);
this.setOption('backReflection', false);
this.setOption('backShadowDistribute', false);
this.setOption('bottomShadowDistribute', false);
} else if (mode === 'calendar') {
this.addPeelConstraint(Peel.Corners.TOP_RIGHT);
this.addPeelConstraint(Peel.Corners.TOP_LEFT);
}
}
Peel.prototype.setPeelPath = function(x1, y1) {
var args = arguments, p1, p2, c1, c2;
p1 = new Point(x1, y1);
if (args.length === 4) {
p2 = new Point(args[2], args[3]);
this.path = new LineSegment(p1, p2);
} else if (args.length === 8) {
c1 = new Point(args[2], args[3]);
c2 = new Point(args[4], args[5]);
p2 = new Point(args[6], args[7]);
this.path = new BezierCurve(p1, c1, c2, p2);
}
}
Peel.prototype.handleDrag = function(fn, el) {
this.dragHandler = fn;
this.setupDragEvents(el);
}
Peel.prototype.handlePress = function(fn, el) {
this.pressHandler = fn;
this.setupDragEvents(el);
}
Peel.prototype.setupDragEvents = function(el) {
var self = this, isDragging, moveName, endName;
if (this.dragEventsSetup) {
return;
}
el = el || this.el;
function dragStart (touch, evt) {
if (self.getOption('dragPreventsDefault')) {
evt.preventDefault();
}
moveName = touch ? 'touchmove' : 'mousemove';
endName = touch ? 'touchend' : 'mouseup';
addEvent(docEl, moveName, dragMove);
addEvent(docEl, endName, dragEnd);
isDragging = false;
}
function dragMove (evt) {
if (self.dragHandler) {
callHandler(self.dragHandler, evt);
}
isDragging = true;
}
function dragEnd(evt) {
if (!isDragging && self.pressHandler) {
callHandler(self.pressHandler, evt);
}
removeEvent(docEl, moveName, dragMove);
removeEvent(docEl, endName, dragEnd);
}
function callHandler(fn, evt) {
var coords = getEventCoordinates(evt, self.el);
fn.call(self, evt, coords.x, coords.y);
}
this.addEvent(el, 'mousedown', dragStart.bind(this, false));
this.addEvent(el, 'touchstart', dragStart.bind(this, true));
this.dragEventsSetup = true;
}
Peel.prototype.removeEvents = function() {
this.events.forEach(function(e, i) {
removeEvent(e.el, e.type, e.handler);
});
this.events = [];
}
Peel.prototype.setTimeAlongPath = function(t) {
t = clamp(t);
var point = this.path.getPointForTime(t);
this.timeAlongPath = t;
this.setPeelPosition(point.x, point.y);
}
Peel.prototype.setFadeThreshold = function(n) {
this.fadeThreshold = n;
}
Peel.prototype.setPeelPosition = function() {
var pos = this.getPointOrCorner(arguments);
pos = this.getConstrainedPeelPosition(pos);
if (!pos) {
return;
}
this.peelLineSegment = this.getPeelLineSegment(pos);
this.peelLineRotation = this.peelLineSegment.getAngle();
this.setClipping();
this.setBackTransform(pos);
this.setEffects();
}
Peel.prototype.addPeelConstraint = function() {
var p = this.getPointOrCorner(arguments);
var radius = this.corner.subtract(p).getLength();
this.constraints.push(new Circle(p, radius));
this.calculateFlipConstraint();
}
Peel.prototype.setOption = function(key, value) {
this.options[key] = value;
}
Peel.prototype.getOption = function(key) {
return this.options[camelize(key)];
}
Peel.prototype.getAmountClipped = function() {
var topArea = this.getTopClipArea();
var totalArea = this.width * this.height;
return normalize(topArea, totalArea, 0);
}
Peel.prototype.addEvent = function(el, type, fn) {
addEvent(el, type, fn);
this.events.push({
el: el,
type: type,
handler: fn
});
return fn;
}
Peel.prototype.getTopClipArea = function() {
var top = new Polygon();
this.elementBox.forEach(function(side) {
this.distributeLineByPeelLine(side, top);
}, this);
return Polygon.getArea(top.getPoints());
}
Peel.prototype.calculateFlipConstraint = function() {
var corner = this.corner, arr = this.constraints.concat();
this.flipConstraint = arr.sort(function(a, b) {
var aY = corner.y - a.center.y;
var bY = corner.y - b.center.y;
return a - b;
})[0];
}
Peel.prototype.dragStart = function(evt, type, fn) {}
Peel.prototype.fireHandler = function(evt, fn) {
var coords = getEventCoordinates(evt, this.el);
fn.call(this, evt, coords.x, coords.y);
}
Peel.prototype.setClipping = function() {
var top = new Polygon();
var back = new Polygon();
this.clippingBox.forEach(function(side) {
this.distributeLineByPeelLine(side, top, back);
}, this);
this.topClip.setPoints(top.getPoints());
this.backClip.setPoints(back.getPoints());
}
Peel.prototype.distributeLineByPeelLine = function(seg, poly1, poly2) {
var intersect = this.peelLineSegment.getIntersectPoint(seg);
this.distributePointByPeelLine(seg.p1, poly1, poly2);
this.distributePointByPeelLine(intersect, poly1, poly2);
}
Peel.prototype.distributePointByPeelLine = function(p, poly1, poly2) {
if (!p) return;
var d = this.peelLineSegment.getPointDeterminant(p);
if (d <= 0) {
poly1.addPoint(p);
}
if (d >= 0 && poly2) {
poly2.addPoint(this.flipPointHorizontally(p));
}
}
Peel.prototype.setOptions = function(opt) {
var options = opt || {}, defaults = Peel.Defaults;
for (var key in defaults) {
if (!defaults.hasOwnProperty(key) || key in options) {
continue;
}
options[key] = defaults[key];
}
this.options = options;
}
Peel.prototype.findOrCreateLayer = function(id, parent, zIndex) {
var optId = id + '-element';
var domId = prefix(id);
var el = getElement(this.getOption(optId) || '.' + domId, parent);
if (!el) {
el = createElement(parent, domId);
}
addClass(el, prefix('layer'));
setZIndex(el, zIndex);
return el;
}
Peel.prototype.getPointOrCorner = function(args) {
if (args.length === 2) {
return new Point(args[0], args[1]);
} else if(typeof args[0] === 'number') {
return this.getCornerPoint(args[0]);
}
return args[0];
}
Peel.prototype.getCornerPoint = function(id) {
var x = +!!(id & 1) * this.width;
var y = +!!(id & 2) * this.height;
return new Point(x, y);
}
Peel.prototype.getOptionalShape = function() {
var shapes = ['rect', 'polygon', 'path', 'circle'], found;
shapes.some(function(type) {
var attr = this.getOption(type), obj;
if (attr) {
obj = {};
obj.attributes = attr;
obj.type = type;
found = obj;
}
return found;
}, this);
return found;
}
Peel.prototype.setupLayers = function() {
var shape = this.getOptionalShape();
var topInnerLayer = this.topLayer = this.findOrCreateLayer('top', this.el, 2);
var backInnerLayer = this.backLayer = this.findOrCreateLayer('back', this.el, 3);
this.bottomLayer = this.findOrCreateLayer('bottom', this.el, 1);
if (shape) {
this.topLayer = this.wrapShapeLayer(this.topLayer, 'top-outer-clip');
this.backLayer = this.wrapShapeLayer(this.backLayer, 'back-outer-clip');
this.topShapeClip = new SVGClip(topInnerLayer, shape);
this.backShapeClip = new SVGClip(backInnerLayer, shape);
this.bottomShapeClip = new SVGClip(this.bottomLayer, shape);
if (this.getOption('topShadowCreatesShape')) {
this.topShadowElement = this.setupDropShadow(shape, topInnerLayer);
}
} else {
this.topShadowElement = this.findOrCreateLayer('top-shadow', topInnerLayer, 1);
}
this.topClip = new SVGClip(this.topLayer);
this.backClip = new SVGClip(this.backLayer);
this.backShadowElement = this.findOrCreateLayer('back-shadow', backInnerLayer, 1);
this.backReflectionElement = this.findOrCreateLayer('back-reflection', backInnerLayer, 2);
this.bottomShadowElement = this.findOrCreateLayer('bottom-shadow', this.bottomLayer, 1);
this.usesBoxShadow = !shape;
}
Peel.prototype.setupDropShadow = function(shape, parent) {
var svg = createSVGElement('svg', parent, {
'class': prefix('layer')
});
createSVGElement(shape.type, svg, shape.attributes);
return svg;
}
Peel.prototype.wrapShapeLayer = function(el, id) {
var zIndex = getZIndex(el);
addClass(el, prefix('shape-layer'));
var outerLayer = this.findOrCreateLayer(id, this.el, zIndex);
outerLayer.appendChild(el);
return outerLayer;
}
Peel.prototype.setupDimensions = function() {
this.width = this.el.offsetWidth;
this.height = this.el.offsetHeight;
this.center = new Point(this.width / 2, this.height / 2);
this.elementBox = this.getScaledBox(1);
this.clippingBox = this.getScaledBox(this.getOption('clippingBoxScale'));
}
Peel.prototype.getScaledBox = function(scale) {
var brScale = scale;
var tlScale = scale - 1;
var tl = new Point(-this.width * tlScale, -this.height * tlScale);
var tr = new Point( this.width * brScale, -this.height * tlScale);
var br = new Point( this.width * brScale, this.height * brScale);
var bl = new Point(-this.width * tlScale, this.height * brScale);
return [
new LineSegment(tl, tr),
new LineSegment(tr, br),
new LineSegment(br, bl),
new LineSegment(bl, tl)
];
}
Peel.prototype.getConstrainedPeelPosition = function(pos) {
this.constraints.forEach(function(area) {
var offset = this.getFlipConstraintOffset(area, pos);
if (offset) {
area = new Circle(area.center, area.radius - offset);
}
pos = area.constrainPoint(pos);
}, this);
return pos;
}
Peel.prototype.getFlipConstraintOffset = function(area, pos) {
var offset = this.getOption('flipConstraintOffset');
if (area === this.flipConstraint && offset) {
var cornerToCenter = this.corner.subtract(this.center);
var cornerToConstraint = this.corner.subtract(area.center);
var baseAngle = cornerToConstraint.getAngle();
var nCornerToConstraint = cornerToConstraint.rotate(-baseAngle);
var nPosToConstraint = pos.subtract(area.center).rotate(-baseAngle);
if (cornerToCenter.x * cornerToCenter.y < 0) {
nPosToConstraint.y *= -1;
}
if (nPosToConstraint.x > 0 && nPosToConstraint.y > 0) {
return normalize(nPosToConstraint.getAngle(), 45, 0) * offset;
}
}
}
Peel.prototype.getPeelLineSegment = function(point) {
var halfToCorner = this.corner.subtract(point).scale(.5);
var midpoint = point.add(halfToCorner);
if (halfToCorner.x === 0 && halfToCorner.y === 0) {
halfToCorner = point.subtract(this.center);
}
var l = halfToCorner.getLength()
var mult = (Math.max(this.width, this.height) / l) * 10;
var half = halfToCorner.rotate(-90).scale(mult);
var p1 = midpoint.add(half);
var p2 = midpoint.subtract(half);
return new LineSegment(p1, p2);
}
Peel.prototype.setBackTransform = function(pos) {
var mirroredCorner = this.flipPointHorizontally(this.corner);
var r = (this.peelLineRotation - 90) * 2;
var t = pos.subtract(mirroredCorner.rotate(r));
var css = 'translate('+ round(t.x) +'px, '+ round(t.y) +'px) rotate('+ round(r) +'deg)';
setTransform(this.backLayer, css);
setTransform(this.topShadowElement, css);
}
Peel.prototype.getPeelLineDistance = function() {
var cornerId, opposingCornerId, corner, opposingCorner;
if (this.peelLineRotation < 90) {
cornerId = Peel.Corners.TOP_RIGHT;
opposingCornerId = Peel.Corners.BOTTOM_LEFT;
} else if (this.peelLineRotation < 180) {
cornerId = Peel.Corners.BOTTOM_RIGHT;
opposingCornerId = Peel.Corners.TOP_LEFT;
} else if (this.peelLineRotation < 270) {
cornerId = Peel.Corners.BOTTOM_LEFT;
opposingCornerId = Peel.Corners.TOP_RIGHT;
} else if (this.peelLineRotation < 360) {
cornerId = Peel.Corners.TOP_LEFT;
opposingCornerId = Peel.Corners.BOTTOM_RIGHT;
}
corner = this.getCornerPoint(cornerId);
opposingCorner = this.getCornerPoint(opposingCornerId);
var cornerToCorner = new LineSegment(corner, opposingCorner).scale(2);
var intersect = this.peelLineSegment.getIntersectPoint(cornerToCorner);
if (!intersect) {
return 2;
}
var distanceToPeelLine = corner.subtract(intersect).getLength();
var totalDistance = corner.subtract(opposingCorner).getLength();
return (distanceToPeelLine / totalDistance);
}
Peel.prototype.setEffects = function() {
var t = this.getPeelLineDistance();
this.setTopShadow(t);
this.setBackShadow(t);
this.setBackReflection(t);
this.setBottomShadow(t);
this.setFade();
}
Peel.prototype.setTopShadow = function(t) {
if (!this.getOption('topShadow')) {
return;
}
var sBlur = this.getOption('topShadowBlur');
var sX = this.getOption('topShadowOffsetX');
var sY = this.getOption('topShadowOffsetY');
var alpha = this.getOption('topShadowAlpha');
var sAlpha = this.exponential(t, 5, alpha);
if (this.usesBoxShadow) {
setBoxShadow(this.topShadowElement, sX, sY, sBlur, 0, sAlpha);
} else {
setDropShadow(this.topShadowElement, sX, sY, sBlur, sAlpha);
}
}
Peel.prototype.distributeOrLinear = function(n, dist, mult) {
if (dist) {
return distribute(n, mult);
} else {
return n * mult;
}
}
Peel.prototype.exponential = function(n, exp, mult) {
return mult * clamp(Math.pow(1 + n, exp) - 1);
}
Peel.prototype.setBackReflection = function(t) {
var stops = [];
if (this.canSetLinearEffect('backReflection', t)) {
var rDistribute = this.getOption('backReflectionDistribute');
var rSize = this.getOption('backReflectionSize');
var rOffset = this.getOption('backReflectionOffset');
var rAlpha = this.getOption('backReflectionAlpha');
var reflectionSize = this.distributeOrLinear(t, rDistribute, rSize);
var rStop = t - rOffset;
var rMid = rStop - reflectionSize;
var rStart = rMid - reflectionSize;
stops.push(getWhiteStop(0, 0));
stops.push(getWhiteStop(0, rStart));
stops.push(getWhiteStop(rAlpha, rMid));
stops.push(getWhiteStop(0, rStop));
}
setBackgroundGradient(this.backReflectionElement, 180 - this.peelLineRotation, stops);
}
Peel.prototype.setBackShadow = function(t) {
var stops = [];
if (this.canSetLinearEffect('backShadow', t)) {
var sSize = this.getOption('backShadowSize');
var sOffset = this.getOption('backShadowOffset');
var sAlpha = this.getOption('backShadowAlpha');
var sDistribute = this.getOption('backShadowDistribute');
var shadowSize = this.distributeOrLinear(t, sDistribute, sSize);
var shadowStop = t - sOffset;
var shadowMid = shadowStop - shadowSize;
var shadowStart = shadowMid - shadowSize;
stops.push(getBlackStop(0, 0));
stops.push(getBlackStop(0, shadowStart));
stops.push(getBlackStop(sAlpha, shadowMid));
stops.push(getBlackStop(sAlpha, shadowStop));
}
setBackgroundGradient(this.backShadowElement, 180 - this.peelLineRotation, stops);
}
Peel.prototype.setBottomShadow = function(t) {
var stops = [];
if (this.canSetLinearEffect('bottomShadow', t)) {
var sSize = this.getOption('bottomShadowSize');
var offset = this.getOption('bottomShadowOffset');
var darkAlpha = this.getOption('bottomShadowDarkAlpha');
var lightAlpha = this.getOption('bottomShadowLightAlpha');
var sDistribute = this.getOption('bottomShadowDistribute');
var darkShadowStart = t - (.025 - offset);
var midShadowStart = darkShadowStart - (this.distributeOrLinear(t, sDistribute, .03) * sSize) - offset;
var lightShadowStart = midShadowStart - ((.02 * sSize) - offset);
stops = [
getBlackStop(0, 0),
getBlackStop(0, lightShadowStart),
getBlackStop(lightAlpha, midShadowStart),
getBlackStop(lightAlpha, darkShadowStart),
getBlackStop(darkAlpha, t)
];
}
setBackgroundGradient(this.bottomShadowElement, this.peelLineRotation + 180, stops);
}
Peel.prototype.canSetLinearEffect = function(name, t) {
return this.getOption(name) && t > 0;
}
Peel.prototype.setFade = function() {
var threshold = this.fadeThreshold, opacity = 1, n;
if (threshold) {
if (this.timeAlongPath !== undefined) {
n = this.timeAlongPath;
} else {
n = this.getAmountClipped();
}
if (n > threshold) {
opacity = (1 - n) / (1 - threshold);
}
setOpacity(this.topLayer, opacity);
setOpacity(this.backLayer, opacity);
setOpacity(this.bottomShadowElement, opacity);
}
}
Peel.prototype.flipPointHorizontally = function(p) {
return new Point(p.x - ((p.x - this.center.x) * 2), p.y);
}
Peel.prototype.init = function() {
if (this.getOption('setPeelOnInit')) {
this.setPeelPosition(this.corner);
}
addClass(this.el, prefix('ready'));
}
function SVGClip (el, shape) {
this.el = el;
this.shape = SVGClip.createClipPath(el, shape || {
'type': 'polygon'
});
setTransform(this.el, 'translate(0px,0px)');
}
SVGClip.getDefs = function() {
if (!this.defs) {
this.svg = createSVGElement('svg', null, {
'class': prefix('svg-clip-element')
});
this.defs = createSVGElement('defs', this.svg);
}
return this.defs;
}
SVGClip.createClipPath = function(el, obj) {
var id = SVGClip.getId();
var clipPath = createSVGElement('clipPath', this.getDefs());
var svgEl = createSVGElement(obj.type, clipPath, obj.attributes);
setSVGAttribute(clipPath, 'id', id);
setCSSClip(el, 'url(#' + id + ')');
return svgEl;
}
SVGClip.getId = function() {
if (!SVGClip.id) {
SVGClip.id = 1;
}
return 'svg-clip-' + SVGClip.id++;
}
SVGClip.prototype.setPoints = function(points) {
var str = points.map(function(p) {
return round(p.x) + ',' + round(p.y);
}).join(' ');
setSVGAttribute(this.shape, 'points', str);
}
function Circle (center, radius) {
this.center = center;
this.radius = radius;
}
Circle.prototype.containsPoint = function(p) {
if(this.boundingRectContainsPoint(p)) {
var dx = this.center.x - p.x;
var dy = this.center.y - p.y;
dx *= dx;
dy *= dy;
var distanceSquared = dx + dy;
var radiusSquared = this.radius * this.radius;
return distanceSquared <= radiusSquared;
}
return false;
}
Circle.prototype.boundingRectContainsPoint = function(p) {
return p.x >= this.center.x - this.radius && p.x <= this.center.x + this.radius &&
p.y >= this.center.y - this.radius && p.y <= this.center.y + this.radius;
}
Circle.prototype.constrainPoint = function(p) {
if (!this.containsPoint(p)) {
var rotation = p.subtract(this.center).getAngle();
p = this.center.add(new Point(this.radius, 0).rotate(rotation));
}
return p;
}
function Polygon() {
this.points = [];
}
Polygon.getArea = function(points) {
var sum1 = 0, sum2 = 0;
points.forEach(function(p, i, arr) {
var next = arr[(i + 1) % arr.length];
sum1 += (p.x * next.y);
sum2 += (p.y * next.x);
});
return (sum1 - sum2) / 2;
}
Polygon.prototype.addPoint = function(point) {
this.points.push(point);
}
Polygon.prototype.getPoints = function() {
return this.points;
}
function BezierCurve (p1, c1, c2, p2) {
this.p1 = p1;
this.c1 = c1;
this.p2 = p2;
this.c2 = c2;
}
BezierCurve.prototype.getPointForTime = function(t) {
var b0 = Math.pow(1 - t, 3);
var b1 = 3 * t * Math.pow(1 - t, 2);
var b2 = 3 * Math.pow(t, 2) * (1 - t);
var b3 = Math.pow(t, 3);
var x = (b0 * this.p1.x) + (b1 * this.c1.x) + (b2 * this.c2.x) + (b3 * this.p2.x)
var y = (b0 * this.p1.y) + (b1 * this.c1.y) + (b2 * this.c2.y) + (b3 * this.p2.y)
return new Point(x, y);
}
function LineSegment (p1, p2) {
this.p1 = p1;
this.p2 = p2;
}
LineSegment.EPSILON = 1e-6;
LineSegment.prototype.getPointForTime = function(t) {
return this.p1.add(this.getVector().scale(t));
}
LineSegment.prototype.scale = function(n) {
var half = 1 + (n / 2);
var p1 = this.p1.add(this.p2.subtract(this.p1).scale(n));
var p2 = this.p2.add(this.p1.subtract(this.p2).scale(n));
return new LineSegment(p1, p2);
}
LineSegment.prototype.getPointDeterminant = function(p) {
var d = ((p.x - this.p1.x) * (this.p2.y - this.p1.y)) - ((p.y - this.p1.y) * (this.p2.x - this.p1.x));
if (d > -LineSegment.EPSILON && d < LineSegment.EPSILON) {
d = 0;
}
return d;
}
LineSegment.prototype.getIntersectPoint = function(seg2) {
var seg1 = this;
function crossProduct(p1, p2) {
return p1.x * p2.y - p1.y * p2.x;
}
var r = seg1.p2.subtract(seg1.p1);
var s = seg2.p2.subtract(seg2.p1);
var uNumerator = crossProduct(seg2.p1.subtract(seg1.p1), r);
var denominator = crossProduct(r, s);
if (denominator == 0) {
return null;
}
var u = uNumerator / denominator;
var t = crossProduct(seg2.p1.subtract(seg1.p1), s) / denominator;
if ((t >= 0) && (t <= 1) && (u >= 0) && (u <= 1)) {
return seg1.p1.add(r.scale(t));
}
return null;
}
LineSegment.prototype.getAngle = function() {
return this.getVector().getAngle();
}
LineSegment.prototype.getVector = function() {
if (!this.vector) {
this.vector = this.p2.subtract(this.p1);
}
return this.vector;
}
function Point (x, y) {
this.x = x;
this.y = y;
}
Point.DEGREES_IN_RADIANS = 180 / Math.PI;
Point.degToRad = function(deg) {
return deg / Point.DEGREES_IN_RADIANS;
};
Point.radToDeg = function(rad) {
var deg = rad * Point.DEGREES_IN_RADIANS;
while(deg < 0) deg += 360;
return deg;
};
Point.vector = function(deg, len) {
var rad = Point.degToRad(deg);
return new Point(Math.cos(rad) * len, Math.sin(rad) * len);
};
Point.prototype.add = function(p) {
return new Point(this.x + p.x, this.y + p.y);
};
Point.prototype.subtract = function(p) {
return new Point(this.x - p.x, this.y - p.y);
};
Point.prototype.scale = function(n) {
return new Point(this.x * n, this.y * n);
};
Point.prototype.getLength = function() {
return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2));
};
Point.prototype.getAngle = function() {
return Point.radToDeg(Math.atan2(this.y, this.x));
};
Point.prototype.setAngle = function(deg) {
return Point.vector(deg, this.getLength());
};
Point.prototype.rotate = function(deg) {
return this.setAngle(this.getAngle() + deg);
};
setCssProperties();
win.Peel = Peel;
})(typeof window !== 'undefined' ? window : {});
export default typeof window !== 'undefined' ? window.Peel : null;

11
src/routes/+layout.svelte Normal file
View file

@ -0,0 +1,11 @@
<script lang="ts">
import favicon from '$lib/assets/favicon.svg';
let { children } = $props();
</script>
<svelte:head>
<link rel="icon" href={favicon} />
</svelte:head>
{@render children()}

114
src/routes/+page.svelte Normal file
View file

@ -0,0 +1,114 @@
<script>
import Peelable from '$lib/components/Peelable.svelte';
function handleLogin() {
window.location.href = '/login';
}
</script>
<div class="container">
<h1>Stickers</h1>
<p>Manage everything sticky! Get free stickers for signing up, hack or trade to earn rare stickers and certify your collection.</p>
<Peelable
class="login-sticker"
corner="bottom-right"
peelOnHover={true}
hoverPeelAmount={0.4}
peelOnClick={true}
peelAwayDuration={1000}
onPeelComplete={handleLogin}
borderRadius="0.5rem"
>
{#snippet topContent()}
<div class="sticker-face">Sign in!</div>
{/snippet}
{#snippet backContent()}
<div class="sticker-back"></div>
{/snippet}
{#snippet bottomContent()}
<div class="sticker-surface">
<span></span>
</div>
{/snippet}
</Peelable>
<p>*footer joke here</p>
</div>
<style>
@font-face {
font-family: 'Departure Mono';
src: url('$lib/assets/fonts/DepartureMono-Regular.woff') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap;
}
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
text-align: center;
font-family: 'Departure Mono', monospace;
padding: 2rem;
background: #eeeeee;
}
h1 {
font-size: 10rem;
margin-bottom: 1rem;
font-weight: 400;
}
p {
font-size: 2rem;
max-width: 60vw;
margin: 0.5rem 0;
opacity: 0.8;
}
:global(.login-sticker) {
width: clamp(150px, 20vw, 650px);
height: clamp(45px, 20vw, 120px);
margin: 2rem 0;
cursor: pointer;
}
.sticker-face {
width: 100%;
height: 100%;
background: #9cada6;
border-radius: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-family: 'Departure Mono', monospace;
font-weight: 400;
font-size: 3.1rem;
}
.sticker-back {
width: 100%;
height: 100%;
background: #d9c9b6;
border-radius: 0.5rem;
}
.sticker-surface {
width: 100%;
height: 100%;
background: #ffffff;
border-radius: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
color: #333;
font-family: 'Departure Mono', monospace;
font-size: 0.9rem;
}
</style>

3
static/robots.txt Normal file
View file

@ -0,0 +1,3 @@
# allow crawling everything by default
User-agent: *
Disallow:

18
svelte.config.js Normal file
View file

@ -0,0 +1,18 @@
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://svelte.dev/docs/kit/integrations
// for more information about preprocessors
preprocess: vitePreprocess(),
kit: {
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
adapter: adapter()
}
};
export default config;

20
tsconfig.json Normal file
View file

@ -0,0 +1,20 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"rewriteRelativeImportExtensions": true,
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler"
}
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
//
// To make changes to top-level options such as include and exclude, we recommend extending
// the generated config; see https://svelte.dev/docs/kit/configuration#typescript
}

6
vite.config.ts Normal file
View file

@ -0,0 +1,6 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()]
});