kinkgarden/kinkgarden

View on GitHub
editor/assets/Editor.svelte

Summary

Maintainability
Test Coverage
<script>
    import TabSelector from "./TabSelector.svelte";
    import EditorTab from "./EditorTab.svelte";
    import CustomTab from "./CustomTab.svelte";
    import SaveTab from "./SaveTab.svelte";
    import { dbData, columns, customData } from "./index.js";

    function fetchKink(kink, kinkData) {
        let { name, description, id } = kinkData.find((k) => k.id === kink.id);
        return { custom: kink.custom, name, description, id };
    }

    export let action = "";
    export let patreonClientId = "";
    export let patreonOk = false;
    export let patreonError = undefined;
    export let listId = "";

    let full_columns;
    $: {
        full_columns = $columns.map((column) => ({
            name: column.name,
            kinks: column.kinks.map((x) =>
                fetchKink(x, x.custom ? $customData : dbData.kinks)
            ),
        }));
    }

    let viewPassword = "";
    let editPassword = "";

    function dragstart(event, fromMenu) {
        if (fromMenu) {
            event.dataTransfer.effectAllowed = "copy";
        } else {
            event.dataTransfer.effectAllowed = "move";
        }
        let kink = {
            id: parseInt(event.target.dataset.id),
            custom: event.target.dataset.custom === "true",
        };
        event.dataTransfer.setData("application/json", JSON.stringify(kink));
    }

    function dragover(event, column) {
        // can't reject illegitimate drags because we can't get the data out of the drag event 😔
        event.dataTransfer.dropEffect = event.dataTransfer.effectAllowed;
    }

    function drop(event, column) {
        if (column !== null) {
            const data = event.dataTransfer;
            let { id, custom } = JSON.parse(data.getData("application/json"));
            // must defer so that if we drag to ourself we add after we remove
            // (there are almost certainly better ways to handle this)
            setTimeout(() => {
                $columns[column].kinks = [
                    ...$columns[column].kinks,
                    { custom, id },
                ];
            });
        }
    }

    function dragend(event, column) {
        const data = event.dataTransfer;
        if (data.dropEffect === "move" && column !== null) {
            let id = parseInt(event.target.dataset.id);
            let custom = event.target.dataset.custom === "true";
            $columns[column].kinks = $columns[column].kinks.filter(
                (k) => k.id !== id || k.custom !== custom
            );
        }
    }
</script>

<article>
    <TabSelector
        options={[{ component: EditorTab, label: 'Editor' }, { component: CustomTab, label: 'Custom' }, { component: SaveTab, label: 'Save' }]}
        {dragstart}
        {dragover}
        {drop}
        saveFormAction={action}
        {fetchKink}
        {patreonClientId}
        {patreonOk}
        {patreonError}
        {listId} />
    {#each full_columns as column, i}
        <div
            class="column"
            on:dragover|preventDefault={(event) => dragover(event, i)}
            on:drop|preventDefault={(event) => drop(event, i)}>
            <h2>
                <svg class="icon {column.name}">
                    <use xlink:href="#{column.name}" />
                </svg>
            </h2>
            <div class="kinks" data-kink-column={i}>
                {#each column.kinks as kink}
                    <div
                        class="kink"
                        draggable="true"
                        on:dragstart={(event) => dragstart(event, false)}
                        on:dragend={(event) => dragend(event, i)}
                        data-id={kink.id}
                        data-custom={kink.custom}>
                        <p title={kink.description}>{kink.name}</p>
                        <p class="description">{kink.description}</p>
                    </div>
                {/each}
            </div>
        </div>
    {/each}
</article>