Add the first few things

This commit is contained in:
k3y0708
2023-10-09 13:14:43 +00:00
parent 0abf42c926
commit b2815dabce
12 changed files with 533 additions and 74 deletions

View File

@@ -1,38 +1,11 @@
# create-svelte
# RestRover
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
RestRover is a REST client written in JavaScript (of course with HTML and CSS).
## Creating a project
# Devices it should support in (more or less) near future
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npm create svelte@latest
# create a new project in my-app
npm create svelte@latest my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
To create a production version of your app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
- Web Browser
- iPad
- Mac OS
- Windows
- Linux

View File

@@ -32,5 +32,8 @@
"vite": "^4.4.2",
"vitest": "^0.32.2"
},
"type": "module"
"type": "module",
"dependencies": {
"pg": "^8.11.3"
}
}

110
pnpm-lock.yaml generated
View File

@@ -4,6 +4,11 @@ settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
dependencies:
pg:
specifier: ^8.11.3
version: 8.11.3
devDependencies:
'@playwright/test':
specifier: ^1.28.1
@@ -784,6 +789,11 @@ packages:
resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
dev: true
/buffer-writer@2.0.0:
resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==}
engines: {node: '>=4'}
dev: false
/cac@6.7.14:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
@@ -1573,6 +1583,10 @@ packages:
p-limit: 3.1.0
dev: true
/packet-reader@1.0.0:
resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==}
dev: false
/parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
@@ -1616,6 +1630,70 @@ packages:
is-reference: 3.0.2
dev: true
/pg-cloudflare@1.1.1:
resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
requiresBuild: true
dev: false
optional: true
/pg-connection-string@2.6.2:
resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==}
dev: false
/pg-int8@1.0.1:
resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
engines: {node: '>=4.0.0'}
dev: false
/pg-pool@3.6.1(pg@8.11.3):
resolution: {integrity: sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==}
peerDependencies:
pg: '>=8.0'
dependencies:
pg: 8.11.3
dev: false
/pg-protocol@1.6.0:
resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==}
dev: false
/pg-types@2.2.0:
resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
engines: {node: '>=4'}
dependencies:
pg-int8: 1.0.1
postgres-array: 2.0.0
postgres-bytea: 1.0.0
postgres-date: 1.0.7
postgres-interval: 1.2.0
dev: false
/pg@8.11.3:
resolution: {integrity: sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==}
engines: {node: '>= 8.0.0'}
peerDependencies:
pg-native: '>=3.0.1'
peerDependenciesMeta:
pg-native:
optional: true
dependencies:
buffer-writer: 2.0.0
packet-reader: 1.0.0
pg-connection-string: 2.6.2
pg-pool: 3.6.1(pg@8.11.3)
pg-protocol: 1.6.0
pg-types: 2.2.0
pgpass: 1.0.5
optionalDependencies:
pg-cloudflare: 1.1.1
dev: false
/pgpass@1.0.5:
resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
dependencies:
split2: 4.2.0
dev: false
/picocolors@1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
dev: true
@@ -1701,6 +1779,28 @@ packages:
source-map-js: 1.0.2
dev: true
/postgres-array@2.0.0:
resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
engines: {node: '>=4'}
dev: false
/postgres-bytea@1.0.0:
resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==}
engines: {node: '>=0.10.0'}
dev: false
/postgres-date@1.0.7:
resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==}
engines: {node: '>=0.10.0'}
dev: false
/postgres-interval@1.2.0:
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
engines: {node: '>=0.10.0'}
dependencies:
xtend: 4.0.2
dev: false
/prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
@@ -1862,6 +1962,11 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/split2@4.2.0:
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
engines: {node: '>= 10.x'}
dev: false
/stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
dev: true
@@ -2271,6 +2376,11 @@ packages:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: true
/xtend@4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
dev: false
/yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
dev: true

View File

@@ -4,6 +4,9 @@
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Open+Sans&display=swap" rel="stylesheet">
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">

View File

@@ -1,23 +0,0 @@
<script lang="ts">
export let name: string;
export let stage: string;
export let date: string;
export let begin_time: string;
export let end_time: string;
</script>
<div>
<h2>{name}</h2>
<slot />
<span>{stage}</span>
<span>{date}</span>
<span>From {begin_time} to {end_time}</span>
</div>
<style>
div {
background-color: #f0f0f0;
padding: 1rem;
border-radius: 0.5rem;
}
</style>

View File

@@ -0,0 +1,30 @@
<script lang="ts">
export let id: string;
export let verb: string;
</script>
<a href="/request/{id}" class="outer">
<span class="verb">{verb}</span>
<slot />
</a>
<style>
.outer {
display: block;
margin-bottom: 0.5rem;
text-decoration: none;
color: #fff;
}
.verb {
display: inline-block;
width: 5rem;
text-align: center;
background-color: #fff;
color: #000;
border-radius: 0.5rem;
margin-right: 0.5rem;
overflow: hidden;
text-overflow: ellipsis;
}
</style>

