commit 5044b14d66f071b15f4c918b07b34d069b32432b
parent 4db7eb5818466e43f567e99f142da27888aac7aa
Author: mokou <mokou@posteo.de>
Date: Thu, 21 May 2020 00:03:18 +0200
feat: Design for the creation page
Diffstat:
6 files changed, 322 insertions(+), 1 deletion(-)
diff --git a/package-lock.json b/package-lock.json
@@ -263,6 +263,11 @@
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
"dev": true
},
+ "atoa": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/atoa/-/atoa-1.0.0.tgz",
+ "integrity": "sha1-DMDpGkgOc4+SPrwQNnZHF3mzSkk="
+ },
"autoprefixer": {
"version": "9.8.0",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.0.tgz",
@@ -345,6 +350,16 @@
"integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==",
"dev": true
},
+ "bullseye": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/bullseye/-/bullseye-1.5.0.tgz",
+ "integrity": "sha1-gaZ4ZYGUjfR7sdaQvb9IRMuGC4w=",
+ "requires": {
+ "crossvent": "^1.3.1",
+ "seleccion": "2.0.0",
+ "sell": "^1.0.0"
+ }
+ },
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
@@ -525,6 +540,15 @@
"integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=",
"dev": true
},
+ "contra": {
+ "version": "1.9.4",
+ "resolved": "https://registry.npmjs.org/contra/-/contra-1.9.4.tgz",
+ "integrity": "sha1-9TveQtfltZhcrk2ZqNYQUm3o8o0=",
+ "requires": {
+ "atoa": "1.0.0",
+ "ticky": "1.0.1"
+ }
+ },
"cosmiconfig": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
@@ -558,6 +582,14 @@
}
}
},
+ "crossvent": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/crossvent/-/crossvent-1.5.4.tgz",
+ "integrity": "sha1-2ixPj0DJR4JRe/K+7BBEFIGUq5I=",
+ "requires": {
+ "custom-event": "1.0.0"
+ }
+ },
"css-color-names": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
@@ -810,6 +842,16 @@
}
}
},
+ "custom-event": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.0.tgz",
+ "integrity": "sha1-LkYovhncSyFLXAJjDFlx6BFhgGI="
+ },
+ "dayjs": {
+ "version": "1.8.27",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.27.tgz",
+ "integrity": "sha512-Jpa2acjWIeOkg8KURUHICk0EqnEFSSF5eMEscsOgyJ92ZukXwmpmRkPSUka7KHSfbj5eKH30ieosYip+ky9emQ=="
+ },
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
@@ -1492,6 +1534,11 @@
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
"dev": true
},
+ "fuzzysearch": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/fuzzysearch/-/fuzzysearch-1.0.3.tgz",
+ "integrity": "sha1-3/yA9tawQiPyImqnndGUIxCW0Ag="
+ },
"generic-names": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz",
@@ -1580,12 +1627,39 @@
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
"dev": true
},
+ "hash-sum": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
+ "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ="
+ },
"hex-color-regex": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
"integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==",
"dev": true
},
+ "horsey": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/horsey/-/horsey-4.2.2.tgz",
+ "integrity": "sha1-RtQYk34Fcbdz6rNkv2wGEb+nAjg=",
+ "requires": {
+ "bullseye": "1.5.0",
+ "contra": "1.9.4",
+ "crossvent": "1.5.4",
+ "fuzzysearch": "1.0.3",
+ "hash-sum": "1.0.2",
+ "lodash": "4.13.1",
+ "sektor": "1.1.4",
+ "sell": "1.0.0"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "4.13.1",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.13.1.tgz",
+ "integrity": "sha1-g+SxCRP0hJbU0W/sSlYK8u50S2g="
+ }
+ }
+ },
"hosted-git-info": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
@@ -3822,6 +3896,21 @@
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true
},
+ "sektor": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/sektor/-/sektor-1.1.4.tgz",
+ "integrity": "sha1-TM7kQczyrP5GlYws5GhCbKfHYuY="
+ },
+ "seleccion": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/seleccion/-/seleccion-2.0.0.tgz",
+ "integrity": "sha1-CYSsHo31E+OLQaYI5lBC6DgeCnM="
+ },
+ "sell": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/sell/-/sell-1.0.0.tgz",
+ "integrity": "sha1-O6yn5R943e6eIu6hrHR6Y2i9FjA="
+ },
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@@ -4331,6 +4420,11 @@
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
"dev": true
},
+ "ticky": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ticky/-/ticky-1.0.1.tgz",
+ "integrity": "sha1-t8+nHnaPHJAAxJe5FRswlHxQ5G0="
+ },
"timsort": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
diff --git a/package.json b/package.json
@@ -24,6 +24,8 @@
"tailwindcss": "^1.4.6"
},
"dependencies": {
+ "dayjs": "^1.8.27",
+ "horsey": "^4.2.2",
"navaid": "^1.1.1",
"pouchdb-browser": "^7.2.1",
"sirv-cli": "^0.4.4"
diff --git a/src/components/DateTimeGrid.svelte b/src/components/DateTimeGrid.svelte
@@ -0,0 +1,124 @@
+<script>
+ import day from 'dayjs'
+ import relativeTime from 'dayjs/plugin/relativeTime'
+ day.extend(relativeTime)
+
+ export let startDate
+ export let selected = []
+ let day1 = null
+ let datesDay1 = []
+ let day2 = null
+ let datesDay2 = []
+ let day3 = null
+ let datesDay3 = []
+ let view = [0, 5]
+ initDays(day(startDate))
+
+ function initDays (start) {
+ let first = start
+ if (start.date() === day(startDate).date()) {
+ day1 = day(startDate)
+ first = day1.add(30, 'minutes').startOf('hour')
+ } else {
+ day1 = start
+ }
+ datesDay1 = [first]
+ let indexDay1 = first
+ while (indexDay1.add(30, 'minutes').date() === day1.date()) {
+ indexDay1 = indexDay1.add(30, 'minutes')
+ datesDay1.push(indexDay1)
+ }
+ day2 = day1.add(1, 'days').startOf('day')
+ datesDay2 = [day2]
+ let indexDay2 = day2
+ while (indexDay2.add(30, 'minutes').date() === day2.date()) {
+ indexDay2 = indexDay2.add(30, 'minutes')
+ datesDay2.push(indexDay2)
+ }
+ day3 = day2.add(1, 'days').startOf('day')
+ datesDay3 = [day3]
+ let indexDay3 = day3
+ while (indexDay3.add(30, 'minutes').date() === day3.date()) {
+ indexDay3 = indexDay3.add(30, 'minutes')
+ datesDay3.push(indexDay3)
+ }
+ }
+
+ function previousDay () {
+ if (day1.date() !== day(startDate).date()) {
+ initDays(day1.subtract(1, 'day').startOf('day'))
+ }
+ }
+
+ function addOrRemove (date) {
+ if (selected.includes(date.unix())) {
+ let c = selected
+ c.splice(selected.indexOf(date.unix()), 1)
+ selected = c
+ } else {
+ selected = [...selected, date.unix()]
+ }
+ console.log(selected)
+ }
+
+ function nextDay () {
+ initDays(day1.add(1, 'day').startOf('day'))
+ }
+</script>
+
+<div class="grid grid-cols-6 w-full datetimegrid">
+ <div class="text-center hover:cursor-pointer" on:click={previousDay}>
+ {day1.date() === day(startDate).date() ? '' : '▲'}
+ </div>
+ <div class="text-center hover:cursor-pointer" on:click={() => view = view[0] !== 0 ? [view[0] - 1, view[1] - 1] : view}>
+ {view[0] !== 0 ? '‹' : ''}
+ </div>
+ <div class="col-span-3"></div>
+ <div class="text-center hover:cursor-pointer" on:click={() => view = [view[0] + 1, view[1] + 1]}>›</div>
+ <div class="font-bold">{day1.date() === day(startDate).date() ? 'today' : day1.endOf('day').fromNow()}</div>
+ {#if datesDay1.slice(view[0], view[1]).length < 5}
+ {#each new Array(5 - datesDay1.slice(view[0], view[1]).length) as a}
+ <div></div>
+ {/each}
+ {/if}
+ {#each datesDay1.slice(view[0], view[1]) as t}
+ <div
+ class="text-center time hover:cursor-pointer"
+ class:bg-purple-600={selected.includes(t.unix())}
+ class:text-white={selected.includes(t.unix())}
+ on:click={() => addOrRemove(t)}
+ >{t.format('hh:mm')}</div>
+ {/each}
+
+ <div>{day2.date() === day(startDate).date() ? 'today' : day2.endOf('day').fromNow()}</div>
+ {#each datesDay2.slice(view[0], view[1]) as t}
+ <div
+ class="text-center time hover:cursor-pointer"
+ class:bg-purple-600={selected.includes(t.unix())}
+ class:text-white={selected.includes(t.unix())}
+ on:click={() => addOrRemove(t)}
+ >{t.format('hh:mm')}</div>
+ {/each}
+
+ <div>{day3.date() === day(startDate).date() ? 'today' : day3.endOf('day').fromNow()}</div>
+ {#each datesDay3.slice(view[0], view[1]) as t}
+ <div
+ class="text-center time hover:cursor-pointer"
+ class:bg-purple-600={selected.includes(t.unix())}
+ class:text-white={selected.includes(t.unix())}
+ on:click={() => addOrRemove(t)}
+ >{t.format('hh:mm')}</div>
+ {/each}
+ <div class="text-center hover:cursor-pointer" on:click={nextDay}>
+ ▼
+ </div>
+</div>
+
+<div class="mt-2">
+ {selected.length} potential time{selected.length === 1 ? '' : 's'} selected:
+ <ul class="list-disc">
+ {#each selected as s}
+ <li><span class="font-bold">{day.unix(s).format('DD/MM/YYYY hh:mm')}</span> ({day.unix(s).fromNow()})</li>
+ {/each}
+ </ul>
+</div>
diff --git a/src/main.css b/src/main.css
@@ -14,4 +14,64 @@ body {
font-family: 'Inter';
}
+input {
+ @apply block w-full px-5;
+ background-color: #fff;
+ border-color: #d2d6dc;
+ border-width: 1px;
+ border-radius: .375rem;
+ padding: .5rem .75rem;
+ font-size: 1rem;
+ line-height: 1.5;
+}
+
+.btn {
+ @apply px-3 py-2 font-bold bg-purple-600 text-white border-purple-600 rounded-sm;
+ font-family: 'Inter';
+}
+
+.datetimegrid div {
+ @apply px-2 py-2 border transition duration-300;
+}
+
+.datetimegrid div.time:hover {
+ @apply bg-purple-600 text-white;
+}
+
+.sey-show {
+ @apply absolute bg-white border border-gray-600 w-64;
+}
+
+.sey-show .sey-item:first-of-type {
+ @apply pt-2;
+}
+
+.sey-show .sey-item {
+ @apply text-xl transition duration-300 px-3;
+}
+
+.sey-show .sey-item:last-of-type {
+ @apply pb-2;
+}
+
+.sey-show .sey-item:hover {
+ @apply cursor-pointer bg-purple-600 text-white;
+}
+
+.sey-container:not(.sey-show) {
+ display: none;
+}
+
+input:focus {
+ outline: none;
+ box-shadow: 0 0 0 3px rgba(164, 202, 254, .45);
+ border-color: #a4cafe;
+}
+
+@media sm {
+ input {
+ @apply text-sm leading-tight;
+ }
+}
+
@import 'tailwindcss/utilities';
diff --git a/src/pages/Index.svelte b/src/pages/Index.svelte
@@ -1,5 +1,34 @@
<script>
+ import horsey from 'horsey'
+ import { onMount } from 'svelte'
+ import DateTimeGrid from '../components/DateTimeGrid.svelte'
+ let durationInput = null
+ let durationsList = [
+ '15 minutes',
+ '30 minutes',
+ '45 minutes',
+ '1 hour',
+ '2 hours',
+ '3 hours',
+ '4 hours',
+ '5 hours'
+ ]
+ let event = {
+ name: '',
+ duration: '',
+ times: []
+ }
+
+ async function submitForm () {
+
+ }
+
+ onMount(() => {
+ durationInput = horsey(document.querySelector('#duration-mount'), {
+ source: [{ list: durationsList }]
+ })
+ })
</script>
<h1 class="text-5xl font-serif font-extrabold">koro</h1>
@@ -8,3 +37,12 @@
meeting, party, raid, whatever you want. It automatically supports the user's timezone
and works locally, too.
</p>
+
+<form class="max-w-xl mt-10" on:submit|preventDefault={submitForm}>
+ <label for="name" class="font-bold text-gray-600">Your event's name</label>
+ <input name="name" type="text" bind:value={event.name} placeholder="Raid with the boys" />
+ <label for="duration" class="font-bold text-gray-600 mt-3">Duration of the event</label>
+ <input id="duration-mount" class="mb-5" bind:value={event.duration} name="duration-mount" placeholder="Start typing to see options..." />
+ <DateTimeGrid startDate={new Date()} bind:selected={event.times} />
+ <button class="btn mt-5" type="submit">Create event</button>
+</form>
diff --git a/tailwind.config.js b/tailwind.config.js
@@ -2,5 +2,8 @@ module.exports = {
purge: [
'./src/**/*.svelte',
'./src/**/*.js'
- ]
+ ],
+ variants: {
+ cursor: ['hover']
+ }
}