fixes, qol and stuff
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
<svelte:options customElement="scubling-card" />
|
||||
|
||||
<script lang="ts">
|
||||
export let title: string = "";
|
||||
export let description: string = "";
|
||||
</script>
|
||||
|
||||
<div class="scubling-card">
|
||||
{#if title}
|
||||
<h3>{title}</h3>
|
||||
{/if}
|
||||
{#if description}
|
||||
<p>{description}</p>
|
||||
{/if}
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.scubling-card {
|
||||
padding: 1rem;
|
||||
border: 2px solid currentColor;
|
||||
}
|
||||
</style>
|
||||
@@ -1,22 +1,32 @@
|
||||
<script lang="ts">
|
||||
let meow = "";
|
||||
<script module lang="ts">
|
||||
export { storeButton };
|
||||
import gumroad from "./sidebar/gumroad.png";
|
||||
import jinxxy from "./sidebar/jinxxy.png";
|
||||
</script>
|
||||
|
||||
{#snippet StoreButton(store: string, url: string)}
|
||||
<a aria-label="Store Page Button" href={url}"></a>
|
||||
{#snippet storeButton(store: string, url: string)}
|
||||
<a aria-label="Store Page Button" class="StoreButton" href={url}>
|
||||
{#if store == "gumroad"}
|
||||
<img src={gumroad} />
|
||||
{:else if store == "jinxxy"}
|
||||
<img src={jinxxy} />
|
||||
{/if}
|
||||
</a>
|
||||
{/snippet}
|
||||
|
||||
<style lang="scss">
|
||||
.StoreButton {
|
||||
display: block;
|
||||
width: fit-content;
|
||||
height: 30px;
|
||||
border: 2px outset #1da1f2;
|
||||
width: 100%;
|
||||
height: 45px;
|
||||
border: 3px outset #1da1f2;
|
||||
background: #1da1f2;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
text-align: center;
|
||||
|
||||
img {
|
||||
height: auto;
|
||||
width: 45px;
|
||||
}
|
||||
}
|
||||
.StoreButton:hover {
|
||||
@@ -27,6 +37,7 @@ let meow = "";
|
||||
border-style: inset;
|
||||
|
||||
img {
|
||||
transform: translate(2px, 2px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<svelte:options customElement="hint-box" />
|
||||
|
||||
<script>
|
||||
let { name = "world" } = $props();
|
||||
import "./Commons.scss";
|
||||
</script>
|
||||
|
||||
<h1>Hello {name}!</h1>
|
||||
<a>meow</a>
|
||||
<slot />
|
||||
@@ -1,21 +1,23 @@
|
||||
.right-sidebar {
|
||||
margin: 5px;
|
||||
margin-right: 0px;
|
||||
height: 800px;
|
||||
width: 125px;
|
||||
background-color: var(--secondary);
|
||||
border: 2px, inset, var(--thirdly);
|
||||
box-sizing: border-box;
|
||||
min-height: 900px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.left-sidebar {
|
||||
margin: 5px;
|
||||
margin-left: 0px;
|
||||
height: 800px;
|
||||
width: 125px;
|
||||
background-color: var(--secondary);
|
||||
border: 2px, inset, var(--thirdly);
|
||||
box-sizing: border-box;
|
||||
min-height: 900px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.side-card {
|
||||
|
||||
@@ -35,4 +35,4 @@
|
||||
<hr style="width: 92%; border-radius: 100px" />
|
||||
<footer>
|
||||
<h2>Doloro, All Meows Reserved.</h2>
|
||||
</footer>
|
||||
</footer>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<title>Doloro's Site (Which resides on the internet)</title>
|
||||
<svelte:head>
|
||||
<title>Doloro Website [Home]</title>
|
||||
</svelte:head>
|
||||
|
||||
<div>
|
||||
<h1>hi</h1>
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
import { commitCard } from "./commitCard.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Doloro Website [Changelog]</title>
|
||||
</svelte:head>
|
||||
|
||||
<table class="commitContainer">
|
||||
<caption>Git Commits of the website repo</caption>
|
||||
<tbody>
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
<script lang="ts">
|
||||
import ScublingCard from "$lib/ScublingCard.svelte";
|
||||
const videos = import.meta.glob("./*.mp4", {
|
||||
eager: true,
|
||||
import: "default",
|
||||
query: { enhanced: true },
|
||||
});
|
||||
console.log(videos);
|
||||
const scub = videos["./scub.mp4"];
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Doloro Website [Scublings]</title>
|
||||
<meta property="og:type" content="video.other" />
|
||||
<meta property="og:video" content="https://doloro.co.uk{scub.video.src}" />
|
||||
<meta property="og:video:type" content="video/mp4" />
|
||||
@@ -16,12 +17,14 @@
|
||||
<meta property="og:video:height" content="1080" />
|
||||
<meta property="og:title" content="Scublings" />
|
||||
<!-- Optional but helps Discord show a thumbnail -->
|
||||
<meta
|
||||
property="og:image"
|
||||
content="https://yourdomain.com/scub-thumbnail.jpg"
|
||||
/>
|
||||
<!-- <meta -->
|
||||
<!-- property="og:image" -->
|
||||
<!-- content="https://yourdomain.com/scub-thumbnail.jpg" -->
|
||||
<!-- /> -->
|
||||
</svelte:head>
|
||||
|
||||
<ScublingCard title="Scublings" description="A scubling video." />
|
||||
|
||||
<div class="video-container">
|
||||
<enhanced:video src={scub}> </enhanced:video>
|
||||
</div>
|
||||
|
||||
@@ -3,16 +3,18 @@ export const prerender = true;
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
export type StoreEntity = {
|
||||
image: string,
|
||||
images: string[],
|
||||
name: string,
|
||||
description: string,
|
||||
short: string, // Short Description
|
||||
category: string,
|
||||
gumroad?: string,
|
||||
jinxxy?: string
|
||||
}
|
||||
|
||||
const Catalog: StoreEntity[] = [
|
||||
{ name: "Magic Circle", image: "MagicCircle", short: "", gumroad: undefined, jinxxy: "" } // Placeholder
|
||||
];
|
||||
const Catalog: Record<string, StoreEntity> = {};
|
||||
|
||||
Catalog["MagicCircle"] = { images: ["MagicCircle"], name: "Magic Circle", description: "Mreowww", short: "magiccircle", category: "Amulets", gumroad: "https://doloro.gumroad.com/l/Amulet", jinxxy: "" } // Placeholder
|
||||
|
||||
export async function load() {
|
||||
return {
|
||||
|
||||
@@ -1,8 +1,35 @@
|
||||
<script lang="ts">
|
||||
let { data } = $props();
|
||||
import { snackProduct } from "./snacks.svelte";
|
||||
import type { StoreEntity } from "./+page.server.ts";
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
function groupByCategory(products: Record<string, StoreEntity>) {
|
||||
const groups: Map<string, string[]> = new Map();
|
||||
for (const [key, product] of Object.entries(products)) {
|
||||
const cat = product.category;
|
||||
if (!groups.has(cat)) {
|
||||
groups.set(cat, []);
|
||||
}
|
||||
groups.get(cat)!.push(key);
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
const categorized = groupByCategory(data.catalog);
|
||||
</script>
|
||||
|
||||
{#each data.catalog as item}
|
||||
{@render snackProduct(item)}
|
||||
<svelte:head>
|
||||
<title>Doloro Website [Store]</title>
|
||||
</svelte:head>
|
||||
|
||||
{#each Array.from(categorized.entries()) as [category, products]}
|
||||
<section class="StoreCategory">
|
||||
<h2 class="StoreCategoryTitle">{category}</h2>
|
||||
<div class="SnackCatagoryContainer">
|
||||
{#each products as key}
|
||||
{@render snackProduct(data.catalog[key], key)}
|
||||
{/each}
|
||||
</div>
|
||||
</section>
|
||||
{/each}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
export const prerender = true;
|
||||
|
||||
import { type StoreEntity } from "../+page.server.ts";
|
||||
|
||||
export type ProductPageData = {
|
||||
product: StoreEntity;
|
||||
slug: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
const Catalog: Record<string, StoreEntity> = {};
|
||||
|
||||
Catalog["MagicCircle"] = { images: ["MagicCircle"], name: "Magic Circle", description: "Mreowww", short: "magiccircle", category: "Amulets", gumroad: "https://doloro.gumroad.com/l/Amulet", jinxxy: "" }
|
||||
|
||||
export function entries() {
|
||||
return Object.keys(Catalog).map((slug) => ({ slug }));
|
||||
}
|
||||
|
||||
export async function load({ params }: { params: { slug: string } }) {
|
||||
const slug = params.slug;
|
||||
const product = Catalog[slug];
|
||||
|
||||
if (!product) {
|
||||
throw new Error(`Product not found: ${slug}`);
|
||||
}
|
||||
|
||||
return {
|
||||
product,
|
||||
slug,
|
||||
url: `/store/${slug}`
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
<script lang="ts">
|
||||
import { snackImage, snackImages } from "../func.svelte";
|
||||
import { storeButton } from "$lib/StoreButtons.svelte";
|
||||
import type { ProductPageData } from "./+page.server.ts";
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
let currentImageIndex = 0;
|
||||
|
||||
function selectImage(index: number) {
|
||||
currentImageIndex = index;
|
||||
}
|
||||
|
||||
function prevImage() {
|
||||
currentImageIndex = (currentImageIndex - 1 + data.product.images.length) % data.product.images.length;
|
||||
}
|
||||
|
||||
function nextImage() {
|
||||
currentImageIndex = (currentImageIndex + 1) % data.product.images.length;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ProductPage {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 30px;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
.ProductPageImageGallery {
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.ProductPageImageMain {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
border-width: 4px;
|
||||
border-style: groove;
|
||||
border-color: var(--accent-2);
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.GalleryControls {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
transform: translateY(-50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
pointer-events: none;
|
||||
|
||||
.GalleryNav {
|
||||
pointer-events: auto;
|
||||
background: var(--primary);
|
||||
border: 2px groove var(--accent-2);
|
||||
color: white;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
font-size: 1.2rem;
|
||||
opacity: 0.7;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.GalleryCounter {
|
||||
color: white;
|
||||
font-size: 1rem;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
padding: 4px 10px;
|
||||
border: 1px groove var(--accent-2);
|
||||
pointer-events: auto;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ProductPageThumbnails {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
|
||||
.Thumbnail {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 2px groove var(--accent-2);
|
||||
cursor: pointer;
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&.active {
|
||||
opacity: 1;
|
||||
border-color: var(--accent-1);
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ProductPageDetails {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.ProductPageInfo {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.ProductPageCategory {
|
||||
font-size: 0.9rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
color: var(--accent-1);
|
||||
border-bottom: 2px groove var(--accent-2);
|
||||
padding-bottom: 6px;
|
||||
width: fit-content;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.ProductPageInfo h1 {
|
||||
font-size: 2rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ProductPageInfo p {
|
||||
font-size: 1.1rem;
|
||||
margin: 0;
|
||||
max-width: 450px;
|
||||
}
|
||||
|
||||
.ProductPageButtons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 12px;
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<svelte:head>
|
||||
<title>{data.product.name} | Doloro Store</title>
|
||||
<meta name="description" content={data.product.description} />
|
||||
<meta property="og:type" content="product" />
|
||||
<meta property="og:title" content={data.product.name} />
|
||||
<meta property="og:description" content={data.product.description} />
|
||||
<meta property="og:url" content={data.url} />
|
||||
</svelte:head>
|
||||
|
||||
<div class="ProductPage">
|
||||
<div class="ProductPageImageGallery">
|
||||
<div class="ProductPageImageMain">
|
||||
{#if data.product.images.length > 1}
|
||||
<div class="GalleryControls">
|
||||
<button class="GalleryNav prev" on:click={prevImage}>‹</button>
|
||||
<span class="GalleryCounter">{currentImageIndex + 1} / {data.product.images.length}</span>
|
||||
<button class="GalleryNav next" on:click={nextImage}>›</button>
|
||||
</div>
|
||||
{/if}
|
||||
<enhanced:img src={snackImage(data.product.images[currentImageIndex])} alt={data.product.name} />
|
||||
</div>
|
||||
{#if data.product.images.length > 1}
|
||||
<div class="ProductPageThumbnails">
|
||||
{#each data.product.images as img, i}
|
||||
<div class="Thumbnail {i === currentImageIndex ? 'active' : ''}" on:click={() => selectImage(i)}>
|
||||
<enhanced:img src={snackImage(img)} alt={`${data.product.name} image ${i + 1}`} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="ProductPageDetails">
|
||||
<div class="ProductPageInfo">
|
||||
<span class="ProductPageCategory">{data.product.category}</span>
|
||||
<h1>{data.product.name}</h1>
|
||||
<p>{data.product.description}</p>
|
||||
</div>
|
||||
<div class="ProductPageButtons">
|
||||
{#if data.product.gumroad != undefined}
|
||||
{@render storeButton("gumroad", data.product.gumroad!)}
|
||||
{/if}
|
||||
{#if data.product.jinxxy != undefined}
|
||||
{@render storeButton("jinxxy", data.product.jinxxy!)}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,69 @@
|
||||
.ProductPage {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 30px;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
.ProductPageImage {
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
border-width: 4px;
|
||||
border-style: groove;
|
||||
border-color: blue;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.ProductPageDetails {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.ProductPageInfo {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.ProductPageCategory {
|
||||
font-size: 0.9rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
color: #888;
|
||||
border-bottom: 2px groove blue;
|
||||
padding-bottom: 6px;
|
||||
width: fit-content;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.ProductPageInfo h1 {
|
||||
font-size: 2rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ProductPageInfo p {
|
||||
font-size: 1.1rem;
|
||||
margin: 0;
|
||||
max-width: 450px;
|
||||
}
|
||||
|
||||
.ProductPageButtons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 12px;
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { StoreEntity } from './+page.server.ts';
|
||||
|
||||
export const Catalog: Record<string, StoreEntity> = {};
|
||||
|
||||
Catalog["MagicCircle"] = { name: "Magic Circle", description: "Mreowww", image: "MagicCircle", short: "magiccircle", category: "Amulets", gumroad: "https://doloro.gumroad.com/l/Amulet", jinxxy: "" }
|
||||
@@ -19,4 +19,8 @@
|
||||
export function snackImage(img: string) {
|
||||
return trimmedImgs[img];
|
||||
}
|
||||
|
||||
export function snackImages(imgs: string[]) {
|
||||
return imgs.map(img => trimmedImgs[img]);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -4,29 +4,104 @@
|
||||
|
||||
border-width: 3px;
|
||||
border-style: groove;
|
||||
border-color: blue;
|
||||
border-color: var(--accent-2);
|
||||
|
||||
width: 300px;
|
||||
height: 500px;
|
||||
min-height: 500px;
|
||||
|
||||
picture {
|
||||
width: 300px;
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 300px;
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.SnackProductLink {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
|
||||
picture {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.SnackProductName {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.SnackProductPopOut {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: var(--accent-1);
|
||||
text-decoration: none;
|
||||
|
||||
svg {
|
||||
stroke: currentColor;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--accent-2);
|
||||
}
|
||||
}
|
||||
|
||||
.SnackProductDetails {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--card-field);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
padding: 12px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.SnackProductButtons {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.SnackCatagoryContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
row-gap: 25px;
|
||||
column-gap: 20px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.StoreCategory {
|
||||
margin-bottom: 40px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.StoreCategoryTitle {
|
||||
font-family: inherit;
|
||||
font-size: 1.8rem;
|
||||
margin: 0 0 15px 0;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 3px groove var(--accent-2);
|
||||
color: var(--card-raised);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,35 @@
|
||||
<script lang="ts" module>
|
||||
import { type StoreEntity } from "./+page.server.ts";
|
||||
import { snackImage } from "./func.svelte";
|
||||
import { storeButton } from "$lib/StoreButtons.svelte";
|
||||
import { ExternalLink } from "@lucide/svelte";
|
||||
import "./snacks.scss";
|
||||
export { snackProduct };
|
||||
</script>
|
||||
|
||||
{#snippet snackProduct(product: StoreEntity)}
|
||||
{#snippet snackProduct(product: StoreEntity, slug: string)}
|
||||
<div class="SnackProductContainer">
|
||||
<enhanced:img src={snackImage(product.image)} />
|
||||
<a href="/store/{slug}" class="SnackProductLink">
|
||||
<enhanced:img src={snackImage(product.images[0])} alt={product.name} />
|
||||
</a>
|
||||
<div class="SnackProductDetails">
|
||||
<h1>{product.name}</h1>
|
||||
<div class="SnackProductButtons"></div>
|
||||
<div>
|
||||
<h1 class="SnackProductName">
|
||||
{product.name}
|
||||
<a href="/store/{slug}" class="SnackProductPopOut">
|
||||
<ExternalLink size={16} />
|
||||
</a>
|
||||
</h1>
|
||||
<p>{product.description}</p>
|
||||
</div>
|
||||
<div class="SnackProductButtons">
|
||||
{#if product.gumroad != undefined}
|
||||
{@render storeButton("gumroad", product.gumroad!)}
|
||||
{/if}
|
||||
{#if product.jinxxy != undefined}
|
||||
{@render storeButton("jinxxy", product.jinxxy!)}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
Reference in New Issue
Block a user