24
src/lib/requests.ts Normal file
View File

@@ -0,0 +1,24 @@
export function getAllRequests() {
const request = [];
request.push({
id: '1',
method: 'GET',
name: 'Request 1',
url: 'https://syfdxgchvjbknl.free.beeceptor.com/todos'
});
request.push({
id: '2',
method: 'POST',
name: 'Request 2',
url: 'https://www.google.com'
});
request.push({ id: '3', method: 'PUT', name: 'Request 3' });
request.push({ id: '4', method: 'DELETE', name: 'Request 4' });
request.push({ id: '5', method: 'OPTIONS', name: 'Request 5' });
request.push({ id: '6', method: 'HEAD', name: 'Request 6' });
request.push({ id: '7', method: 'PATCH', name: 'Request 7' });
request.push({ id: '8', method: 'TRACE', name: 'Request 8' });
request.push({ id: '9', method: 'CONNECT', name: 'Request 9' });
return request;
}

75
src/routes/+layout.svelte Normal file
View File

@@ -0,0 +1,75 @@
<script lang="ts">
import RequestElement from '$lib/RequestElement.svelte';
import { getAllRequests } from '$lib/requests';
let filter = '';
function getRequest(filter: string): {
id: string;
method: string;
name: string;
}[] {
let request = getAllRequests();
return request.filter((r) => r.name.toLowerCase().includes(filter.toLowerCase()));
}
</script>
<nav>
<input type="text" placeholder="Search" bind:value={filter} />
<div id="request-holder">
{#each getRequest(filter) as request}
<RequestElement id={request.id} verb={request.method}>
{request.name}
</RequestElement>
{/each}
</div>
</nav>
<main>
<slot />
</main>
<style>
/* Hide scrollbar */
::-webkit-scrollbar {
display: none;
}
:global(body) {
margin: 0;
padding: 0;
background-color: #323232;
color: #fff;
font-family: 'Open Sans', sans-serif;
}
main {
position: fixed;
top: 1rem;
right: 1rem;
height: calc(100vh - 2rem);
width: calc(80vw - 1.5rem);
overflow-y: auto;
overflow-x: hidden;
}
nav {
position: fixed;
top: 1rem;
left: 1rem;
height: calc(100vh - 2rem);
width: calc(20vw - 1.5rem);
}
nav input {
width: 80%;
height: 2rem;
border-radius: 0.5rem;
border: none;
background-color: #fff;
padding: 0 0.5rem;
}
#request-holder {
margin-top: 1rem;
}
</style>

View File

@@ -1,15 +1 @@
<script>
import Element from "$lib/Element.svelte";
</script>
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>
<Element
name="page"
stage="page stage"
date="page date"
begin_time="start"
end_time="end"
>
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Unde iure, esse sequi deleniti veniam quos! Exercitationem, cumque fugit eaque, veniam optio labore distinctio tempore impedit libero ad numquam delectus non!
</Element>
TEXT

View File

