From 39e7a3aed41adac42988c0dff70152c3342c3284 Mon Sep 17 00:00:00 2001 From: lexx Date: Sat, 28 Sep 2024 18:36:18 +0300 Subject: [PATCH] wip file field --- front/js/components/dropdown.js | 47 +++++- front/js/helpers/clickOutside.js | 8 + front/js/helpers/debounce.js | 72 +++++++++ front/js/main.js | 7 + front/js/recordEditor/colorPicker.js | 13 ++ front/sass/app.scss | 4 + front/views/components/dropdown.blade.php | 2 +- front/views/components/icon.blade.php | 148 ++++++++++++++++++ front/views/components/notice.blade.php | 2 +- front/views/components/switch.blade.php | 1 + front/views/components/tabs.blade.php | 22 +++ front/views/records-editor/edit.blade.php | 20 ++- .../records-editor/fieldHeader.blade.php | 17 ++ front/views/records-editor/fields.blade.php | 20 +++ .../records-editor/fields/color.blade.php | 25 +++ .../records-editor/fields/file.blade.php | 16 ++ .../fields/file/preview.blade.php | 50 ++++++ .../fields/file/thumb.blade.php | 59 +++++++ .../records-editor/fields/slug.blade.php | 18 +++ .../records-editor/fields/text.blade.php | 20 +++ front/views/records-editor/header.blade.php | 91 +++++++---- front/views/records-editor/status.blade.php | 27 ++++ front/views/records-editor/title.blade.php | 10 ++ src/Http/Controller/RecordController.php | 4 +- src/macros.php | 15 ++ 25 files changed, 674 insertions(+), 44 deletions(-) create mode 100644 front/js/helpers/clickOutside.js create mode 100644 front/js/helpers/debounce.js create mode 100644 front/js/recordEditor/colorPicker.js create mode 100644 front/views/components/icon.blade.php create mode 100644 front/views/components/switch.blade.php create mode 100644 front/views/components/tabs.blade.php create mode 100644 front/views/records-editor/fieldHeader.blade.php create mode 100644 front/views/records-editor/fields.blade.php create mode 100644 front/views/records-editor/fields/color.blade.php create mode 100644 front/views/records-editor/fields/file.blade.php create mode 100644 front/views/records-editor/fields/file/preview.blade.php create mode 100644 front/views/records-editor/fields/file/thumb.blade.php create mode 100644 front/views/records-editor/fields/slug.blade.php create mode 100644 front/views/records-editor/fields/text.blade.php create mode 100644 front/views/records-editor/status.blade.php create mode 100644 front/views/records-editor/title.blade.php diff --git a/front/js/components/dropdown.js b/front/js/components/dropdown.js index cb89cf3..04245bb 100644 --- a/front/js/components/dropdown.js +++ b/front/js/components/dropdown.js @@ -1,3 +1,46 @@ -export function init(){ +import {onClickOutside} from "./../helpers/clickOutside.js"; + +export function dropdown() { + document.querySelectorAll(".dropdown").forEach(el => { + dropdownInit(el); + }) +} + +function dropdownInit(el) { + const button = el.querySelector("button"); + const menu = el.querySelector(".dropdown-menu"); + button.addEventListener('click', function () { + if (menu.hasAttribute('hidden')) { + this.setAttribute('aria-expanded', 'true'); + menu.removeAttribute('hidden'); + + // Set focus on first link + // will be highlighted for keyboard users + menu.querySelector(".dropdown-item:first-child")?.focus(); + } else { + menu.setAttribute('hidden', 'true'); + this.setAttribute('aria-expanded', 'false'); + } + }); + + document.addEventListener('keydown', (event) => { + // Ignore IME composition + if (event.isComposing || event.key === "esc") { + return; + } + + // Close menu with ESC key + if (event.keyCode === 27) { + if (!menu.hasAttribute('hidden')) { + menu.setAttribute('aria-expanded', 'false'); + menu.setAttribute('hidden', 'true'); + } + } + }); + + onClickOutside(menu, ".dropdown", () => menu.hidden = true); + + +} + -} \ No newline at end of file diff --git a/front/js/helpers/clickOutside.js b/front/js/helpers/clickOutside.js new file mode 100644 index 0000000..36dbb9a --- /dev/null +++ b/front/js/helpers/clickOutside.js @@ -0,0 +1,8 @@ +export function onClickOutside(ele, closest, cb) { + document.addEventListener('click', function (event) { + if (!event.target.closest(closest)) { + cb(event) + } + }, false); +}; + diff --git a/front/js/helpers/debounce.js b/front/js/helpers/debounce.js new file mode 100644 index 0000000..cb427b6 --- /dev/null +++ b/front/js/helpers/debounce.js @@ -0,0 +1,72 @@ +export function throttle(delay, callback, options) { + const { + noTrailing = false, + noLeading = false, + debounceMode = undefined + } = options || {}; + + let timeoutID; + let cancelled = false; + let lastExec = 0; + + function clearExistingTimeout() { + if (timeoutID) { + clearTimeout(timeoutID); + } + } + + function cancel(options) { + const {upcomingOnly = false} = options || {}; + clearExistingTimeout(); + cancelled = !upcomingOnly; + } + + function wrapper(...arguments_) { + let self = this; + let elapsed = Date.now() - lastExec; + + if (cancelled) { + return; + } + + function exec() { + lastExec = Date.now(); + callback.apply(self, arguments_); + } + + function clear() { + timeoutID = undefined; + } + + if (!noLeading && debounceMode && !timeoutID) { + exec(); + } + + clearExistingTimeout(); + + if (debounceMode === undefined && elapsed > delay) { + if (noLeading) { + lastExec = Date.now(); + if (!noTrailing) { + timeoutID = setTimeout(debounceMode ? clear : exec, delay); + } + } else { + exec(); + } + } else if (noTrailing !== true) { + timeoutID = setTimeout( + debounceMode ? clear : exec, + debounceMode === undefined ? delay - elapsed : delay + ); + } + } + + wrapper.cancel = cancel; + return wrapper; +} + + +export function debounce(delay, callback, options) { + const {atBegin = false} = options || {}; + return throttle(delay, callback, {debounceMode: atBegin !== false}); +} diff --git a/front/js/main.js b/front/js/main.js index 9df4b5d..9210a6b 100644 --- a/front/js/main.js +++ b/front/js/main.js @@ -4,6 +4,13 @@ import Account from "./svelte/Account.svelte"; import Channel from "./svelte/Channel.svelte"; import Mustache from "mustache"; import 'htmx.org'; +import {dropdown} from "./components/dropdown.js"; +import {colorPicker} from "./recordEditor/colorPicker.js"; + +addEventListener("load", (event) => { + dropdown() + colorPicker() +}); Mustache.escape = function (value) { return value; diff --git a/front/js/recordEditor/colorPicker.js b/front/js/recordEditor/colorPicker.js new file mode 100644 index 0000000..10bc6eb --- /dev/null +++ b/front/js/recordEditor/colorPicker.js @@ -0,0 +1,13 @@ +export function colorPicker() { + document.querySelectorAll(".color-picker").forEach(el => { + colorPickerInit(el); + }) +} + +function colorPickerInit(el){ + const colorInput = el.querySelector("[type=color]"); + const textInput = el.querySelector("[type=text]"); + + colorInput.addEventListener("change",(e) => textInput.value = colorInput.value); + textInput.addEventListener("change",(e) => colorInput.value = textInput.value); +} \ No newline at end of file diff --git a/front/sass/app.scss b/front/sass/app.scss index 48ce6f4..a1086c1 100644 --- a/front/sass/app.scss +++ b/front/sass/app.scss @@ -105,3 +105,7 @@ a { .lucent-component { position: relative; } + +[hidden] { + display: none; +} diff --git a/front/views/components/dropdown.blade.php b/front/views/components/dropdown.blade.php index dbed80f..2881228 100644 --- a/front/views/components/dropdown.blade.php +++ b/front/views/components/dropdown.blade.php @@ -6,7 +6,7 @@ > {{$slot}} -