With GitHub Pages markdown you can do that using the > notation:
> **Fact:** There are no bad students or a bad audience --
only bad workshops and talks. Your mood, dedication and
enthusiasm do become those of the audience --
if you are not happy, they won\'t be happy.
> **Fact:** There are no bad students or a bad audience --
only bad workshops and talks. Your mood, dedication and
enthusiasm do become those of the audience --
if you are not happy, they won\'t be happy.
The problem was that I couldn’t add CSS classes to the blockquote elements so I can show them in different styles. I wanted four of them: example, fact, warning and tip.
The good news is that even without any styling using the strong name should make it obvious. But as there is no text “contains” selector in CSS I couldn’t rely on that to change the blockquote element.
First solution: JavaScript
The first thing I thought was to use JavaScript to apply the classes, which is pretty straight forward:
let bqs = document.querySelectorAll('blockquote');
bqs.forEach(b =>{
b.className= b.
querySelector('strong').
innerText.
toLowerCase().
replace(':','');});
let bqs = document.querySelectorAll('blockquote');
bqs.forEach(b => {
b.className = b.
querySelector('strong').
innerText.
toLowerCase().
replace(':','');
});
This, however, felt dirty and I wanted to use the system itself to do that task.
Moving to liquid
So I wrote a liquid include to convert the HTML before rendering. In my layout template, this works by replacing the {{ content }} with {% include blockquotes.html html=content %}.
In the blockquotes.html, I thought it’d be easy to do a search and replace. Alas, there is the issue that liquid only does string replacement and doesn’t know any regular expressions.
The HTML generated from the markdown has a line-break in it:
<blockquote><p><strong>Fact:</strong> There are no bad students β¦ </p></blockquote>
<blockquote>
<p><strong>Fact:</strong> There are no bad students β¦ </p>
</blockquote>
This is where it didn’t get fun. The replace filter doesn’t allow you to concatenate strings and doesn’t know the concept of n. So, I tried to use the newline_to_br together with strip_newlines filters and then replace the br but it was messy.
Turns out, the main trick was to capture a newline in liquid and assemble the string to replace using that one.
This works fine. Seems superfluous, but it is a way. It might be that there is a much simpler way as I am new to this world, having used PHP before the build the old version of the book. Got a better option? Tell me :)
Posted in General | Comments Off on Quick Tip: How to capture and replace newlines in liquid for Jekyll/GitHub Pages
Eleven years ago I wrote the Developer Evangelism Handbook .Last month I was approached by a publisher who is interested to print it in another language. Whilst flattered, I also couldn’t let that happen as there are parts of the book that are quaintly outdated now. Some of the products I promote aren’t available any longer and there are big differences in the way we use social media and the web now compared to 2009.
So I spent a few evenings polishing the book, removing a lot of outdated material and adding new things that are more relevant now.
I added materials about virtual conference participation, code hosting, recording your own videos and screencasts, and incorporated some of the posts and materials I created since first publication. Currently it is at roughly 40000 words and the letter sized Word Doc would me 85 pages.
For now, I will publish the book online again, chapter by chapter and also consider creating some ebooks for those who prefer using readers. There’s a dark and light theme and it will work across all resolutions and platforms. I’m using jekyll/eleventy with GitHub pages and learn a few new things on the way.
Here’s the new table of contents:
About this handbook
About this version
About the author
What is Developer Advocacy / Evangelism?
Defining Developer Advocacy
Start with the right mindset
Find your role and play to your strengths
Work with your own company
Prepare for prejudice
Deal with company changes
Be there for internal developers
Work with PR and marketing
Be known as an outward channel
Train other advocates and developers
Share useful technology
Balance your personal and official channels
Remove the brand
Working with your competition
Work with the competition
Show respect to the competition
Acknowledge when the competition is better
Know about the competition
Build examples using and try out competitive products
Prepare for outreach
Get your facts right
Know the audience and their needs
Have expert backup
Choose the right medium
Plan for failure
Get speaking opportunities
Take part in podcasts
Take part in panels
Go to Grass Roots events
Go to Meetups
Write articles
Offer Brownbags
Ask questions at conferences
Be a presenter people want to invite – publish your presenter terms
Travel and conference participation
Getting your travel and accommodation sorted
Who pays what?
Be at the event
Give the event some social media love
Use the event to build a network
Keep track of your conference participation
Work with the conference buzz
Be a part of the conference you talk at
Release immediately
Write about conferences
Deliver a talk or workshop
Be yourself
Invite communication
Prepare takeaways
Plan time for and own the questions and answers
Be honest and real
Follow up communication
Delivering presentations tips: timekeeping and more
How will I fit all of this in X minutes?
Less is more
Your talk is only extremely important to you
Map out more information
Live coding?
Avoid questions
Things to cut
Talk fillers
Planning Your Talk Summary
Things not to say on stage – and what to do instead
“This is easy…”
“I’ll repeat quickly, for the few of you who don’t know…”
“Everybody can do that…”
“X solves this problem, so you don’t have to worry about it”
“As everybody knows…”
“This is just like we learned in school…”
“That’s why Y(your product) is much better than (competitor) X”
To celebrate the 25th birthday of our favourite strange and wonderful language for the web, Pluralsight has ramped up the JavaScript.com domain and offers 25 free courses over the month of December. Click the following overview to sign up for free and see them.
In addition to that, on the 10th of December there’ll be a live JavaScript build session with Cassidy Williams.
One request that keeps coming up in web design right now are card interfaces that work like this:
They should have headings and text and link to another document
You should be able to click anywhere on the card to go to the other document
Except, there could also be inline links in text that should go to another document
And they should have a button to close them
Basically this:
The problem with that interface is that whilst anchor elements can contain other elements, nesting them makes no semantic sense and is invalid HTML.
So if you tried:
<ahref="#1">One
<ahref="#2">Two</a></a>
<a href="#1">One
<a href="#2">Two</a>
</a>
The HTML parser rightfully would kick the second link out.
We need to be cleverer about this. I wanted to work with that and play with some features of the browser developer tools at the same time. That’s how I came up with a clickable card interface in 50 lines of CSS and 11 lines of JavaScript.
<ulclass="fullclick"><li><h2>Dogs</h2><p>
Dogs are excellent, and good people. If want to browse dogs
by breed, check <ahref="https://codepo8.github.io/dog-browser/">
The dog browser</a>. Almost all dogs are good boys and girls.
</p><ahref="dogs.html"class="main">More dog news</a><buttontitle="click to close"aria-label="click to close">x</button></li><li><h2>Wombats</h2><p>
Wombats are cute as buttons and digging machines. They look always
chill and jolly, but aren't a good idea to keep in the house.
</p><ahref="wombat.html"class="main">More wombat info</a><buttontitle="click to close"aria-label="click to close">x</button></li></ul>
<ul class="fullclick">
<li>
<h2>Dogs</h2>
<p>
Dogs are excellent, and good people. If want to browse dogs
by breed, check <a href="https://codepo8.github.io/dog-browser/">
The dog browser</a>. Almost all dogs are good boys and girls.
</p>
<a href="dogs.html" class="main">More dog news</a>
<button title="click to close" aria-label="click to close">x</button>
</li>
<li>
<h2>Wombats</h2>
<p>
Wombats are cute as buttons and digging machines. They look always
chill and jolly, but aren't a good idea to keep in the house.
</p>
<a href="wombat.html" class="main">More wombat info</a>
<button title="click to close" aria-label="click to close">x</button>
</li>
</ul>
An unordered list is easy to style and will also tell screenreaders that the items are linked. It will even announce “1 of 2”, “2 of 2” and so on.
Using a button with an aria-label to close the card makes it keyboard accessible and screenreaders won’t read “button x” which doesn’t give much information.
Making the whole card clickable
Positioning each list item relative makes sure all positioned elements are contained in it.
Create an overlay over the whole list item that links to the document works with CSS generated content. Setting a z-index of 1 makes sure this covers all elements without positioning.
.fullclick li {list-style:none;margin:1em0;padding:20px10px;background:#2b2b2b;position:relative;}.fullclick a.main{color:#85baff;text-align:right;display:block;z-index:1;}.fullclick li a.main::after{position:absolute;top:0;left:0;right:0;bottom:0;content:' ';}
As part of my Tile Editor I needed a way to shift an image by x pixels left, right, up or down. I didn’t need to move the image, I needed to shift the pixels of the image. This allows you now to shift the image and thus makes painting seamless tiles much easier.
Now, visually this is easily done using CSS. You can use the image as a background, define background-repeat as repeat and offset the image using background-position. You can play with this here :
This is pretty straight forward and performs well (as a test, click the image in the above demo for some useless fancy stuff. Click again to stop it).
With background position being zero in horizontal and vertical the image is just the image:
When you set the the horizontal offset to 130 and the vertical to 115 you get a shifted image and the image data gets repeated:
But it is only visual. You don’t really change the image data – you just display it. If I wanted users to shift the image and save it, they’d have to create a screenshot.
Canvas to the rescue – shifting an image
Now, manipulation of image data can be done using HTML canvas. You can manipulate images pixel by pixel, but – even better – you can slice parts of the image out, cache it, manipulate the image and then paste the sliced part again.
For example if you wanted to shift the data 100px to the left, you’d need to slice out a 100px wide part of it on the left, move the rest of the image to the top left corner of the canvas and paste the slice 100px from the top right corner of the canvas.
As code, this looks somewhat like this:
// Create canvas, store context and add to DIV
let c = document.createElement('canvas');
let cx = c.getContext('2d');
document.querySelector('div').appendChild(c);// load image and // resize canvas to be the same size as the image
let i =new Image();
i.src='puking-unicorn.jpg';
i.onload=function(){
c.height= i.naturalHeight;
c.width= i.naturalWidth;
cx.drawImage(i,0,0);}// Slice method to shift image const slice = _ =>{// get image data from the top left to 100px from the left// store it as slice
let slicedata = cx.getImageData(0,0,100, c.height);// get image data from the 100px left to the end of the image// store it as slice
let restdata = cx.getImageData(100,0, c.width, c.height);// clear the canvas (not needed, but safe)
cx.clearRect(0,0, c.width, c.height);// put the restdata to the top left of the canvas
cx.putImageData(restdata,0,0);// put the slice data 100px from the right on the canvas
cx.putImageData(slicedata, c.width-100,0);}// if the user clicks on the image, move it
c.addEventListener('click', slice);
// Create canvas, store context and add to DIV
let c = document.createElement('canvas');
let cx = c.getContext('2d');
document.querySelector('div').appendChild(c);
// load image and
// resize canvas to be the same size as the image
let i = new Image();
i.src = 'puking-unicorn.jpg';
i.onload = function() {
c.height = i.naturalHeight;
c.width = i.naturalWidth;
cx.drawImage(i, 0, 0);
}
// Slice method to shift image
const slice = _ => {
// get image data from the top left to 100px from the left
// store it as slice
let slicedata = cx.getImageData(0, 0, 100, c.height);
// get image data from the 100px left to the end of the image
// store it as slice
let restdata = cx.getImageData(100, 0, c.width, c.height);
// clear the canvas (not needed, but safe)
cx.clearRect(0, 0, c.width, c.height);
// put the restdata to the top left of the canvas
cx.putImageData(restdata, 0, 0);
// put the slice data 100px from the right on the canvas
cx.putImageData(slicedata, c.width - 100,0);
}
// if the user clicks on the image, move it
c.addEventListener('click', slice);
This takes care of shifting to the left. If you want to move the image right, to the bottom or up, you need to tweak the coordinates for the slices accordingly. The following animation show how this is done. Click the different buttons to see the steps to move the image around.
Making it generic: CanvasShift.js
This takes a bit of fiddling, so I thought I make it easier and created CanvasShift.js.
This allows you to shift any canvas by x and y pixels. You can see it in action by trying out the test page .
This would make our first example of shifting 100px to the left the following:
<scriptsrc="canvasshift.js"></script><script>
<script src="canvasshift.js"></script>
<script>
let c = document.createElement('canvas');
let cx = c.getContext('2d');
document.body.appendChild(c);
let i =new Image();
i.src='puking-unicorn.jpg';
i.onload=function(){
c.height= i.naturalHeight;
c.width= i.naturalWidth;
cx.drawImage(i,0,0);
canvasshift(c,-100,0);}
let c = document.createElement('canvas');
let cx = c.getContext('2d');
document.body.appendChild(c);
let i = new Image();
i.src = 'puking-unicorn.jpg';
i.onload = function() {
c.height = i.naturalHeight;
c.width = i.naturalWidth;
cx.drawImage(i, 0, 0);
canvasshift(c, -100, 0);
}
</script>
</script>
For other shifting, use different parameters. For example to shift the image 100 pixels to the right and 20 pixels up, you use canvasshift(c, 100, -20), to move 15px left and 20px down, canvasshift(c, 15, 20) and so on…
If the loading part is annoying to you, you can also use the load method of the script:
let c = document.createElement('canvas');
document.body.appendChild(c);const shift = _ =>{
canvasshift(c,-200);}
canvasshift.load(c,'puking-unicorn.jpg', shift);
let c = document.createElement('canvas');
document.body.appendChild(c);
const shift = _ => {
canvasshift(c, -200);
}
canvasshift.load(c, 'puking-unicorn.jpg', shift);
This one takes three parameters, of which the last one is optional. The first is the canvas, the second the url of the image (this needs to be on the same domain – or a cors-enabled one) and a callback method that will be called once the image was successfully loaded.
Summary
Whilst CSS should be enough in most of the cases you want to do some image shifting, this should get you on the way. There are more options in canvas like defining images as patterns an using transform, but for non-animated shifting this seems to be the easiest option.
Posted in General | Comments Off on Shifting an image with canvas