Skip to content

Commit

Permalink
Merge pull request #39 from compose-us/feat/make-default-ui-customizable
Browse files Browse the repository at this point in the history
feat: update default ui
  • Loading branch information
nidhal-labidi authored Sep 24, 2024
2 parents d011b69 + 6b053b3 commit 8628fbc
Show file tree
Hide file tree
Showing 27 changed files with 1,127 additions and 1,167 deletions.
20 changes: 0 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,6 @@ Why no license (yet)? We want to share our progress, but we are not sure about t

We are about to explore ideas how we can solve the issue we described in detail about [UX challenges in web forms if you have a file on another device](https://github.com/compose-us/build-in-public/tree/main/updates/2023-10-23%20Defining%20our%20mission%20-%20Improve%20Web%20Form%20File%20Uploads).

### Todos

- [x] Build a server that allows file uploads from a form
- [x] Build a server that accepts files
- [x] Build a web form with an input field for files
- [ ] Let device A create a URL that allows connecting another device through WebRTC
- [ ] Allow only one connection per URL
- [ ] Establish a WebRTC connection between devices
- [ ] Have an upload field on that URL for device B
- [ ] Uploading to that URL populates the file field on device A

## Roadmap

- [ ] Make it easier to use by creating QR codes
- [ ] Make it possible for form developers to add our feature with a single script
- [ ] Find a business model that works for everybody
- [ ] Find a license that fits our needs
- [ ] Create a logo
- [ ] Build a website

## Update Instructions for Remote Server Deployment

These are the necessary steps to update the code on the remote server to the latest version.
Expand Down
2 changes: 2 additions & 0 deletions flottform/demo/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<script lang="ts">
import { base } from '$app/paths';
import '../app.postcss';
import '@flottform/forms/base.css';
import '@flottform/forms/theme/default.css';
</script>

<slot />
Expand Down
16 changes: 13 additions & 3 deletions flottform/demo/src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { base } from '$app/paths';
import { onMount } from 'svelte';
import { defaultThemeForFileInput, FlottformFileInputHost } from '@flottform/forms';
import { createDefaultFlottformComponent } from '@flottform/forms';
import { writable } from 'svelte/store';
import FileInput from '$lib/components/FileInput.svelte';
import { createClientUrl, sdpExchangeServerBase } from '../api';
Expand Down Expand Up @@ -101,16 +101,21 @@
isFillingOut = false;
};
let flottformAnchor: HTMLElement;
onMount(async () => {
const fileInputs = document.querySelectorAll(
'input[type=file]'
) as NodeListOf<HTMLInputElement>;
const flottformComponent = createDefaultFlottformComponent({
flottformAnchorElement: flottformAnchor
});
for (const file of fileInputs) {
const flottformFileInputHost = new FlottformFileInputHost({
flottformComponent.createFileItem({
flottformApi: sdpExchangeServerBase,
createClientUrl,
inputField: file,
theme: defaultThemeForFileInput()
label: file.id
});
}
});
Expand Down Expand Up @@ -144,6 +149,7 @@
up every few hours.
</p>
<form action="{base}/upload" method="POST" enctype="multipart/form-data" class="grid gap-8">
<div id="flottform-anchor" bind:this={flottformAnchor} class="flottform-anchor"></div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-6">
<div class="flex flex-col">
<label for="name">Name</label>
Expand Down Expand Up @@ -292,6 +298,10 @@
</div>

<style lang="postcss">
.flottform-anchor {
--flottform-border-width: 2px;
--flottform-border-color: #343af0;
}
.drag {
@apply border-2 border-dotted border-primary-blue;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<script lang="ts">
import { FlottformTextInputClient } from '@flottform/forms';
import { page } from '$app/stores';
import { onMount } from 'svelte';
import { sdpExchangeServerBase } from '../../../api';
let currentState = $state<
'init' | 'connected' | 'sending' | 'done' | 'error-user-denied' | 'error'
>('init');
let textInput: HTMLInputElement;
let sendTextToForm = $state<() => void>();
let textToSend = $state('');
onMount(async () => {
const flottformTextInputClient = new FlottformTextInputClient({
endpointId: $page.params.endpointId,
flottformApi: sdpExchangeServerBase
});
// Start the WebRTC connection process as soon as the page loads.
flottformTextInputClient.start();
// Listen to the events to update the UI appropriately
flottformTextInputClient.on('connected', () => {
currentState = 'connected';
});
flottformTextInputClient.on('sending', () => {
currentState = 'sending';
});
flottformTextInputClient.on('done', () => {
currentState = 'done';
});
flottformTextInputClient.on('error', () => {
currentState = 'error';
});
sendTextToForm = () => {
currentState = 'sending';
try {
flottformTextInputClient.sendText(textToSend);
console.log(textToSend);
} catch (err) {
currentState = 'error';
console.error('Error getting navigators current position', err);
}
};
});
</script>

<div class="max-w-screen-xl mx-auto p-8 box-border grid grid-cols-1 gap-8">
<h1>Flottform "Return and complaints" client</h1>
<p>Use this form to send a text from this device to the open form on the main device.</p>

<form action="" on:submit={sendTextToForm}>
<div class="flex flex-col gap-4">
<label for="flottform">Send your text</label>
<input
type="text"
name="flottform"
id="flottform"
bind:this={textInput}
bind:value={textToSend}
class=" rounded p-2 border-primary-blue border-2"
/>
{#if currentState === 'sending'}
<div class="h-24 items-center">
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" class="w-12 spinner-svg">
<circle cx="50" cy="50" r="45" class="spinner" />
</svg>
</div>
{:else if currentState === 'done'}
<div class="flex gap-6">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" version="1.1" class="w-12">
<path
d="M 28.28125 6.28125 L 11 23.5625 L 3.71875 16.28125 L 2.28125 17.71875 L 10.28125 25.71875 L 11 26.40625 L 11.71875 25.71875 L 29.71875 7.71875 Z "
class="checkmark"
stroke-linecap="round"
pathLength="1"
stroke-width="2"
stroke="#3ab53a"
fill="none"
/>
</svg>
<p>Your text is successfully sent</p>
</div>
{:else if currentState === 'connected'}
<button
type="submit"
class="group relative w-fit cursor-pointer overflow-hidden rounded-md border-2 bg-primary-blue text-white border-primary-blue px-12 py-3 font-semibold disabled:border-gray-300 disabled:bg-gray-200 disabled:text-gray-500 disabled:pointer-events-none"
>
<span
class="ease absolute top-1/2 h-0 w-64 origin-center -translate-x-20 rotate-45 bg-white transition-all duration-300 group-hover:h-64 group-hover:-translate-y-32"
/>
<span class="ease relative transition duration-300 group-hover:text-primary-blue"
>Send</span
>
</button>
{:else if currentState === 'error'}
<h2 class="animate-bounce">Ouch!</h2>
<p>There was an error connecting to flottform! 😬</p>
<p>Please try again with a new QR code by clicking the button again on the main form.</p>
{/if}
</div>
</form>

<div>Connection state: {currentState}</div>
</div>

<style lang="postcss">
.spinner-svg {
animation: 2s linear infinite svg-animation;
}
.spinner {
@apply block fill-transparent stroke-primary-blue;
stroke-linecap: round;
stroke-dasharray: 283;
stroke-dashoffset: 280;
stroke-width: 8px;
transform-origin: 50% 50%;
animation: spinner 1.4s ease-in-out infinite both;
}
.checkmark {
stroke-dasharray: 1;
stroke-dashoffset: 1;
animation: dash 1s linear 1 forwards;
}
@keyframes spinner {
0%,
25% {
stroke-dashoffset: 280;
transform: rotate(0);
}
50%,
75% {
stroke-dashoffset: 65;
transform: rotate(45deg);
}
100% {
stroke-dashoffset: 280;
transform: rotate(360deg);
}
}
@keyframes rotate {
0% {
transform: rotateZ(0deg);
}
100% {
transform: rotateZ(360deg);
}
}
@keyframes dash {
from {
stroke-dashoffset: 1;
}
to {
stroke-dashoffset: 0;
}
}
</style>
61 changes: 21 additions & 40 deletions flottform/demo/src/routes/multiple-input-form/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import { FlottformFileInputHost, defaultThemeForFileInput } from '@flottform/forms';
import { createDefaultFlottformComponent } from '@flottform/forms';
import { onMount } from 'svelte';
import { browser } from '$app/environment';
import { env } from '$env/dynamic/public';
Expand All @@ -16,67 +16,41 @@
return `${clientBase}/${endpointId}`;
};
let flottformAnchor: HTMLElement;
onMount(async () => {
const fileInputs = document.querySelectorAll(
'input[type=file]'
) as NodeListOf<HTMLInputElement>;
const flottformComponent = createDefaultFlottformComponent({
flottformAnchorElement: flottformAnchor
});
for (const file of fileInputs) {
const flottformFileInputHost = new FlottformFileInputHost({
flottformComponent.createFileItem({
flottformApi: sdpExchangeServerBase,
createClientUrl,
inputField: file,
theme: defaultThemeForFileInput()
label: file.id || file.name || 'File'
});
}
// flottformFileInputHost.on('new', () => {
// // Optional: Custom UI
// });
// flottformFileInputHost.on('connected', () => {
// // Optional: Custom UI
// });
// flottformFileInputHost.on('receive', () => {
// // Optional: Custom UI
// });
// flottformFileInputHost.on('progress', (p) => {
// // Optional: Custom UI
// console.log('progress=', p);
// });
// flottformFileInputHost.on('disconnected', () => {
// // Optional: Custom UI
// });
// flottformFileInputHost.on('error', (err) => {
// // Optional: Custom UI
// });
// flottformFileInputHost.on('endpoint-created', ({ link, qrCode }) => {
// // Optional: Custom UI
// });
// flottformFileInputHost.on('webrtc:waiting-for-client', (link) => {
// // Optional: Custom UI
// });
// flottformFileInputHost.on('webrtc:waiting-for-ice', () => {
// // Optional: Custom UI
// });
// flottformFileInputHost.on('webrtc:waiting-for-file', () => {
// // Optional: Custom UI
// });
// flottformFileInputHost.on('done', () => {
// // Optional: Custom UI
// });
// flottformFileInputHost.start();
});
</script>

<svelte:head>
<title>Flottform DEMO</title>
</svelte:head>

<div
id="flottform-anchor"
bind:this={flottformAnchor}
class="absolute top-0 right-0 w-64 flottform-anchor"
></div>
<div class="max-w-screen-xl mx-auto p-8 box-border grid grid-cols-1 gap-8">
<h1>Multiple Input Form</h1>
<form class="grid grid-cols-1 gap-8">
<label class="grid">
<span>Please upload the first file:</span>
<input type="file" name="fileA" multiple />
<input type="file" name="fileA" id="document-A" multiple />
</label>
<label class="grid">
<span>Please upload the second file:</span>
Expand All @@ -103,6 +77,13 @@
</div>

<style lang="postcss">
.flottform-anchor {
--flottform-border-style: dashed;
--flottform-root-border-width: 0 0 1px 1px;
--flottform-root-border-style: solid;
--flottform-root-border-color: #808080;
--flottform-root-border-radius: 0px 0px 0 10px;
}
.flottform {
@apply absolute top-0 right-0;
}
Expand Down
Loading

0 comments on commit 8628fbc

Please sign in to comment.