helpful stuff

This commit is contained in:
Omer Sabic 2024-06-20 23:21:22 +02:00
parent 199ca176cf
commit 4fc784e5c8
6 changed files with 300 additions and 200 deletions

8
package-lock.json generated
View File

@ -9,7 +9,7 @@
"version": "0.0.1", "version": "0.0.1",
"dependencies": { "dependencies": {
"aws-sdk": "^2.1628.0", "aws-sdk": "^2.1628.0",
"bits-ui": "^0.21.7", "bits-ui": "^0.21.10",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"tailwind-merge": "^2.3.0", "tailwind-merge": "^2.3.0",
@ -1468,9 +1468,9 @@
} }
}, },
"node_modules/bits-ui": { "node_modules/bits-ui": {
"version": "0.21.7", "version": "0.21.10",
"resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-0.21.7.tgz", "resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-0.21.10.tgz",
"integrity": "sha512-1PKp90ly1R6jexIiAUj1Dk4u2pln7ok+L8Vc0rHMY7pi7YZvadFNZvkp1G5BtmL8qh2xsn4MVNgKjPAQMCxW0A==", "integrity": "sha512-KuweEOKO0Rr8XX87dQh46G9mG0bZSmTqNxj5qBazz4OTQC+oPKui04/wP/ISsCOSGFomaRydTULqh4p+nsyc2g==",
"dependencies": { "dependencies": {
"@internationalized/date": "^3.5.1", "@internationalized/date": "^3.5.1",
"@melt-ui/svelte": "0.76.2", "@melt-ui/svelte": "0.76.2",

View File

@ -18,6 +18,9 @@
"@sveltejs/vite-plugin-svelte": "^3.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0",
"@tabler/icons-svelte": "^3.3.0", "@tabler/icons-svelte": "^3.3.0",
"autoprefixer": "^10.4.16", "autoprefixer": "^10.4.16",
"formsnap": "^1.0.0",
"lucide-svelte": "^0.373.0",
"mode-watcher": "^0.3.0",
"postcss": "^8.4.32", "postcss": "^8.4.32",
"postcss-load-config": "^5.0.2", "postcss-load-config": "^5.0.2",
"prettier": "^3.1.1", "prettier": "^3.1.1",
@ -27,23 +30,20 @@
"svelte-awesome-color-picker": "^3.0.6", "svelte-awesome-color-picker": "^3.0.6",
"svelte-check": "^3.6.0", "svelte-check": "^3.6.0",
"svelte-legos": "^0.2.2", "svelte-legos": "^0.2.2",
"tailwindcss": "^3.3.6",
"timeago.js": "^4.0.2",
"typescript": "^5.0.0",
"vite": "^5.0.3",
"formsnap": "^1.0.0",
"lucide-svelte": "^0.373.0",
"mode-watcher": "^0.3.0",
"svelte-markdown": "^0.4.1", "svelte-markdown": "^0.4.1",
"svelte-motion": "^0.12.2", "svelte-motion": "^0.12.2",
"svelte-radix": "^1.1.0", "svelte-radix": "^1.1.0",
"svelte-sonner": "^0.3.22", "svelte-sonner": "^0.3.22",
"sveltekit-superforms": "^2.12.6" "sveltekit-superforms": "^2.12.6",
"tailwindcss": "^3.3.6",
"timeago.js": "^4.0.2",
"typescript": "^5.0.0",
"vite": "^5.0.3"
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"aws-sdk": "^2.1628.0", "aws-sdk": "^2.1628.0",
"bits-ui": "^0.21.7", "bits-ui": "^0.21.10",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"tailwind-merge": "^2.3.0", "tailwind-merge": "^2.3.0",

View File

@ -0,0 +1,12 @@
<script>
import { Collapsible as CollapsiblePrimitive } from "bits-ui";
import { slide } from "svelte/transition";
export let transition = slide;
export let transitionConfig = {
duration: 150,
};
</script>
<CollapsiblePrimitive.Content {transition} {transitionConfig} {...$$restProps}>
<slot />
</CollapsiblePrimitive.Content>

View File

@ -0,0 +1,13 @@
import { Collapsible as CollapsiblePrimitive } from "bits-ui";
import Content from "./collapsible-content.svelte";
const Root = CollapsiblePrimitive.Root;
const Trigger = CollapsiblePrimitive.Trigger;
export {
Root,
Content,
Trigger,
//
Root as Collapsible,
Content as CollapsibleContent,
Trigger as CollapsibleTrigger,
};

View File

@ -141,16 +141,16 @@
</Select.Trigger> </Select.Trigger>
<Select.Content> <Select.Content>
<Select.Group> <Select.Group>
<Select.Item value="700" label="Short (~700 words)" <Select.Item value="700" label="Short"
>Short (~700 words)</Select.Item >Short</Select.Item
> >
<Select.Item value="1500" label="Medium (~1500 words)" <Select.Item value="1500" label="Medium"
>Medium (~1500 words) >Medium
<!-- <ProBadge /> --> <!-- <ProBadge /> -->
</Select.Item> </Select.Item>
<!-- disabled={['free', 'basic'].includes(tier)} --> <!-- disabled={['free', 'basic'].includes(tier)} -->
<Select.Item value="2500" label="Long (~2500 words)" <Select.Item value="2500" label="Long"
>Long (~2500 words) >Long
<!-- <ProBadge /> --> <!-- <ProBadge /> -->
</Select.Item> </Select.Item>
</Select.Group> </Select.Group>

View File

@ -11,6 +11,10 @@
import { Textarea } from '$lib/components/ui/textarea'; import { Textarea } from '$lib/components/ui/textarea';
import * as Tooltip from '$lib/components/ui/tooltip'; import * as Tooltip from '$lib/components/ui/tooltip';
import { config } from '$lib'; import { config } from '$lib';
import { QuestionMarkCircled } from 'svelte-radix';
import ChevronsUpDown from 'lucide-svelte/icons/chevrons-up-down';
import * as Collapsible from '$lib/components/ui/collapsible/index.js';
import { Button } from '$lib/components/ui/button/index.js';
/** @type {import("./$types").PageServerData} */ /** @type {import("./$types").PageServerData} */
export let data; export let data;
@ -71,200 +75,271 @@
} }
let disable_freebies = !$formData.use_freebie; let disable_freebies = !$formData.use_freebie;
let disable_autopublish = !$formData.auto_publish;
$: disable_freebies = !$formData.use_freebie; $: disable_freebies = !$formData.use_freebie;
$: disable_autopublish = !$formData.auto_publish;
</script> </script>
<div class="w-full max-w-7xl"> <div class="w-full max-w-7xl">
<form method="post" use:enhance enctype="multipart/form-data"> <form method="post" use:enhance enctype="multipart/form-data">
<input type="text" value={data.blog_info.id} name="id" readonly class="hidden" /> <input type="text" value={data.blog_info.id} name="id" readonly class="hidden" />
<div class="grid grid-cols-1 gap-16 md:grid-cols-2 md:grid-rows-1"> <div class="grid grid-cols-1 gap-16 md:grid-cols-2 md:grid-rows-1">
<div> <div>
<h2 class="mb-4 text-2xl font-bold">Basics</h2> <Collapsible.Root class="space-y-2">
<Form.Field {form} name="name"> <div class="flex items-center justify-between space-x-4 border-b px-4">
<Form.Control let:attrs> <h2 class="mb-4 text-2xl font-bold">Basics</h2>
<Form.Label>Blog name</Form.Label> <Collapsible.Trigger asChild let:builder>
<Input {...attrs} bind:value={$formData.name} /> <Button builders={[builder]} variant="ghost" size="sm" class="w-9 p-0">
</Form.Control> <ChevronsUpDown class="h-4 w-4" />
<Form.Description /> <span class="sr-only">Toggle</span>
<Form.FieldErrors /> </Button>
</Form.Field> </Collapsible.Trigger>
<Form.Field {form} name="title"> </div>
<Form.Control let:attrs> <Collapsible.Content class="space-y-2">
<Form.Label>Blog title</Form.Label> <Form.Field {form} name="name">
<Input {...attrs} bind:value={$formData.title} /> <Form.Control let:attrs>
</Form.Control> <Form.Label>Blog name</Form.Label>
<Form.Description /> <Input {...attrs} bind:value={$formData.name} />
<Form.FieldErrors /> </Form.Control>
</Form.Field> <Form.Description />
<Form.Field {form} name="subtitle"> <Form.FieldErrors />
<Form.Control let:attrs> </Form.Field>
<Form.Label>Blog subtitle</Form.Label> <Form.Field {form} name="title">
<Input {...attrs} bind:value={$formData.subtitle} /> <Form.Control let:attrs>
</Form.Control> <Form.Label>Blog title</Form.Label>
<Form.Description /> <Input {...attrs} bind:value={$formData.title} />
<Form.FieldErrors /> </Form.Control>
</Form.Field> <Form.Description />
<Form.FieldErrors />
<Form.Field {form} name="primary_color_hex"> </Form.Field>
<Form.Control let:attrs> <Form.Field {form} name="subtitle">
<Form.Label>Primary color</Form.Label> <Form.Control let:attrs>
<ColorPicker <Form.Label>Blog subtitle</Form.Label>
on:input={(e) => { <Input {...attrs} bind:value={$formData.subtitle} />
if (e.detail.hex) $formData.primary_color_hex = e.detail.hex; </Form.Control>
}} <Form.Description />
hex={data.blog_info.primary_color_hex} <Form.FieldErrors />
{...attrs} </Form.Field>
/> <Form.Field {form} name="primary_color_hex">
</Form.Control> <Form.Control let:attrs>
<Form.Description /> <Form.Label>Primary color</Form.Label>
<Form.FieldErrors /> <ColorPicker
</Form.Field> on:input={(e) => {
<Form.Field {form} name="secondary_color_hex"> if (e.detail.hex) $formData.primary_color_hex = e.detail.hex;
<Form.Control let:attrs> }}
<Form.Label>Secondary color</Form.Label> hex={data.blog_info.primary_color_hex}
<ColorPicker {...attrs}
on:input={(e) => { />
if (e.detail.hex) $formData.secondary_color_hex = e.detail.hex; </Form.Control>
}} <Form.Description />
hex={data.blog_info.secondary_color_hex} <Form.FieldErrors />
{...attrs} </Form.Field>
/> <Form.Field {form} name="secondary_color_hex">
</Form.Control> <Form.Control let:attrs>
<Form.Description /> <Form.Label>Secondary color</Form.Label>
<Form.FieldErrors /> <ColorPicker
</Form.Field> on:input={(e) => {
<Form.Field {form} name="text_color_hex"> if (e.detail.hex) $formData.secondary_color_hex = e.detail.hex;
<Form.Control let:attrs> }}
<Form.Label>Text color</Form.Label> hex={data.blog_info.secondary_color_hex}
<ColorPicker {...attrs}
on:input={(e) => { />
if (e.detail.hex) $formData.text_color_hex = e.detail.hex; </Form.Control>
}} <Form.Description />
hex={data.blog_info.text_color_hex} <Form.FieldErrors />
{...attrs} </Form.Field>
/> <Form.Field {form} name="text_color_hex">
</Form.Control> <Form.Control let:attrs>
<Form.Description /> <Form.Label>Text color</Form.Label>
<Form.FieldErrors /> <ColorPicker
</Form.Field> on:input={(e) => {
<Form.Field {form} name="domain"> if (e.detail.hex) $formData.text_color_hex = e.detail.hex;
<Form.Control let:attrs> }}
<Form.Label>Custom domain</Form.Label> hex={data.blog_info.text_color_hex}
<Input {...attrs} bind:value={$formData.domain} /> {...attrs}
</Form.Control> />
{#if data.blog_info.subdomain_slug} </Form.Control>
<Form.Description <Form.Description />
>You can also access your website at <a <Form.FieldErrors />
href="http://{data.blog_info.subdomain_slug}.{config.sites_url}" </Form.Field>
class="font-semibold underline" <Form.Field {form} name="domain">
>{data.blog_info.subdomain_slug}.{config.sites_url}</a <Form.Control let:attrs>
></Form.Description <Form.Label>Custom domain</Form.Label>
> <Input {...attrs} bind:value={$formData.domain} />
{/if} </Form.Control>
<Form.FieldErrors /> {#if data.blog_info.subdomain_slug}
</Form.Field> <Form.Description
<Form.Field {form} name="auto_publish"> >You can also access your website at <a
<Form.Control let:attrs> href="http://{data.blog_info.subdomain_slug}.{config.sites_url}"
<Tooltip.Root> class="font-semibold underline"
<Tooltip.Trigger> >{data.blog_info.subdomain_slug}.{config.sites_url}</a
<Form.Label>Auto Publish</Form.Label> ></Form.Description
</Tooltip.Trigger> >
<Tooltip.Content> {/if}
<p>Automatically creates a blog post for you when you upload a video</p> <Form.FieldErrors />
</Tooltip.Content> </Form.Field>
</Tooltip.Root> </Collapsible.Content>
<Switch {...attrs} bind:checked={$formData.auto_publish} /> </Collapsible.Root>
</Form.Control>
<Form.FieldErrors />
</Form.Field>
</div> </div>
<div> <div>
<h2 class="mb-4 text-2xl font-bold">Freebies</h2> <Collapsible.Root class="space-y-2">
<Form.Field {form} name="use_freebie"> <div class="flex items-center justify-between space-x-4 border-b px-4">
<Form.Control let:attrs> <h2 class="mb-4 text-2xl font-bold">Freebies</h2>
<Form.Label class="text-right">Send freebie</Form.Label> <Collapsible.Trigger asChild let:builder>
<div class="flex items-center justify-start"> <Button builders={[builder]} variant="ghost" size="sm" class="w-9 p-0">
<!-- <Switch disabled={['free', 'basic'].includes(tier)} {...attrs} /> --> <ChevronsUpDown class="h-4 w-4" />
<Switch {...attrs} bind:checked={$formData.use_freebie} /> <span class="sr-only">Toggle</span>
<!-- <ProBadge class="ml-[10px]" /> --> </Button>
</Collapsible.Trigger>
</div>
<Collapsible.Content class="space-y-2">
<Form.Field {form} name="use_freebie">
<Form.Control let:attrs>
<Form.Label class="text-right">Send freebie</Form.Label>
<div class="flex items-center justify-start">
<!-- <Switch disabled={['free', 'basic'].includes(tier)} {...attrs} /> -->
<Switch {...attrs} bind:checked={$formData.use_freebie} />
<!-- <ProBadge class="ml-[10px]" /> -->
</div>
<Form.Description
>Whether to send a freebie when a new person enters their email on your website.</Form.Description
>
</Form.Control>
</Form.Field>
<Form.Field {form} name="freebie_name">
<Form.Control let:attrs>
<Form.Label class="text-right">Freebie Name</Form.Label>
<div class="flex items-center justify-start">
<Input
{...attrs}
bind:value={$formData.freebie_name}
bind:readonly={disable_freebies}
/>
</div>
</Form.Control>
<Form.FieldErrors />
</Form.Field>
<Form.Field {form} name="freebie_url">
<Form.Control let:attrs>
<Form.Label class="text-right">Freebie file</Form.Label>
<div class="flex items-center justify-start">
<Input
type="file"
on:input={(e) =>
handleFileChange(e, $formData.freebie_url).then((x) => {
$formData.freebie_url = x;
})}
bind:disabled={disable_freebies}
/>
<Input {...attrs} class="hidden" bind:value={$formData.freebie_url} readonly />
</div>
</Form.Control>
<Form.Description>Maximum size of 5MB (TEMPORARY)</Form.Description>
<Form.FieldErrors />
</Form.Field>
<div class="hidden">
<Form.Field {form} name="freebie_image_url">
<Form.Control let:attrs>
<Form.Label class="text-right">Freebie image</Form.Label>
<div class="flex items-center justify-start">
<Input
type="file"
accept="png,jpg,webp,jpeg"
on:input={(e) =>
handleFileChange(e, $formData.freebie_image_url).then(
(x) => ($formData.freebie_image_url = x)
)}
bind:disabled={disable_freebies}
/>
<Input
{...attrs}
class="hidden"
bind:value={$formData.freebie_image_url}
readonly
/>
</div>
</Form.Control>
<Form.FieldErrors />
</Form.Field>
</div> </div>
<Form.Description
>Whether to send a freebie when a new person enters their email on your website.</Form.Description
>
</Form.Control>
</Form.Field>
<Form.Field {form} name="freebie_name">
<Form.Control let:attrs>
<Form.Label class="text-right">Freebie Name</Form.Label>
<div class="flex items-center justify-start">
<Input
{...attrs}
bind:value={$formData.freebie_name}
bind:readonly={disable_freebies}
/>
</div>
</Form.Control>
<Form.FieldErrors />
</Form.Field>
<Form.Field {form} name="freebie_url">
<Form.Control let:attrs>
<Form.Label class="text-right">Freebie file</Form.Label>
<div class="flex items-center justify-start">
<Input
type="file"
on:input={(e) =>
handleFileChange(e, $formData.freebie_url).then((x) => {
$formData.freebie_url = x;
})}
bind:disabled={disable_freebies}
/>
<Input {...attrs} class="hidden" bind:value={$formData.freebie_url} readonly />
</div>
</Form.Control>
<Form.Description>Maximum size of 5MB (TEMPORARY)</Form.Description>
<Form.FieldErrors />
</Form.Field>
<div class="hidden">
<Form.Field {form} name="freebie_image_url">
<Form.Control let:attrs>
<Form.Label class="text-right">Freebie image</Form.Label>
<div class="flex items-center justify-start">
<Input
type="file"
accept="png,jpg,webp,jpeg"
on:input={(e) =>
handleFileChange(e, $formData.freebie_image_url).then(
(x) => ($formData.freebie_image_url = x)
)}
bind:disabled={disable_freebies}
/>
<Input
{...attrs}
class="hidden"
bind:value={$formData.freebie_image_url}
readonly
/>
</div>
</Form.Control>
<Form.FieldErrors />
</Form.Field>
</div>
<Form.Field {form} name="freebie_text"> <Form.Field {form} name="freebie_text">
<Form.Control let:attrs> <Form.Control let:attrs>
<Form.Label class="text-right">Freebie text</Form.Label> <Form.Label class="text-right">Freebie text</Form.Label>
<div class="flex items-center justify-start"> <div class="flex items-center justify-start">
<Textarea {...attrs} bind:value={$formData.freebie_text} /> <Textarea {...attrs} bind:value={$formData.freebie_text} />
</div> </div>
</Form.Control> </Form.Control>
<Form.FieldErrors /> <Form.FieldErrors />
<Form.Description <Form.Description
>The text displayed next to the signup form on your blog.</Form.Description >The text displayed next to the signup form on your blog.</Form.Description
> >
</Form.Field> </Form.Field>
</Collapsible.Content>
</Collapsible.Root>
</div>
<div>
<Collapsible.Root class="space-y-2">
<div class="flex items-center justify-between space-x-4 border-b px-4">
<h2 class="mb-4 text-2xl font-bold">Auto publish</h2>
<Collapsible.Trigger asChild let:builder>
<Button builders={[builder]} variant="ghost" size="sm" class="w-9 p-0">
<ChevronsUpDown class="h-4 w-4" />
<span class="sr-only">Toggle</span>
</Button>
</Collapsible.Trigger>
</div>
<Collapsible.Content class="space-y-2">
<Form.Field {form} name="auto_publish">
<Form.Control let:attrs>
<Form.Label>Auto Publish</Form.Label>
<div class="flex items-center justify-start">
<Switch {...attrs} bind:checked={$formData.auto_publish} />
</div>
</Form.Control>
<Form.FieldErrors />
<Form.Description
>Automatically creates a blog post for you when you upload a video</Form.Description
>
</Form.Field>
<Form.Field {form} name="freebie_name">
<Form.Control let:attrs>
<Form.Label class="text-right">Freebie Name</Form.Label>
<div class="flex items-center justify-start">
<Input
{...attrs}
bind:value={$formData.freebie_name}
bind:readonly={disable_freebies}
/>
</div>
</Form.Control>
<Form.FieldErrors />
</Form.Field>
<Form.Field {form} name="freebie_url">
<Form.Control let:attrs>
<Form.Label class="text-right">Freebie file</Form.Label>
<div class="flex items-center justify-start">
<Input
type="file"
on:input={(e) =>
handleFileChange(e, $formData.freebie_url).then((x) => {
$formData.freebie_url = x;
})}
bind:disabled={disable_freebies}
/>
<Input {...attrs} class="hidden" bind:value={$formData.freebie_url} readonly />
</div>
</Form.Control>
<Form.Description>Maximum size of 5MB (TEMPORARY)</Form.Description>
<Form.FieldErrors />
</Form.Field>
</Collapsible.Content>
</Collapsible.Root>
</div> </div>
</div> </div>
<div class="mt-4">
<Form.Button disabled={!isTainted($tainted)}>Submit</Form.Button> <Form.Button disabled={!isTainted($tainted)}>Submit</Form.Button>
</div>
</form> </form>
</div> </div>