diff --git a/app/Blocks/Banner.php b/app/Blocks/Banner.php new file mode 100644 index 0000000..5d99ee4 --- /dev/null +++ b/app/Blocks/Banner.php @@ -0,0 +1,24 @@ + $block['attrs']['eyebrow'] ?? '', + 'heading' => $block['attrs']['heading'] ?? '', + 'text' => $block['attrs']['text'] ?? '', + 'showEyebrow' => $block['attrs']['showEyebrow'] ?? true, + 'showHeading' => $block['attrs']['showHeading'] ?? true, + 'showText' => $block['attrs']['showText'] ?? true, + 'id' => $block['attrs']['id'] ?? '', + 'alt' => $block['attrs']['alt'] ?? '', + 'buttonText' => $block['attrs']['buttonText'] ?? '', + 'buttonHref' => $block['attrs']['buttonHref'] ?? '', + ]); + } +} diff --git a/app/View/Components/Button.php b/app/View/Components/Button.php new file mode 100644 index 0000000..3a25227 --- /dev/null +++ b/app/View/Components/Button.php @@ -0,0 +1,39 @@ +href = $href; + $this->type = $type; + $this->text = $text; + } + + /** + * Get the view / contents that represent the component. + * + * @return \Illuminate\View\View|string + */ + public function render() + { + return $this->view('components.button'); + } +} diff --git a/app/View/Components/Image.php b/app/View/Components/Image.php new file mode 100644 index 0000000..83c75ad --- /dev/null +++ b/app/View/Components/Image.php @@ -0,0 +1,124 @@ +attr = []; + + if ($class) { + $this->attr['class'] = $class; + } + + if ($alt) { + $this->attr['alt'] = $alt; + } + + $this->attr['loading'] = $lazy ? 'lazy' : false; + + $this->container = $container; + + $this->image = $this->display_image($image, $size, $this->attr); + } + + /** + * Display Images + * + * @param [type] $image + * @return void + */ + public function display_image($image, $image_size, $attr = '', $inline_svg = false) + { + $default_attr = [ + 'class' => 'img-fluid', + ]; + + // Get alt param + if (is_numeric($image) && wp_attachment_is_image($image)) { + $default_attr['alt'] = trim(strip_tags(get_post_meta($image, '_wp_attachment_image_alt', true))); + } + + // New Attributes (Merge) + $attr = wp_parse_args($attr, $default_attr); + $attr = array_map('esc_attr', $attr); + + // parsed attrs for html + $img_html_tags = ''; + foreach ($attr as $name => $value) { + $img_html_tags .= " $name=" . '"' . $value . '"'; + } + + // If it's an ID act like WP normally does + if (is_numeric($image) && wp_attachment_is_image($image)) { + return wp_get_attachment_image($image, $image_size, 0, $attr); + } + + // If it's an String + if (!is_array($image) && !is_object($image) && is_string($image)) { + // Pending Question: can we try and use wp_get_attachment_image via reverse lookup of the url?? + $image_string = ''; + return $image_string; + } + + // If it's an array (from ACF Image field) + if (is_array($image)) { + // If it's an svg + if ($image['mime_type'] === 'image/svg+xml') { + if ($inline_svg == true) { + $file_name = get_attached_file($image['ID']); + if (file_exists($file_name)) { + return file_get_contents($file_name); + } + } else { + return wp_get_attachment_image($image['ID'], $image_size, 0, $attr); + } + } else { + return wp_get_attachment_image($image['ID'], $image_size, 0, $attr); + } + } + + // If it's an Object (rare) + if (is_object($image)) { + return wp_get_attachment_image($image->ID, $image_size, 0, $attr); + } + + // If Image is empty + if ($image == null && $this->placeholder) { + return ''; + } + + // Else + return false; + } + + /** + * Get the view / contents that represent the component. + * + * @return \Illuminate\Contracts\View\View|\Closure|string + */ + public function render() + { + return view('components.image'); + } +} diff --git a/app/View/Components/SectionHeader.php b/app/View/Components/SectionHeader.php new file mode 100644 index 0000000..6580aa4 --- /dev/null +++ b/app/View/Components/SectionHeader.php @@ -0,0 +1,60 @@ +showEyebrow = $showEyebrow; + $this->showHeading = $showHeading; + $this->showText = $showText; + + $this->eyebrow = $eyebrow; + $this->heading = $heading; + $this->text = $text; + $this->containerClasses = $containerClasses; + $this->eyebrowClasses = $eyebrowClasses; + $this->headingClasses = $headingClasses; + $this->textClasses = $textClasses; + } + + /** + * Get the view / contents that represent the component. + * + * @return \Illuminate\View\View|string + */ + public function render() + { + return $this->view('components.section-header'); + } +} diff --git a/app/View/Composers/App.php b/app/View/Composers/App.php index a8aabff..66371da 100644 --- a/app/View/Composers/App.php +++ b/app/View/Composers/App.php @@ -24,7 +24,7 @@ public function with() { return [ 'containerClasses' => 'max-w-5xl mx-auto', - 'containerInnerClasses' => 'px-6', + 'containerInnerClasses' => '', 'siteName' => $this->siteName(), ]; } diff --git a/public/content/themes/radicle/theme.json b/public/content/themes/radicle/theme.json index 42e5e29..71e9076 100644 --- a/public/content/themes/radicle/theme.json +++ b/public/content/themes/radicle/theme.json @@ -146,6 +146,26 @@ "color": "#1e1b4b", "name": "Indigo 950", "slug": "indigo-950" + }, + { + "color": "#45c4af", + "name": "Primary", + "slug": "primary" + }, + { + "color": "#dafdb9", + "name": "Auxiliar", + "slug": "auxiliar" + }, + { + "color": "#13678b", + "name": "Primary-dark", + "slug": "primary-dark" + }, + { + "color": "#f1ffee", + "name": "Back-light", + "slug": "back-light" } ] }, diff --git a/resources/scripts/editor/blocks/banner/banner.block.tsx b/resources/scripts/editor/blocks/banner/banner.block.tsx new file mode 100644 index 0000000..3ab9ccf --- /dev/null +++ b/resources/scripts/editor/blocks/banner/banner.block.tsx @@ -0,0 +1,89 @@ +import { InspectorControls, useBlockProps, RichText} from "@wordpress/block-editor"; +import { PanelBody, ToggleControl } from "@wordpress/components"; +import { __ } from "@wordpress/i18n"; +import { + attributes as imageAttributes, + Edit as ImageEdit, + Sidebar as ImageSidebar, +} from "scripts/editor/components/image/image"; +import { + attributes as buttonAttributes, + Edit as ButtonEdit, + Sidebar as ButtonSidebar, +} from "scripts/editor/components/button/button"; +import { + Edit as SectionHeaderEdit, + Sidebar as SectionHeaderSidebar, + attributes as sectionHeaderAttributes, +} from "scripts/editor/components/section-header/section-header"; +import { + GetBlockAttributeValues, + GetSetAttributesFunction, +} from "scripts/editor/utils/type-mapping"; + +/* Block name */ +export const name = "by40q/banner"; + +/* Block title */ +export const title = __("Banner", "40q"); + +/* Block icon */ +export const icon = "format-image"; + +/* Block category */ +export const category = "40q"; + +/* Block attributes */ +export const attributes = { + ...sectionHeaderAttributes, + ...buttonAttributes, + ...imageAttributes, +} as const; + +/* Block types */ +type BlockAttributeValues = GetBlockAttributeValues; +type SetAttributesFunction = GetSetAttributesFunction; + +/* Block edit */ +export const edit = ({ + attributes, + setAttributes, +}: { + attributes: BlockAttributeValues; + setAttributes: SetAttributesFunction; +}) => { + const blockProps = useBlockProps({ + className: "relative py-12 px-16", + }); + + return ( + <> + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+ + ); +}; + +/* Block save */ +export const save = () => <>; + +/* Block styles */ +export const styles = []; diff --git a/resources/scripts/editor/components/button/button.tsx b/resources/scripts/editor/components/button/button.tsx new file mode 100644 index 0000000..3afe7a4 --- /dev/null +++ b/resources/scripts/editor/components/button/button.tsx @@ -0,0 +1,84 @@ +import { + RichText, + URLInputButton, + useBlockProps, +} from "@wordpress/block-editor"; +import { PanelBody, SelectControl } from "@wordpress/components"; +import { __ } from "@wordpress/i18n"; +import { + GetBlockAttributeValues, + GetSetAttributesFunction, +} from "scripts/editor/utils/type-mapping"; + +/* Component attributes */ +export const attributes = { + buttonText: { + type: "string", + default: "", + }, + buttonHref: { + type: "string", + default: "", + }, + buttonType: { + type: "string", + default: "primary", + }, +} as const; + +/* Component types */ +type BlockAttributeValues = GetBlockAttributeValues; +type SetAttributesFunction = GetSetAttributesFunction; + +/* Component edit */ +export const Edit = ({ + attributes, + setAttributes, +}: { + attributes: BlockAttributeValues; + setAttributes: SetAttributesFunction; +}) => { + const { buttonText, buttonHref, buttonType } = attributes; + const blockProps = useBlockProps(); + return ( + <> + + setAttributes({ buttonHref })} + /> + setAttributes({ buttonText })} + /> + + + ); +}; + +/* Component sidebar */ +export const Sidebar = ({ + attributes, + setAttributes, +}: { + attributes: BlockAttributeValues; + setAttributes: SetAttributesFunction; +}) => { + const { buttonType } = attributes; + return ( + + setAttributes({ buttonType: value })} + /> + + ); +}; diff --git a/resources/scripts/editor/components/image/image.tsx b/resources/scripts/editor/components/image/image.tsx new file mode 100644 index 0000000..839d39f --- /dev/null +++ b/resources/scripts/editor/components/image/image.tsx @@ -0,0 +1,88 @@ +import { MediaUpload, MediaUploadCheck } from "@wordpress/block-editor"; +import { Button } from "@wordpress/components"; +import { __ } from "@wordpress/i18n"; +import { + GetBlockAttributeValues, + GetSetAttributesFunction, +} from "scripts/editor/utils/type-mapping"; + +/* Component attributes */ +export const attributes = { + url: { + type: "string", + default: "", + }, + id: { + type: "string", + default: "", + }, + alt: { + type: "string", + default: "", + }, +} as const; + +/* Component types */ +type BlockAttributeValues = GetBlockAttributeValues; +type SetAttributesFunction = GetSetAttributesFunction; + +/* Component edit */ +export const Edit = ({ attributes }: { attributes: BlockAttributeValues }) => { + const { url, alt } = attributes; + return ( +
+ {url ? ( + {alt} + ) : ( +
+

Select an image using the button in the sidebar

+
+ )} +
+ ); +}; + +/* Component sidebar */ +export const Sidebar = ({ + attributes, + setAttributes, +}: { + attributes: BlockAttributeValues; + setAttributes: SetAttributesFunction; +}) => { + const { url } = attributes; + return ( + <> + + + setAttributes({ + url: image.url, + alt: image.alt, + id: String(image.id), + }) + } + render={({ open }) => ( + + )} + /> + + {url && ( + + )} + + ); +}; diff --git a/resources/scripts/editor/components/section-header/section-header.tsx b/resources/scripts/editor/components/section-header/section-header.tsx new file mode 100644 index 0000000..a7efca6 --- /dev/null +++ b/resources/scripts/editor/components/section-header/section-header.tsx @@ -0,0 +1,135 @@ +import { RichText, useBlockProps } from "@wordpress/block-editor"; +import { PanelBody, ToggleControl } from "@wordpress/components"; +import { __ } from "@wordpress/i18n"; +import { + GetBlockAttributeValues, + GetSetAttributesFunction, +} from "scripts/editor/utils/type-mapping"; + +/* Component attributes */ +export const attributes = { + showEyebrow: { + type: "boolean", + default: true, + }, + eyebrow: { + type: "string", + default: "", + }, + showHeading: { + type: "boolean", + default: true, + }, + heading: { + type: "string", + default: "", + }, + showText: { + type: "boolean", + default: true, + }, + text: { + type: "string", + default: "", + }, + containerClasses: { + type: "string", + default: "", + }, + eyebrowClasses: { + type: "string", + default: "", + }, + headingClasses: { + type: "string", + default: "", + }, + textClasses: { + type: "string", + default: "", + }, +} as const; + +/* Component types */ +type BlockAttributeValues = GetBlockAttributeValues; +type SetAttributesFunction = GetSetAttributesFunction; + +/* Component edit */ +export const Edit = ({ + attributes, + setAttributes, +}: { + attributes: BlockAttributeValues; + setAttributes: SetAttributesFunction; +}) => { + const { showEyebrow, eyebrow, showHeading, heading, showText, text, containerClasses, eyebrowClasses, headingClasses, textClasses } = + attributes; + + const blockProps = useBlockProps({ + className: `${containerClasses}`, + }); + + return ( + <> +
+ {!!showEyebrow && ( + setAttributes({ eyebrow })} + /> + )} + {!!showHeading && ( + setAttributes({ heading })} + /> + )} + {!!showText && ( + setAttributes({ text })} + /> + )} +
+ + ); +}; + +/* Component sidebar */ +export const Sidebar = ({ + attributes, + setAttributes, +}: { + attributes: BlockAttributeValues; + setAttributes: SetAttributesFunction; +}) => { + const { showEyebrow, showHeading, showText } = attributes; + return ( + + setAttributes({ showEyebrow })} + /> + setAttributes({ showHeading })} + /> + setAttributes({ showText })} + /> + + ); +}; diff --git a/resources/styles/app.css b/resources/styles/app.css index a31e444..8e6277f 100644 --- a/resources/styles/app.css +++ b/resources/styles/app.css @@ -1,3 +1,8 @@ @import 'tailwindcss/base'; @import 'tailwindcss/components'; @import 'tailwindcss/utilities'; + + +body { + padding: 0; +} \ No newline at end of file diff --git a/resources/views/blocks/banner.blade.php b/resources/views/blocks/banner.blade.php new file mode 100644 index 0000000..7816cf7 --- /dev/null +++ b/resources/views/blocks/banner.blade.php @@ -0,0 +1,15 @@ +
+
+
+ + @if ($buttonText) + + @endif +
+ @if ($id) + +
+ @endif +
+
\ No newline at end of file diff --git a/resources/views/components/button.blade.php b/resources/views/components/button.blade.php index dd34ca5..fa5f0c5 100644 --- a/resources/views/components/button.blade.php +++ b/resources/views/components/button.blade.php @@ -1,30 +1,7 @@ -@php -$element = $attributes->get('element', 'a'); -if ($element === 'a' && !$attributes->has('href')) { - $element = 'button'; -} + + {{ $text }} -$defaultClasses = 'inline-flex border border-black active:bg-black active:text-white '; - -$types = [ - 'primary' => 'text-white bg-black hover:bg-white hover:text-black', - 'outline' => 'text-black bg-transparent hover:bg-black hover:text-white', -]; - -$sizes = [ - 'xs' => 'px-4 py-2 text-xs', - 'sm' => 'px-4 py-2 text-sm', - 'base' => 'px-6 py-3 text-base', - 'lg' => 'px-8 py-4 text-lg', -]; -@endphp - -<{{ $element }} - class="{{ $defaultClasses }} {{ $types[$attributes->get('type', 'primary')] }} {{ $sizes[$attributes->get('size', 'base')] }} {{ $attributes->get('class') }}" - - @foreach ($attributes->except(['class', 'type', 'size', 'element']) as $key => $value) - {{ $key }}="{{ $value }}" - @endforeach -> - {{ $slot }} - +
+ @include('partials.svg.arrow') +
+
\ No newline at end of file diff --git a/resources/views/components/image.blade.php b/resources/views/components/image.blade.php new file mode 100644 index 0000000..1c4e62f --- /dev/null +++ b/resources/views/components/image.blade.php @@ -0,0 +1,10 @@ +@if ($container) + +@endif diff --git a/resources/views/components/section-header.blade.php b/resources/views/components/section-header.blade.php new file mode 100644 index 0000000..71c819a --- /dev/null +++ b/resources/views/components/section-header.blade.php @@ -0,0 +1,13 @@ +
+ @if ($showEyebrow && !empty($eyebrow)) +

{{ $eyebrow }}

+ @endif + + @if ($showHeading && !empty($heading)) +

{{ $heading }}

+ @endif + + @if ($showText && !empty($text)) +
{{ $text }}
+ @endif +
diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index b37b4ab..44d0479 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -18,7 +18,7 @@ @include('sections.header') -
+
@yield('content')
diff --git a/resources/views/partials/svg/arrow.blade.php b/resources/views/partials/svg/arrow.blade.php new file mode 100644 index 0000000..e4d54cf --- /dev/null +++ b/resources/views/partials/svg/arrow.blade.php @@ -0,0 +1,3 @@ + + + diff --git a/tailwind.config.ts b/tailwind.config.ts index e1dea1e..71944ef 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -42,7 +42,21 @@ export default { 900: '#312e81', 950: '#1e1b4b', }, + 'primary': '#45C4AF', + 'auxiliar': '#DAFDB9', + 'primary-dark': '#13678B', + 'back-light': '#F1FFEE', }, + extend: { + spacing: { + '17': '4.25rem', + }, + lineHeight: { + '7.5': '1.875rem', + '10.5': '2.625rem', + '14': '3.5rem', + } + } }, plugins: [ forms,