about summary refs log tree commit diff
path: root/client/src/Components
diff options
context:
space:
mode:
authorMelonai <einebeere@gmail.com>2021-01-20 23:18:09 +0100
committerMelonai <einebeere@gmail.com>2021-01-20 23:18:09 +0100
commit826c7c47785ee01d2b9267919132ada696425344 (patch)
tree901cc90be9a953a6c3f968b6c1abe33cc13774b4 /client/src/Components
parent2953dec527cedaabaa5f0eb48637c5ddd4a4103b (diff)
downloadshorest-826c7c47785ee01d2b9267919132ada696425344.tar.zst
shorest-826c7c47785ee01d2b9267919132ada696425344.zip
Remade the client in SvelteKit
Diffstat (limited to 'client/src/Components')
-rw-r--r--client/src/Components/Button.js15
-rw-r--r--client/src/Components/CopyButton.js24
-rw-r--r--client/src/Components/Form.js39
-rw-r--r--client/src/Components/Form.svelte64
-rw-r--r--client/src/Components/Loader.js13
-rw-r--r--client/src/Components/Response.js55
-rw-r--r--client/src/Components/Response.svelte33
-rw-r--r--client/src/Components/ResponseContainer.js12
-rw-r--r--client/src/Components/Responses.svelte24
-rw-r--r--client/src/Components/Title.js12
-rw-r--r--client/src/Components/Title.svelte22
-rw-r--r--client/src/Components/icons/ArrowIcon.svelte10
-rw-r--r--client/src/Components/icons/CrossIcon.svelte10
13 files changed, 163 insertions, 170 deletions
diff --git a/client/src/Components/Button.js b/client/src/Components/Button.js
deleted file mode 100644
index b6ed91b..0000000
--- a/client/src/Components/Button.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import {faArrowRight, faTimes} from '@fortawesome/free-solid-svg-icons';
-
-function Button(props) {
-    return (
-        <div className="button-container">
-            <button type="submit" className={"button" + (props.valid ? "" : " disabled")} id="btn" onClick={props.submit}>
-                <FontAwesomeIcon icon={props.valid ? faArrowRight : faTimes}/>
-            </button>
-        </div>
-    )
-}
-
-export default Button;
\ No newline at end of file
diff --git a/client/src/Components/CopyButton.js b/client/src/Components/CopyButton.js
deleted file mode 100644
index 65c4cb9..0000000
--- a/client/src/Components/CopyButton.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import React, {useState} from 'react';
-import copy from 'clipboard-copy';
-
-function CopyButton(props) {
-    const [copied, setCopied] = useState(false);
-
-    const handleClick = async () => {
-        await copy("https://sho.rest/" + props.hash);
-        setCopied(true);
-    };
-
-    let content;
-    if (copied) {
-        content = <span>Link Copied!</span>;
-    } else {
-        content = <strong>Copy Link</strong>;
-    }
-
-    return (
-        <span className="copy-text right-item" onClick={handleClick}>{content}</span>
-    )
-}
-
-export default CopyButton;
\ No newline at end of file
diff --git a/client/src/Components/Form.js b/client/src/Components/Form.js
deleted file mode 100644
index 979d9c9..0000000
--- a/client/src/Components/Form.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import React, {useState} from 'react';
-import Button from './Button';
-import isURL from "validator/lib/isURL";
-
-function Form(props) {
-    const [state, setState] = useState({value: '', valid: false});
-
-    const handleSubmit = () => {
-        if (state.valid) {
-            props.addRequest(state.value);
-        }
-    };
-
-    const handleChange = e => {
-        const userInput = e.target.value;
-        const valid = isURL('https://' + userInput);
-        setState({value: userInput, valid: valid});
-    };
-
-    const handlePaste = e => {
-        e.preventDefault();
-        const pattern = /^https?:\/\//;
-        setState({value: e.clipboardData.getData('Text').replace(pattern, ''), valid: false});
-    };
-
-    return (
-        <form id="form" onSubmit={(e) => e.preventDefault()}>
-            <div className="input-group">
-                <div className="input-container">
-                    <span className="input-field-text">https://</span>
-                    <input className="input-field" required value={state.value} onChange={handleChange} onPaste={handlePaste}/>
-                </div>
-                <Button valid={state.valid} submit={handleSubmit}/>
-            </div>
-        </form>
-    )
-}
-
-export default Form;
\ No newline at end of file
diff --git a/client/src/Components/Form.svelte b/client/src/Components/Form.svelte
new file mode 100644
index 0000000..327d25d
--- /dev/null
+++ b/client/src/Components/Form.svelte
@@ -0,0 +1,64 @@
+<script lang="ts">
+    import shorten from "$actions/shorten";
+    import { links } from "$data/links";
+    import checkUrl from "$utils/checkUrl";
+    import debounce from "$utils/debounce";
+    import ArrowIcon from "./icons/ArrowIcon.svelte";
+    import CrossIcon from "./icons/CrossIcon.svelte";
+
+    let value = "";
+    let valid = false;
+
+    function submit() {
+        const url = checkUrl(value);
+        if (url !== null) {
+            links.add(shorten(url));
+        }
+    }
+
+    const check = debounce(() => valid = !!checkUrl(value), 100);
+
+    // @ts-ignore: Value is a dependency
+    $: value, check();
+</script>
+
+<style>
+    form {
+        position: relative;
+        border: 1px solid #aaaabb;
+        box-shadow: 0 4px 6px #aaaabb30;
+        box-sizing: border-box;
+        border-radius: 5px;
+    }
+
+    .field {
+        box-sizing: border-box;
+        width: 100%;
+        border: none;
+        padding: 15px 50px 15px 20px;
+        background: transparent;
+        font-size: 1rem;
+    }
+
+    .button {
+        position: absolute;
+        right: 10px;
+        margin: auto;
+        top: 0;
+        bottom: 0;
+        background: transparent;
+        border: none;
+        cursor: pointer;
+    }
+</style>
+
+<form on:submit|preventDefault={submit}>
+    <input class="field" bind:value type="text"/>
+    <button class="button" type="submit">
+        {#if valid}
+            <ArrowIcon/>
+        {:else}
+            <CrossIcon/>
+        {/if}
+    </button>
+</form>
diff --git a/client/src/Components/Loader.js b/client/src/Components/Loader.js
deleted file mode 100644
index 3f4c47f..0000000
--- a/client/src/Components/Loader.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react';
-
-function Loader() {
-    return (
-        <div className="ball-pulse">
-            <div/>
-            <div/>
-            <div/>
-        </div>
-    )
-}
-
-export default Loader;
\ No newline at end of file
diff --git a/client/src/Components/Response.js b/client/src/Components/Response.js
deleted file mode 100644
index f69000a..0000000
--- a/client/src/Components/Response.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import React, {useEffect, useState} from 'react';
-import axios from "axios";
-import Loader from "./Loader";
-import CopyButton from "./CopyButton";
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faBomb } from '@fortawesome/free-solid-svg-icons';
-
-function Response(props){
-    const CancelToken = axios.CancelToken;
-    const [requestState, setRequestState] = useState({loading: true, cancel: CancelToken.source()});
-
-    useEffect(() => {
-        axios.post('/', {url: "https://" + props.url}, {cancelToken: requestState.cancel.token})
-            .then((r) => {
-                setRequestState({loading: false, hash: r.data.hash, cancel: requestState.cancel});
-            }).catch((e) => {
-                if (!axios.isCancel(e)) {
-                    setRequestState({loading: false, error: true, cancel: requestState.cancel});
-                }
-            });
-
-        return () => {
-            requestState.cancel.cancel();
-        };
-    }, [props.url, requestState.cancel])
-
-    let text;
-    let rightItem;
-    if (!requestState.loading) {
-        if (!requestState.error) {
-            rightItem = <CopyButton hash={requestState.hash}/>;
-            if (props.url.length < 20) {
-                text =
-                    <span>The short link for <strong>{props.url}</strong> is<br/><strong>sho.rest/{requestState.hash}</strong></span>;
-            } else {
-                text =
-                    <span>The short link for your URL is<br/><strong>sho.rest/{requestState.hash}</strong></span>;
-            }
-        } else {
-            rightItem = <FontAwesomeIcon className="right-item" icon={faBomb}/>;
-            text = <span>There was an error.</span>
-        }
-    } else {
-        text = <Loader/>
-    }
-
-    return (
-        <div className={"response-container" + (requestState.error ? " disabled" : "")}>
-            <div className={"title response-text" + (requestState.error ? " disabled" : "")}>{text}</div>
-            {rightItem}
-        </div>
-    )
-}
-
-export default Response;
\ No newline at end of file
diff --git a/client/src/Components/Response.svelte b/client/src/Components/Response.svelte
new file mode 100644
index 0000000..215af1b
--- /dev/null
+++ b/client/src/Components/Response.svelte
@@ -0,0 +1,33 @@
+<script lang="ts">
+    import type { ShortenRequest } from "$actions/shorten";
+
+    export let info: ShortenRequest;
+</script>
+
+<style>
+    div {
+        display: flex;
+        justify-content: space-between;
+    }
+
+    .url {
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+    }
+
+    .output {
+        margin-left: 50px;
+    }
+</style>
+
+<div>
+    <span class="url">{info.url}</span>
+    {#await info.response}
+        <span class="output">Loading...</span>
+    {:then { hash }} 
+        <a class="output" href="https://sho.rest/{hash}">sho.rest/{hash}</a>
+    {:catch { error }}
+        <span class="output">{error}</span>
+    {/await}
+</div>
\ No newline at end of file
diff --git a/client/src/Components/ResponseContainer.js b/client/src/Components/ResponseContainer.js
deleted file mode 100644
index 8fad4bd..0000000
--- a/client/src/Components/ResponseContainer.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from 'react';
-import Response from "./Response";
-
-function ResponseContainer(props){
-    const responseContent = props.requests.map((r) => <Response key={r.key} url={r.url}/>);
-
-    return (
-        responseContent
-    )
-}
-
-export default ResponseContainer;
\ No newline at end of file
diff --git a/client/src/Components/Responses.svelte b/client/src/Components/Responses.svelte
new file mode 100644
index 0000000..7124f1e
--- /dev/null
+++ b/client/src/Components/Responses.svelte
@@ -0,0 +1,24 @@
+<script lang="ts">
+    import Response from "./Response.svelte"
+    import { slide } from 'svelte/transition';
+    import { links } from "$data/links";
+</script>
+
+<style>
+    ul {
+        list-style: none;
+        padding: 0 10px;
+    }
+
+    li {
+        margin-bottom: 10px;
+    }
+</style>
+
+<ul>
+    {#each $links as info (info.nonce)}
+        <li transition:slide >
+            <Response {info}/>
+        </li>
+    {/each}
+</ul>
\ No newline at end of file
diff --git a/client/src/Components/Title.js b/client/src/Components/Title.js
deleted file mode 100644
index 8ea96a9..0000000
--- a/client/src/Components/Title.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from 'react';
-
-function Title() {
-    return (
-        <div className="title">
-            <span><b>sho.rest</b><br/></span>
-            <span>Made with ❤ by <b>Mel</b></span>
-        </div>
-    )
-}
-
-export default Title;
\ No newline at end of file
diff --git a/client/src/Components/Title.svelte b/client/src/Components/Title.svelte
new file mode 100644
index 0000000..4266eb1
--- /dev/null
+++ b/client/src/Components/Title.svelte
@@ -0,0 +1,22 @@
+<style>
+    p {
+        color: #212121;
+        margin: 0 0 5px 0;
+    }
+
+    .text {
+        margin: 10px 0 15px 0;
+    }
+
+    img {
+        width: 25px;
+    }
+</style>
+
+<div>
+    <img src="/shorest.svg" alt=""/>
+    <div class="text">
+        <p><b>sho.rest</b></p>
+        <p>Made with ❤ by <b>Mel</b></p>
+    </div>
+</div>
diff --git a/client/src/Components/icons/ArrowIcon.svelte b/client/src/Components/icons/ArrowIcon.svelte
new file mode 100644
index 0000000..52c79ae
--- /dev/null
+++ b/client/src/Components/icons/ArrowIcon.svelte
@@ -0,0 +1,10 @@
+<style>
+    svg {
+        width: 20px;
+        color: #212121;
+    }
+</style>
+
+<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" />
+</svg>
\ No newline at end of file
diff --git a/client/src/Components/icons/CrossIcon.svelte b/client/src/Components/icons/CrossIcon.svelte
new file mode 100644
index 0000000..55525d8
--- /dev/null
+++ b/client/src/Components/icons/CrossIcon.svelte
@@ -0,0 +1,10 @@
+<style>
+    svg {
+        width: 20px;
+        color: #212121;
+    }
+</style>
+
+<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
+</svg>
\ No newline at end of file