• Время чтения ~8 мин
  • 05.07.2023

В этом сообщении блога мы создадим пять повторно используемых компонентов, используя Laravel Blade Components, Alpine.js и TailwindCSS. Мы построим следующие компоненты:

  • Копировать в буфер
  • Глобальный индикатор выполнения
  • Образ
  • Код QrCode
  • Аватар

Я предполагаю, что вы уже использовали AlpineJS, Laravel Blade Components и TailwindCSS. Если вы еще не пробовали AlpineJS и TailwindCSS, вам стоит это сделать. Они фантастические.

Давайте начнем!!

Копировать в буфер

обмена Этот компонент копирования в буфер обмена очень вдохновлен этим обсуждением переполнения стека https://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript.

Как использовать в наших представлениях

<x-copytoclipboard 
  content="Laravel Blade Component is Awesome" 
/>

колонок Ниже приведен пример с HTML-содержимым

<x-copytoclipboard 
  content='<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path d="M12 14l9-5-9-5-9 5 9 5z" /><path d="M12 14l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14z" /><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 14l9-5-9-5-9 5 9 5zm0 0l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14zm-4 6v-7.5l4-2.222" /></svg>' 
/>

Полный компонент Глобальный индикатор выполнения Этот компонент

// views/components/copytoclipboard.blade.php
@props(['content' => 'Content' ])
<a 
	{{
		$attributes->merge([
			"class" => "no-underline border border-gray-200 px-1 rounded text-xs uppercase tracking-wide font-semibold text-gray-500"
		])
	}}
	href="#"
	x-data="{
		isCopied: false,
		copyToClipBoard() {
			if (! navigator.clipboard) {
				textArea = document.createElement('textarea');
				textArea.value = this.$refs.content.innerHTML;
				textArea.style.top = '0';
				textArea.style.left = '0';
				textArea.style.position = 'fixed';
				document.body.appendChild(textArea);
				textArea.focus();
				textArea.select();
				try {
					if (document.execCommand('copy')) {
						this.isCopied = true;
						setTimeout(() => {
							this.isCopied = false;
						}, 2500);
					}
				} catch (err) {
					console.error('Fallback: Oops, unable to copy', err);
				}
				document.body.removeChild(textArea);
				return;
			} else {
				navigator.clipboard.writeText(this.$refs.content.innerHTML)
					.then(() => {
						this.isCopied = true;
						setTimeout(() => {
							this.isCopied = false;
						}, 2500);
					});
			}
		}  
	}"
	x-on:click.prevent="copyToClipBoard()"
	x-cloak
>
<span class="hidden" x-ref="content">{!! $content !!}</span>
<span x-text="isCopied ? 'Copied' : 'Copy'"></span></a>

показывает индикатор

выполнения в верхней части страницы при переходе с одной страницы на другую. Этот компонент использует библиотеку Pace.js.

Pace.js является прекрасным индикатором прогресса для загрузки вашей страницы и навигации ajax - как определено на их официальном веб-сайте

Как использовать в наших представлениях

<x-global-progress color="coral" />

колонок Поместите приведенный выше код в раздел head вашего мастер-макета, например. app.blade.php

Полный компонент Глобальный индикатор выполнения Этот компонент

// views/components/global-progress.blade.php

@props([
	'color' => '#d72630'
])

<script src="https://cdn.jsdelivr.net/npm/[email protected]/pace.min.js" defer></script>

@once
  @push('styles')
  <style>
    /*!
      * pace.js v1.2.4 | Default theme
      * https://github.com/CodeByZach/pace/
      * Licensed MIT © HubSpot, Inc.
      */
    .pace {
      -webkit-pointer-events: none;
      pointer-events: none;
      -webkit-user-select: none;
      -moz-user-select: none;
      user-select: none
    }

    .pace-inactive {
      display: none
    }

    .pace .pace-progress {
      background: {{ $color }};
      position: fixed;
      z-index: 2000;
      top: 0;
      right: 100%;
      width: 100%;
      height: 3px
    }
  </style>
  @endpush
