Ich habe gestern ein Feature für mein Blog programmiert und würde diesen gerne auch euch zur Verfügung stellen. Ich schreibe Blogbeiträge mit sehr viel Text und vielen Zwischenüberschriften. Damit das nicht langweilig wird, habe ich mir überlegt diese Funktion zu programmieren. Ich finde auch dass das eine schöne Unterteilung der Abschnitte darstellt. So sieht es aus:
Der Code
Auf der Code Seite habe ich nicht wirklich viel gemacht. Ich habe zur Verwirklichung eher auf meine css Skills gesetzt. Die Codes sehen wie folgt aus:
php
<?php
defined( 'ABSPATH' ) || exit;
wp_enqueue_style(
basename(__DIR__).'-style',
get_template_directory_uri().'/blocks/'.basename(__DIR__).'/'.basename(__DIR__).'.css'
);
function register_full_image_title() {
if ( ! function_exists( 'register_block_type' ) ) {
// Gutenberg is not active.
return;
}
wp_enqueue_script(
basename(__DIR__),
get_template_directory_uri().'/blocks/'.basename(__DIR__).'/block.js',
array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor' )
);
register_block_type( 'konzeptcode/'.basename(__DIR__), array(
'editor_script' => basename(__DIR__),
'style' => basename(__DIR__).'-style',
'editor_style' => basename(__DIR__).'-style'
) );
}
add_action( 'enqueue_block_editor_assets', 'register_full_image_title' );
add_action( 'enqueue_block_assets', 'register_full_image_title' );
js (Backend)
const { registerBlockType } = wp.blocks;
const { PanelBody, ToggleControl, TextControl, Button } = wp.components;
const { Fragment } = wp.element;
const { InspectorControls, MediaUpload } = wp.editor;
let { withState } = wp.compose;
registerBlockType( 'konzeptcode/full-image-title', {
title: 'Vollbild mit Titel',
icon: 'align-center',
category: 'layout',
keywords: ['fazit', 'headline', 'full'],
attributes: {
text: {
type: 'string',
default: '',
},
imageData: {
type: 'object',
default: {}
},
},
edit: ( props ) => {
const {
attributes: {
text,
imageData
},
setAttributes,
className
} = props;
return <Fragment>
<div
class="full-image-title-preview"
style={{ backgroundImage : (imageData.hasOwnProperty('fhd-url'))? "url("+imageData['fhd-url']+")" : "url("+imageData['full-url']+")" }}
>
<TextControl
label="Headline"
class="full-image-title-text"
value={text}
onChange={ ( text ) => setAttributes( { text } ) }
/>
<MediaUpload
onSelect={ function(media){
var image = {};
['uhd','wqhd','fhd'].forEach(function (size){
if (media.sizes.hasOwnProperty(size)) {
image[size+'-url'] = media.sizes[size].url;
image[size+'-width'] = media.sizes[size].width;
image[size+'-height'] = media.sizes[size].height;
}
});
if(media.sizes.full.width == 1920){
image['fhd-url'] = media.sizes.full.url;
image['fhd-width'] = media.sizes.full.width;
image['fhd-height'] = media.sizes.full.height;
}
if(Object.keys(image).length === 0){
image['full-url'] = media.sizes.full.url;
image['full-width'] = media.sizes.full.width;
image['full-height'] = media.sizes.full.height;
}
image['thumb-id'] = media.id;
if(Object.keys(image).length >= 4){
setAttributes( {
imageData: image
} );
}
} }
value={ (imageData.hasOwnProperty('thumb-id')? imageData.id : 0 ) }
render={ ( { open } ) => (
<Button isDefault onClick={ open } >
Bild setzen
</Button>
) }
/>
</div>
</Fragment>;
},
save: ( props ) => {
const {
attributes: {
text,
imageData
},
setAttributes,
className
} = props;
return <Fragment>
<div class="full-image-title-image-wrapper" {...imageData}>
<img class="full-image-title-image" src={imageData['thumbnail-url']} />
</div>{ (text)? <h2 class="full-image-title-title">{text}</h2> : ''}
</Fragment>;
},
} );
js (Frontend)
if($('.full-image-title-outer-wrapper').length){
var w = window.innerWidth;
var h = window.innerHeight;
loadTitleImage();
$( window ).resize(function() { loadTitleImage(); });
$(window).scroll(function(){
$('.full-image-title-image-wrapper').each(function(index, el) {
if(el.getBoundingClientRect().y <= 0){
$(el).addClass('rollout')
}else {
$(el).removeClass('rollout')
}
});
});
}
function loadTitleImage(){
console.log('loadTitleImage');
$('.full-image-title-image-wrapper').each(function(index, el) {
let url = false;
$(['fhd','wqhd','uhd']).each(function(index, size) {
if($(el)[0].hasAttribute(size+'-url')) url = $(el).attr(size+'-url');
if(
$(el)[0].hasAttribute(size+'-url') &&
parseInt($(el).attr(size+'-width')) > w &&
parseInt($(el).attr(size+'-height')) > h
){
url = $(el).attr(size+'-url');
return false;
}
});
if(!url) url = $(el).attr('full-url');
$(el).find('.full-image-title-image').attr('src', url );
});
}
css
@import "../scss/vars.scss";
#wrapper{
.full-image-title-inner-wrapper,
.full-image-title-outer-wrapper{
display: block;
height: 150vh;
}
.full-image-title-outer-wrapper,
.full-image-title-inner-wrapper,
.full-image-title-image-wrapper{
position: relative;
display: block;
width: 100%;
padding: 0;
}
.full-image-title-outer-wrapper{
.full-image-title-inner-wrapper{
max-width: none;
.full-image-title-image-wrapper{
position: sticky;
top: 0;
overflow: hidden;
width: 100%;
max-height: 100vh;
z-index: -1;
.full-image-title-image{
position: relative;
display: block;
width: auto;
height: auto;
min-width: 100vw;
min-height: 100vh;
max-width: none;
max-height: none;
top: 50vh;
left: 50vw;
transform: translate(-50%, -50%);
}
&:after{
content: ' ';
background-color: $white;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
transition: all .3s ease-in-out;
}
&.rollout{
&:after{
opacity: .8;
}
& + .full-image-title-title{
transform: translateY(-50%);
}
}
}
.full-image-title-title{
transform: translateY(0);
z-index: 10;
font-size: 8vw;
font-weight: 700;
text-align: center;
width: 100%;
max-width: 75vw;
margin: 0 auto;
transition: all .3s ease-in-out;
}
}
}
}
.full-image-title-preview{
width: 100%;
height: 320px;
background-position: center;
background-size: cover;
}