aboutsummaryrefslogtreecommitdiff
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