@endonce

с полным компонентом

Простой компонент изображения, поддерживающий пропорции.

Как использовать в наших представлениях

{{-- Give a width to adjust the height of image --}}
<div class="w-96">
  <x-image 
    image="https://pixabay.com/get/g3b015eccf776a5dbd497250775cdfaeb9846ad5b6f2828a69ae591385ad13fa5344f02279549c74909e2d1429158af0f3565a3384da23ed1ff7fcd9f5b8a26d132cdc60aad5e4795970a71d990e82d6b_640.jpg" 
    image-aspect-ratio="16:9" // Aspect Ratio 1:1, 4:3, 2:1
  />
</div>

Полный компонент Глобальный индикатор выполнения Этот компонент

// views/components/image.blade.php
@props([
	'image' => null,
	'imageAspectRatio' => '16:9',
	'rounded' => true,
	'srcsets' => null,
	'alt' => '',
	'sizes' => "(min-width: 768px) 40vw, 90vw"
])
{{-- 
	The sizes attribute describes the width that the image will display within the layout of your specific site
--}}
@php
	$roundedClass = $rounded ? 'rounded-md' : '';
	$aspectRatio = [
		'16:9' => 'padding-bottom: 56.25%',
		'4:3' => 'padding-bottom: 75%',
		'2:1' => 'padding-bottom: 50%',
		'1:1' => 'padding-bottom: 100%',
		'custom' => ''
	][$imageAspectRatio];
	$defaultImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAeAAAAHgCAIAAADytinCAAAACXBIWXMAAC4jAAAuIwF4pT92AAARrklEQVR42u3dW2wU5f/AYbBIKYdSPCEazocoAhorkpggF8IfNGI4iQh4BIKpigoiGiUaLyTxcIFRsFEEMUFCiIcLY6IRkVBEQVCRABcoCBQCpbY/aWkB5f+GN25qi7WyW7orz3PRbLfT2emEfPplOjPb7CQAaamZXQAg0AAINIBAAyDQAAINgEADINAAAg2AQAMINAACDYBAAwg0AAININAACDSAQAMg0AAINIBAAyDQAAINgEADINAAAg2AQAMINAACDSDQAAg0AAININAACDSAQAMg0AAINIBAAyDQAAINgEADCDQAAg2AQAMINAACDSDQAAg0AAININAACDSAQAMg0AAINIBAAyDQAAINgEADCDQAAg2AQAMINAACDSDQAAg0AAININAACDSAQAMg0AACDYBAAyDQAAINgEADCDQAAg2AQAMINAACDSDQAAg0gEADINAACDSAQAMg0AACDYBAAyDQAAINgEADCDQAAg2AQAMINAACDSDQAAg0gEADINAACDSAQAMg0AACDYBAAyDQAAINgEADCDQAAg0g0AAINAACDSDQAAg0gEADINAACDSAQAMg0AACDYBAAwg0AAINgEADCDQAAg0g0AAINAACDSDQAAg0gEADINAACDSAQAMg0AACDYBAAwg0AAINgEADCDQAAg0g0AAINAACDSDQAAg0gEADINAAAg2AQAMg0AACDYBAAwg0AAINgEADCDQAAg0g0AAINIBAAyDQAAg0gEADINAAAg2AQAMg0AACDYBAAwg0AAINgEADCDQAAg0g0AAINIBAAyDQAAg0gEADINAAAg2AQAMg0AACDYBAAwg055I//vjj+PHjJ0ipsEv900KgSbbOgf3QSPvWTkCgSaogJSUlTz755LBhw/6PFBkxYsT8+fOrq6tlGoEmKTfddFOzZs0uvPDCjh07XkLSwm7My8sLu7SgoCDs3t9//92/MQSafyeGY+vWrSEljzzyiJSk9v8lQ4cOzcnJ+e233wzRCDT/2okTJ8LHDRs2hEAvWbIkPPZ3rZSIu/GBBx4IO7a0tFSgEWiSCvSiRYvC42PHjv1B0sJuDDtz+vTpYcf++uuvAo1Ak1Sg3377bRN0Y0zQAo1AI9AC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';
