Skip to content

Commit

Permalink
feat(editor): added searchable icon select input
Browse files Browse the repository at this point in the history
uses as standalone alpine component with events to propagate changes (built on select2)
  • Loading branch information
Jonnx committed Nov 16, 2023
1 parent 6a947d1 commit b26ea6e
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 47 deletions.
71 changes: 71 additions & 0 deletions app/View/Components/EditorIconSelect.php
@@ -0,0 +1,71 @@
<?php

namespace App\View\Components;

use Illuminate\Support\Str;
use Illuminate\View\Component;

class EditorIconSelect extends Component
{
public $changeEvent;

public $default;

public $icons;

/**
* Create a new component instance.
*
* @return void
*/
public function __construct(string $changeEvent, string $default = 'fa-solid fa-map-location')
{
// set default
$this->changeEvent = $changeEvent;
$this->default = $default;

// load available icons
$this->icons = collect();
$this->getIconsInDir('fa-solid fa-', base_path('resources/icons/font-awesome-6/solid'));
$this->getIconsInDir('fa-regular fa-', base_path('resources/icons/font-awesome-6/regular'));
$this->getIconsInDir('fa-brands fa-', base_path('resources/icons/font-awesome-6/brands'));
}

protected function getIconsInDir($prefix, $path)
{
$files = scandir($path);
foreach ($files as $file) {
// SKIP HIDDEN FILES OR PARENT PATHS
if (Str::startsWith($file, '.')) {
continue;
}

// DETERMINE FULL PATH
$itemPath = $path.'/'.$file;

// CHECK NESTED DIRECTORY
if (! is_dir($itemPath)) {
// ADD ICON
$iconName = data_get(explode('.', $file), 0);

if ($iconName) {
$iconValue = $prefix.$iconName;
$this->icons->push((object) [
'value' => $iconValue,
'label' => $iconValue,
]);
}
}
}
}

/**
* Get the view / contents that represent the component.
*
* @return \Illuminate\Contracts\View\View|\Closure|string
*/
public function render()
{
return view('components.editor-icon-select');
}
}
65 changes: 21 additions & 44 deletions public/css/app.css
Expand Up @@ -1221,6 +1221,9 @@ select {
.mb-8 {
margin-bottom: 2rem;
}
.mb-9 {
margin-bottom: 2.25rem;
}
.ml-2 {
margin-left: 0.5rem;
}
Expand All @@ -1239,9 +1242,6 @@ select {
.mt-9 {
margin-top: 2.25rem;
}
.mb-9 {
margin-bottom: 2.25rem;
}
.block {
display: block;
}
Expand Down Expand Up @@ -1371,10 +1371,6 @@ select {
border-right-width: calc(1px * var(--tw-divide-x-reverse));
border-left-width: calc(1px * calc(1 - var(--tw-divide-x-reverse)));
}
.divide-gray-800 > :not([hidden]) ~ :not([hidden]) {
--tw-divide-opacity: 1;
border-color: rgb(31 41 55 / var(--tw-divide-opacity));
}
.divide-gray-900 > :not([hidden]) ~ :not([hidden]) {
--tw-divide-opacity: 1;
border-color: rgb(17 24 39 / var(--tw-divide-opacity));
Expand Down Expand Up @@ -1408,32 +1404,24 @@ select {
.border-0 {
border-width: 0px;
}
.border-gray-300 {
.border-gray-900 {
--tw-border-opacity: 1;
border-color: rgb(209 213 219 / var(--tw-border-opacity));
border-color: rgb(17 24 39 / var(--tw-border-opacity));
}
.border-transparent {
border-color: transparent;
}
.border-indigo-400 {
--tw-border-opacity: 1;
border-color: rgb(129 140 248 / var(--tw-border-opacity));
}
.border-indigo-500 {
--tw-border-opacity: 1;
border-color: rgb(99 102 241 / var(--tw-border-opacity));
}
.border-gray-900 {
--tw-border-opacity: 1;
border-color: rgb(17 24 39 / var(--tw-border-opacity));
}
.bg-gray-200 {
--tw-bg-opacity: 1;
background-color: rgb(229 231 235 / var(--tw-bg-opacity));
}
.bg-gray-600 {
.bg-gray-700 {
--tw-bg-opacity: 1;
background-color: rgb(55 65 81 / var(--tw-bg-opacity));
}
.bg-gray-800 {
--tw-bg-opacity: 1;
background-color: rgb(75 85 99 / var(--tw-bg-opacity));
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
}
.bg-gray-900 {
--tw-bg-opacity: 1;
Expand All @@ -1458,10 +1446,6 @@ select {
.bg-transparent {
background-color: transparent;
}
.bg-white {
--tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.bg-yellow-600 {
--tw-bg-opacity: 1;
background-color: rgb(202 138 4 / var(--tw-bg-opacity));
Expand All @@ -1470,14 +1454,6 @@ select {
--tw-bg-opacity: 1;
background-color: rgb(24 24 27 / var(--tw-bg-opacity));
}
.bg-gray-700 {
--tw-bg-opacity: 1;
background-color: rgb(55 65 81 / var(--tw-bg-opacity));
}
.bg-gray-800 {
--tw-bg-opacity: 1;
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
}
.p-10 {
padding: 2.5rem;
}
Expand All @@ -1490,6 +1466,9 @@ select {
.p-6 {
padding: 1.5rem;
}
.p-4 {
padding: 1rem;
}
.px-2 {
padding-left: 0.5rem;
padding-right: 0.5rem;
Expand Down Expand Up @@ -1678,6 +1657,9 @@ select {
--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.\[x-bind\:data-icon\=\"iconName\"\] {
x-bind: data-icon="iconName";
}

[x-cloak] {
display: none !important;
Expand Down Expand Up @@ -1745,24 +1727,19 @@ select {
color: rgb(209 213 219 / var(--tw-text-opacity));
}

.hover\:bg-gray-50:hover {
--tw-bg-opacity: 1;
background-color: rgb(249 250 251 / var(--tw-bg-opacity));
}

.hover\:bg-gray-700:hover {
--tw-bg-opacity: 1;
background-color: rgb(55 65 81 / var(--tw-bg-opacity));
}

.hover\:bg-indigo-700:hover {
.hover\:bg-gray-800:hover {
--tw-bg-opacity: 1;
background-color: rgb(67 56 202 / var(--tw-bg-opacity));
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
}

.hover\:bg-gray-800:hover {
.hover\:bg-indigo-700:hover {
--tw-bg-opacity: 1;
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
background-color: rgb(67 56 202 / var(--tw-bg-opacity));
}

.hover\:text-gray-700:hover {
Expand Down
45 changes: 45 additions & 0 deletions resources/views/components/editor-icon-select.blade.php
@@ -0,0 +1,45 @@
<div
{{ $attributes->merge(['class' => 'mb-8']) }}
x-data="{
multiple: false,
value: '{{ $default }}',
options: {{ json_encode($icons) }},
init() {
let bootSelect2 = () => {
let selections = this.multiple ? this.value : [this.value]
$(this.$refs.select).select2({
multiple: this.multiple,
data: this.options.map(i => ({
id: i.value,
text: i.label,
selected: selections.map(i => String(i)).includes(String(i.value)),
})),
})
}
let refreshSelect2 = () => {
$(this.$refs.select).select2('destroy')
this.$refs.select.innerHTML = ''
bootSelect2()
}
bootSelect2()
$(this.$refs.select).on('change', () => {
let currentSelection = $(this.$refs.select).select2('data')
this.value = this.multiple
? currentSelection.map(i => i.id)
: currentSelection[0].id
$dispatch('{{ $changeEvent }}', this.value)
})
this.$watch('value', () => refreshSelect2())
this.$watch('options', () => refreshSelect2())
},
}"
class="w-full">
<select class="w-full" x-ref="select"></select>
</div>
15 changes: 12 additions & 3 deletions resources/views/components/editor.blade.php
@@ -1,6 +1,10 @@
<div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-12" x-data="{
experience: 'pin-with-text'
<div class="grid grid-cols-1 lg:grid-cols-3 gap-12"
id="editor"
@icon-changed.window="console.log($event.detail)"
x-data="{
iconName: undefined,
experience: 'pin-with-text',
}">

<div class="md:col-span-2 text-left p-10 rounded-lg" style="background: linear-gradient(145deg, #0f0f10, #171719, #171719, #171719);">
Expand Down Expand Up @@ -53,7 +57,12 @@
<div class="mb-9">
{{-- PIN WITH TEXT --}}
<div>
<h2 class="font-bold text-xl mb-4">Customize your marker:</h2>
<h2 class="font-bold text-xl mb-4" x-on:click="console.log($refs)">
Customize your marker:
</h2>

<div x-ref="test">lorem</div>
<x-editor-icon-select change-event="icon-changed" />
</div>

{{-- PIN WITH ICON --}}
Expand Down
14 changes: 14 additions & 0 deletions resources/views/layouts/app-nav.blade.php
Expand Up @@ -89,4 +89,18 @@ class="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-
@endsection

@section('content')
{{-- will be filled with page content --}}
@endsection

{{-- load select 2 scripts --}}
@section('scripts')
@parent
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
@endsection

{{-- load jquery for select2 --}}
@section('scripts')
@parent
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
@endsection
2 changes: 2 additions & 0 deletions resources/views/layouts/app.blade.php
Expand Up @@ -6,6 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>MapMarker</title>
<link href="{{ asset('css/app.css') }}" rel="stylesheet">

@section('scripts') @show
</head>

<body class="antialiased bg-zinc-900 p-2 md:p-10">
Expand Down

0 comments on commit b26ea6e

Please sign in to comment.