@@ -0,0 +1,59 @@
<script lang="ts">
import { page } from '$app/stores';
import { getAllRequests } from '$lib/requests';
import Request from './Request.svelte';
import Response from './Response.svelte';
$: req = getAllRequests().find((r) => r.id === $page.params.id);
$: name = req?.name || '';
$: method = req?.method || 'GET';
$: requestUrl = req?.url || '';
$: headers = [{ key: 'User-Agent', value: 'RestRover/0.0.1' }];
$: body = '';
$: responseBody = '';
$: responseHeaders = {};
async function doRequest() {
const response = await fetch(requestUrl, {
method: method,
headers: {
...headers.reduce((acc, header) => {
if (header.key) {
// @ts-ignore
acc[header.key] = header.value;
}
return acc;
}, {})
}
});
console.log(response);
let data = await response.text();
responseBody = data;
responseHeaders = Object.fromEntries(response.headers.entries());
}
</script>
<h1>{$page.params.id} - {name}</h1>
<div>
<input type="text" bind:value={method} />
<input type="text" bind:value={requestUrl} />
<button on:click={doRequest}> Send </button>
</div>
<h2>Request</h2>
<Request bind:headers bind:body />
<h2>Response</h2>
<Response body={responseBody} headers={responseHeaders} />
<h3>cURL</h3>
<pre>
curl{#if method != 'GET'} -X {method}{/if} {requestUrl}
{#each headers as header}
-H "{header.key}: {header.value}"
{/each}
{#if body}
-d '{body}'
{/if}
</pre>

View File

@@ -0,0 +1,117 @@
<script lang="ts">
export let headers: {
key: string;
value: string;
}[] = [];
export let body: string = '';
</script>
<div class="tabbed">
<input checked id="tab-request-body" type="radio" name="tabs-request" />
<input id="tab-request-headers" type="radio" name="tabs-request" />
<input id="tab-request-unused" type="radio" name="tabs-request" />
<nav>
<label for="tab-request-body">Body</label>
<label for="tab-request-headers">Headers</label>
<label for="tab-request-unused">Cookies</label>
</nav>
<figure>
<div class="tab-request-body">
<textarea bind:value={body} />
</div>
<div class="tab-request-headers">
{#each headers as header}
<div class="single-header">
<input type="text" bind:value={header.key} />
<input type="text" bind:value={header.value} />
<button
on:click={() => {
headers = headers.filter((h) => h !== header);
}}>Remove</button
>
</div>
{/each}
<button
on:click={() => {
headers = [...headers, { key: '', value: '' }];
}}>Add</button
>
</div>
<div class="tab-request-unused">...</div>
</figure>
</div>
<style>
/* Tabs mit radio-Buttons */
.tabbed figure {
display: block;
margin-left: 0;
border-bottom: 1px solid silver;
clear: both;
}
.tabbed > input,
.tabbed figure > div {
display: none;
}
.tabbed figure > div {
padding: 20px;
width: 100%;
border: 1px solid silver;
background: #fff;
line-height: 1.5em;
letter-spacing: 0.3px;
color: #444;
}
#tab-request-body:checked ~ figure .tab-request-body,
#tab-request-headers:checked ~ figure .tab-request-headers,
#tab-request-unused:checked ~ figure .tab-request-unused {
display: block;
}
nav label {
float: left;
padding: 15px 15px;
border-top: 1px solid silver;
border-right: 1px solid silver;
background: hsl(210, 50%, 50%);
color: #eee;
}
nav label:nth-child(1) {
border-left: 1px solid silver;
}
nav label:hover {
background: hsl(210, 50%, 40%);
}
nav label:active {
background: #ffffff;
}
#tab-request-body:checked ~ nav label[for='tab-request-body'],
#tab-request-headers:checked ~ nav label[for='tab-request-headers'],
#tab-request-unused:checked ~ nav label[for='tab-request-unused'] {
background: white;
color: #111;
position: relative;
border-bottom: none;
}
#tab-request-body:checked ~ nav label[for='tab-request-body']:after,
#tab-request-headers:checked ~ nav label[for='tab-request-headers']:after,
#tab-request-unused:checked ~ nav label[for='tab-request-unused']:after {
content: '';
display: block;
position: absolute;
height: 2px;
width: 100%;
background: white;
left: 0;
bottom: -1px;
}
</style>

View File

@@ -0,0 +1,102 @@
<script>
export let body = '';
export let headers = {};
</script>
<div class="tabbed">
<input checked id="tab1" type="radio" name="tabs" />
<input id="tab2" type="radio" name="tabs" />
<input id="tab3" type="radio" name="tabs" />
<nav>
<label for="tab1">Body</label>
<label for="tab2">Headers</label>
<label for="tab3">Cookies</label>
</nav>
<figure>
<div class="tab1">
<pre>{body}</pre>
</div>
<div class="tab2">
{#each Object.entries(headers) as [key, value]}
<div>
{key}: {value}
</div>
{/each}
</div>
<div class="tab3">...</div>
</figure>
</div>
<style>
/* Tabs mit radio-Buttons */
.tabbed figure {
display: block;
margin-left: 0;
border-bottom: 1px solid silver;
clear: both;
}
.tabbed > input,
.tabbed figure > div {
display: none;
}
.tabbed figure > div {
padding: 20px;
width: 100%;
border: 1px solid silver;
background: #fff;
line-height: 1.5em;
letter-spacing: 0.3px;
color: #444;
}
#tab1:checked ~ figure .tab1,
#tab2:checked ~ figure .tab2,
#tab3:checked ~ figure .tab3 {
display: block;
}
nav label {
float: left;
padding: 15px 15px;
border-top: 1px solid silver;
border-right: 1px solid silver;
background: hsl(210, 50%, 50%);
color: #eee;
}
nav label:nth-child(1) {
border-left: 1px solid silver;
}
nav label:hover {
background: hsl(210, 50%, 40%);
}
nav label:active {
background: #ffffff;
}
#tab1:checked ~ nav label[for='tab1'],
#tab2:checked ~ nav label[for='tab2'],
#tab3:checked ~ nav label[for='tab3'] {
background: white;
color: #111;
position: relative;
border-bottom: none;
}
#tab1:checked ~ nav label[for='tab1']:after,
#tab2:checked ~ nav label[for='tab2']:after,
#tab3:checked ~ nav label[for='tab3']:after {
content: '';
display: block;
position: absolute;
height: 2px;
width: 100%;
background: white;
left: 0;
bottom: -1px;
}
</style>