@endphp
<div
	@if($aspectRatio)
		style="{{ $aspectRatio }}" 
	@endif
	
	{{
		$attributes->merge([
			'class' => 'relative border border-gray-100 overflow-hidden '. $roundedClass
		])
	}}
>
	@if ($image)
		<img 
			class="absolute object-cover h-full w-full"
			src="{{ $defaultImage }}"
			alt="{{ $alt ?? $image }}"
			loading="lazy"
			data-src="{{ $image }}" 
			onload="if(this.src !== this.getAttribute('data-src')) this.src=this.getAttribute('data-src');"
			
			@if (! is_null($srcsets))
				sizes="{{ $sizes }}"
				srcset="{{ $srcsets }}"
			@endif
		/>
	@else
		<img 
			class="absolute object-cover h-full w-full"
			src="{{ $defaultImage }}"
			alt="Placehoder-image"
			loading="lazy"
		/>
	@endif
</div>
 

QrCode на основе библиотеки https://github.com/milon/barcode

Simple QrCode на основе библиотеки https://github.com/milon/barcode based on the library https://github.com/milon/barcode

laravel Как использовать в наших представлениях

composer require milon/barcode

Как использовать в наших представлениях

<x-qrcode data="Laravel is awesome" />

Полный компонент Глобальный индикатор выполнения Этот компонент

// views/components/qrcode.blade.php
@props([
	'size' => 6,
	'data' => 'Hello QR Code',
	'type' => 'QRCODE',
	'dimension' => 2
])
<img 
	@if ($dimension === 2)
		src="data:image/png;base64,{{ DNS2D::getBarcodePNG($data, $type, $size, $size) }}"
	@else
		src="data:image/png;base64,{{ DNS1D::getBarcodePNG($data, $type) }}"
	@endif
	alt="qrcode"   
/>

Компонент

аватара, основанный на удивительном API, предоставляемом https://avatars.dicebear.com/ и https://boringavatars.com/.

Как использовать в наших представлениях

<x-avatar name="Loki" size="128" />
<x-avatar name="Loki" size="128" source="boringAvatars" />

Полный компонент Глобальный индикатор выполнения Этот компонент

// views/components/avatar.blade.php
@props([
	'shape' => 'circle', // circle or square
	'size' => 40,
  
  // works only with source type boringAvatars
	'variant' => 'beam', // marble, beam, pixel, sunset, bauhaus, ring
  'colors' => ['5e9fa3', 'dcd1b4', 'fab87f', 'f87e7b', 'b05574'],
	
  'name' => 'Tony Stark',
	
	'source' => "dicebearAvatars" // boringAvatars or dicebearAvatars
])
@php
	$avatarShapeClass = [
		'rounded' => 'rounded-lg',
		'square' => 'rounded-lg',
		'circle' => 'rounded-full',
	][$shape];
@endphp
<div class="inline-flex flex-shrink-0 overflow-hidden bg-gray-100 {{ $avatarShapeClass }}" style="width: {{ $size }}px; height: {{ $size }}px;">
	@if ($source === 'dicebearAvatars')
		<img 
	    src="https://avatars.dicebear.com/api/initials/{{ urlencode($name) }}.svg?&width={{ $size }}&height={{ $size }}" 
	    alt="{{ $name }}" 
			title="{{ $name }}" 
	    class="object-fit" 
			loading="lazy"
	  />
	@else
		<img 
			src="https://source.boringavatars.com/{{ $variant }}/{{ $size }}/{{ urlencode($name) }}?colors={{ implode(',', $colors) }}&{{ $shape }}" 
			alt="{{ $name }}" 
			title="{{ $name }}" 
			class="object-fit" 
			loading="lazy"
		/>
	@endif
</div>

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

Про мене

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

Об авторе CrazyBoy49z
WORK EXPERIENCE
Контакты
Ukraine, Lutsk
+380979856297