Freelancers: 5 Ways To Lose Your Clients

Original Source: https://www.hongkiat.com/blog/ways-to-lose-your-clients/

Clients are a feared group of people who freelancers depend greatly upon . Some clients are incredibly easy to work with; they say what they mean and mean what they say, and they never pay late….

Visit hongkiat.com for full content.

15 Fun and Inspiring Examples of CSS Animation

Original Source: http://feedproxy.google.com/~r/1stwebdesigner/~3/wqO5MiuT-Ks/

CSS is a powerful coding language that can give style and personality to HTML. CSS animations, in particular, are created by transitioning between various CSS configurations over a period of time.

There are a lot of extremely practical cases for CSS animation, such as the ability to animate HTML elements without the use of JavaScript or Flash (although some do utilize JavaScript).

In this article, we’ll be taking a look at 15 lighthearted CSS animation projects to give you inspiration for your next endeavor. These are going to be practical applications that have a certain level of whimsy and fun to them. Hopefully, they’re just as fun to work on!

Google’s Game of the Year

Google’s Game of the Year

The Game of the Year animation for Google looks like a fairly simple CSS animation. It features the title text falling slightly, and the elements bumping into each other. While there is plenty of code that went into this, the core is animating the rotation of the elements after a delay.

Cascading Solar System

See the Pen
Cascading Solar System! by Tady Walsh (@tadywankenobi)
on CodePen.

The author of cascading solar system obviously has an eye for humor, naming his project so that it also can be abbreviated as CSS. This is an impressive but unassuming animation that models the solar system in 2D. The orbits use a scaled rotation speed so that they’re all accurate to their real-world counterparts.

Gooey Menu

See the Pen
Gooey Menu by Lucas Bebber (@lbebber)
on CodePen.

Menu animations are a pretty common use of CSS, and this gooey menu is no exception. This has plenty of small details, including a slight increase in size when hovering over the button, and then the bouncy, gelatinous animation when the menu expands.

Each individual button then highlights when hovered over. It is also a special treat to notice the subtle details. Take note of how the hamburger menu symbol collapses into an X and transforms back when you close the menu again.

Flying Birds at Fournier Père et Fils

Flying Birds at Fournier Père et Fils

This winery’s homepage features an animation that involves two birds flying across the screen. The process of applying this animation is actually fairly straightforward.

The first layer of animation is to animate the birds flapping their wings, which works much like a flipbook. The second step is the animated vertical and horizontal path that the bird follows, in order to make the speed and flight path look natural. This is done through keyframe animation. The best part is, this can be replicated across any number of birds, you will just need to vary the timing a little bit.

Ball Loading Animation

See the Pen
CSS loading animation by Patrik Hjelm (@patrikhjelm)
on CodePen.

This loading animation is another simple one. It is a vertical line of seven circles that swing back and forth horizontally in a seemingly random pattern.

In terms of CSS code, each ball has its own short few lines of animation. Each ball has the same code except for the length of time that it takes to move side-to-side. This creates a variation between each element.

The rest of the code defines the keyframe points, so really it’s just selecting two keyframe points and varying the amount of time it takes for the circles to travel between them. While straightforward, this is often all you need for a loading screen!

Submarine

See the Pen
Submarine with CSS by Alberto Jerez (@ajerez)
on CodePen.

This CSS exercise features a little red submarine roving the ocean. It has several simple animated elements that come together to make a very pleasing looking loop. This is a lot of keyframing and elements linked to each other, but it’s a fun inspiration for your own CSS projects!

Circles Loading Animation

See the Pen
Animated – SVG Loader by Steven Roberts (@matchboxhero)
on CodePen.

Simple loading screens are one of the best ways to show off CSS, and these concentric circles are no different. The code is pretty quick and simple, essentially telling the circles to ease in and out of rotation at different intervals.

Since the shapes don’t actually change size, and just rotate around, it’s a pretty straightforward exercise in CSS! And it makes a great addition to any website.

Moving Background Mask

See the Pen
Animated – Background Mask by Steven Roberts (@matchboxhero)
on CodePen.

At first glance, you might not realize there is an animation going on here. But look closely, and you’ll see the colored background slowly gliding down. This is an extremely subtle effect, but sometimes that’s what CSS is all about!

At its core, this is using masking as you might see in a photo or video editing software. It only displays the image on the masked layer, and moves the image along a path.

Flat Design Camera

See the Pen
Flat design camera with CSS animation by Damien Pereira Morberto (@damienpm)
on CodePen.

This flat design camera image has a clever concept around it. Press the camera button, and it takes a picture! Well, sort of. The images are predetermined for this code, but the potential for more is there.

This CSS project has several small moving parts, such as the flashing red light on the left side, and the animation of the entire asset as the camera “prints” a photo. Overall, this definitely has some practical applications for any photo-related app that might access a user’s webcam.

Pulse Animation

See the Pen
Animated – SVG Pulse by Steven Roberts (@matchboxhero)
on CodePen.

This is another simple but effective CSS animation. And that’s a trend here! Some of the best uses of CSS are straightforward and simple. No need to get overcomplicated with it.

This one just sends out a few circles that fade out when they expand to their fullest. It’s pretty easy to come up with and to replicate. So, this is a great place to start for a simple CSS project if you’re looking for inspiration as a newcomer to the language.

Bubbling Up

See the Pen
Animated – SVG Bubbles by Steven Roberts (@matchboxhero)
on CodePen.

This bubble animation is made up of a few elements and animations. The first level of animation changes the bubble opacity and makes the image move vertically, so it looks like the bubbles rise up out of nothing.

The second level of animation creates a wobbling effect to make the bubbles look more alive and natural. This makes great use of keyframes, which really make CSS animations look smooth.

Google Now 3rd Party Apps

See the Pen
Google Now 3rd Party Apps by Paweł Kuna (@codecalm)
on CodePen.

This animation is inspired by another designer’s concept that was made in After Effects, but this one does it just with CSS! It’s a cute flat icon pack that pops into existence and slides out. This CSS code makes heavy use of keyframes and timing the different elements as they pop in.

It’s basically just the same code for each icon, but time-adjusted appropriately. This is great inspiration for making something that is simple overall, but is complex when you put all the pieces together.

Hamburger Menu

See the Pen
Hamburger Icon CSS3 ONLY Animation by Dawid Krajewski (@DawidKrajewski)
on CodePen.

Don’t let this simple hamburger menu fool you, it’s actually quite complicated. This doesn’t use any HTML or JavaScript and is entirely made in CSS.

What makes this complex is the fact that it doesn’t use HTML, so all of the shapes in this animation had to be created within CSS alone. From there, there is a lot of keyframe animation to construct the transformation between shapes. This should get you inspired to ditch the traditional HTML and try something different!

Perspective Split Text Animation

See the Pen
Perspective Split Text Menu Hover by James Bosworth (@bosworthco)
on CodePen.

This animated menu looks simple on the outside but can make a big impact on any website. When you hover over the area, the text changes perspective to follow your mouse. When you hover over a specific block of text, it gets split in half.

The animation uses some different techniques to achieve these goals, so it’s a great inspiration as an exercise for practicing some advanced CSS skills.

Floating Ghost

See the Pen
ghost by Beep (@scoooooooby)
on CodePen.

Let’s end with something fun! This adorable ghost just floats up and down, indefinitely. The image just eases in and out, up and down, and the shadow underneath expands and contracts. This simple animation is versatile and can be used as a loading screen or just about anything else!

A Moving Inspiration

CSS is a powerful tool in your web design pocket. Hopefully, these funny and lighthearted animations can inspire you to go out and create your own awesome concepts.

Always remember that you don’t have to make something just for productivity’s sake! You can create something just for fun – even if it serves no purpose. And who knows, maybe someone else will see it, and become inspired themselves.


How to Run Custom Tasks in Windows 10 with Cortana

Original Source: https://www.hongkiat.com/blog/make-cortana-do-custom-chores-in-windows-10/

Detailed guide to enable Cortana do custom tasks in Windows 10 through some simple steps.

The post How to Run Custom Tasks in Windows 10 with Cortana appeared first on Hongkiat.

Visit hongkiat.com for full content.

Is the Rise of Millennial Women in Tech Just an Illusion?

Original Source: https://www.sitepoint.com/rise-of-younger-women-in-tech/?utm_source=rss

woman with computer

This article was created in partnership with the Developer Economics Survey. Thank you for supporting the partners who make SitePoint possible.

The latest Developer Economics survey is upon us again, and as always, we highly recommend that everyone participates. It’s an excellent opportunity to express your views about what’s happening in the world of web development, and it helps paint a cohesive picture about the landscape.

In the last survey, published April 2019, we garnered a lot of interesting insights into the modern dev at work. Of the participants in the last survey, 9% were women, suggesting a global population of 1.7 million women developers versus the 17 million that are men. However, the report also found that under the age of 35, 36% of developers were women, versus 33% of men. Compare this with the survey’s other finding that 37% of male developers are over 35 years of age, as compared to 29% of women in the same age bracket. This indicates that younger generations of women are increasingly moving towards a career in development. Hopefully in the next few years we’ll start seeing parity between male and female developers in more senior roles. Currently men are almost three times more likely to hold senior or C-suite positions than women.

However, as the report also notes, a less optimistic reading of the data may be that women “have always been involved, but tend to leave software development as they get older, either by choice or necessity.”

The post Is the Rise of Millennial Women in Tech Just an Illusion? appeared first on SitePoint.

A Look at WordPress Plugin Ecosystems

Original Source: http://feedproxy.google.com/~r/1stwebdesigner/~3/FpmVc7Ha6k4/

Among the many strengths of WordPress is the massive number of available plugins. There are tens of thousands, and those are just the free offerings. They handle all sorts of functionality, from security to image galleries to forms. Just about everything you could possibly want for your website is only a download away.

But it is the rare plugin that is so well-crafted and useful that it inspires a number of companion offerings to use along side of it. In many cases, they are among the most popular plugins out there. So popular and well-liked, in fact, that they have developed their very own ecosystems.

Today, we’ll take a look at the concept of WordPress plugin ecosystems. Along the way, we’ll show you some examples and discuss the advantages (and disadvantages) that come with adopting them into your website.

Prime Examples

Before we dig too deeply into the pros and cons, let’s see what a plugin ecosystem looks like. For our purposes, we’ll define it as such:

A “base” or “core” plugin that works on its own, but also has multiple add-on plugins available;
Add-ons may be created by the original author, or by outside developers within the WordPress community;
Can be free, commercial or any combination thereof;

In short, this means that the term “ecosystem” is rather flexible. It might be that a plugin’s author has created the base and all add-ons themselves. Or, other developers out there may have decided to build their own extensions. Either way, we have a group of related plugins that can scale up functionality based on need.

Here are a few prime examples we can use to better illustrate the concept:

WooCommerce

Perhaps the most well-known plugin ecosystem, WooCommerce turns your website into an online store. The core plugin adds shopping cart functionality and related features that go along with it for things like shipping and accepting payments. However, it is capable of so much more.

Through the use of add-ons (WooCommerce refers to them as “extensions”), you can leverage the cart for all sorts of niche functionality. Among the more basic features are the ability to work with a wider variety of payment gateways and shipping providers. But you can also add some advanced capabilities such as selling membership subscriptions or event tickets.

Gravity Forms

Here’s a great example of a plugin whose ecosystem has taken a core concept and expanded it immensely. Gravity Forms is a form-building plugin, which already includes a lot of advanced functionality. Yet add-ons allow it to perform tasks well beyond what you’d expect from your standard contact form.

Through a community that both includes and goes beyond the plugin’s original author, add-ons allow for a number of advanced tasks. You can accept payments, run polls or surveys, connect with third-party service providers, view and manipulate entry data and a whole lot more. It may one of the best examples of how an ecosystem provides nearly endless flexibility.

WooCommerce and Gravity Forms

Something to Build On

One of the biggest advantages to buying into one of these plugin ecosystems is that you can add what you need, when you need it. Think of it as a building. The base plugin provides you with a solid foundation (and maybe a floor or two). Then, you can add as many floors as it takes to fulfill your needs.

Sometimes, that first core plugin is all you need. But even then, you still have the blueprints to build upon should you want to expand later.

Another potential benefit is that these plugins tend to have been built with expansion in mind. That means that you don’t necessarily have to rely on official or even community-based add-ons. If you have some programming knowledge, you might be able to add functionality by building it yourself.

Plus, by utilizing a related set of plugins, you can avoid one of the more frustrating parts of WordPress site development. So often, we attempt to bring many disparate pieces together to form some sort of cohesively functioning website.

This often means using plugins that were never meant to necessarily work together, which can lead to problems when attempting to make it all run seamlessly. In theory, this shouldn’t be an issue when you tap into an ecosystem.

A skyscraper building.

Potential Drawbacks

Despite the many advantages to using a set of related plugins, there are some possible downsides to consider. Among the most common:

It Can Get Expensive

For plugins with commercial add-ons, you may find yourself being nickeled and dimed for each and every piece of added functionality you’d like to add. WooCommerce is a classic example, where each official add-on requires a yearly investment. That’s not to say it’s not worth the cost – it very well may be. Rather, it is a potential obstacle for the budget-conscious.

Not Everything You Want Is Available

This is something you’ll want to check before making any decisions as to how you’ll build your site. It may be that a base plugin and a selection of add-ons will get you 90% of the functionality you need. However, that missing 10% could be a big deal.

If a companion plugin doesn’t cover this, you might have to either look elsewhere or build it yourself. That could lead to some unexpected issues when it comes to both compatibility and cost. Short of those options, a lack of that one piece of functionality can result in a long wait in hopes of it being added in at a later date.

Unofficial Add-Ons May Not Keep Pace

Plugins are updated with new features and bugfixes all the time. Sometimes, those updates can be major – and that poses a risk when using unofficial add-ons built by community members. It could mean that updating the base plugin means that you have to abandon a particular add-on.

One way to avoid this potential issue is to stick with official add-ons only. If you do utilize those from unofficial sources, look for plugins that are frequently updated. They are more likely to adapt to any major upgrades.

Broken glass.

A Compelling Option

In the right situation, a WordPress plugin with its own ecosystem can be your best option. This is especially so in cases when you are building a website in which a plugin fulfills the core part of your mission.

For instance, an eCommerce site will want to use a shopping cart that can be expanded to meet the specific requirements of the store. This provides the best opportunity for future growth and will help you avoid a costly switch later on.

Of course, there are some potential negatives to consider. But with some due diligence, you may just find a collection of plugins that will successfully power your WordPress website for years to come.


The 10 People Who Helped Shape Adobe Photoshop

Original Source: https://www.hongkiat.com/blog/heroes-of-photoshop/

Nowadays it’s impossible to find a professional website and even physical prints that is not digitally processed by Photoshop. In fact, almost every product or design today, including…

Visit hongkiat.com for full content.

How To Build A Sketch Plugin With JavaScript, HTML And CSS (Part 2)

Original Source: https://www.smashingmagazine.com/2019/07/build-sketch-plugin-javascript-html-css-part-2/

How To Build A Sketch Plugin With JavaScript, HTML And CSS (Part 2)

How To Build A Sketch Plugin With JavaScript, HTML And CSS (Part 2)

Matt Curtis

2019-07-08T12:30:59+02:00
2019-07-08T13:07:00+00:00

As mentioned in part 1, this tutorial is intended for people who know and use the Sketch app and are not afraid of dabbling with code as well. To profit from it the most, you will need to have at least some basic experience writing JavaScript (and, optionally, HTML/CSS).

In the previous part of this tutorial, we learned about the basic files that make up a plugin, and how to create the plugin’s user interface. In this second and final part, we’ll learn how to connect the user interface to the core plugin code and how to implement the plugin’s main features. Last but not least, we’ll also learn how to optimize the code and the way the plugin works.

Building The Plugin’s User Interface: Making Our Web Interface And The Sketch Plugin Code “Talk” To Each Other

The next thing we need to do is to set up communication between our web interface and the Sketch plugin.

We need to be able to send a message from our web interface to the Sketch plugin when the “Apply” button in our web interface is clicked. This message needs to tell us about what settings the user has input — like the number of steps, rotation amount, the number of duplicates to create, and so on.

WKWebView makes this task a little bit easier for us: we can send messages to our Sketch plugin from our web interface’s JavaScript code by using the window.webkit.messageHandlers API.

On our Sketch code’s side, we can use another method, addScriptMessageHandler:name: (or addScriptMessageHandler_name) to register a message handler that will be called whenever it receives a message sent from our plugin web interface.

Let’s start by making sure we can receive messages from our web UI. Head over to our ui.js file’s createWebView function, and add the following:

function createWebView(pageURL){
const webView = WKWebView.alloc().init();

// Set handler for messages from script

const userContentController = webView.configuration().userContentController();

const ourMessageHandler = …

userContentController.addScriptMessageHandler_name(
ourMessageHandler, “sketchPlugin”
);

// Load page into web view

webView.loadFileURL_allowingReadAccessToURL(pageURL, pageURL.URLByDeletingLastPathComponent());

return webView;
};

Here we use the web view’s userContentController property to add a message handler we’ve named “sketchPlugin”. This “user content controller” is the bridge that ensures messages get across from our web view.

You might have noticed something odd about the above code: the object we’re adding as the message handler, ourMessageHandler, doesn’t exist yet! Unfortunately, we can’t just use a regular JavaScript object or function as the handler, as this method expects a certain kind of native object.

Luckily for us, we can get around this limitation by using MochaJSDelegate, a mini-library I wrote that makes it possible to create the kind of native object we need using regular ol’ JavaScript. You’ll need to manually download and save it in your plugin bundle under Sketch/MochaJSDelegate.js.

In order to use it, we’ll need to first import it into ui.js. Add the following at the top of the file:

const MochaJSDelegate = require(“./MochaJSDelegate”);

Now we can use MochaJSDelegate to create the type of message handler addScriptMessageHandler:name: is expecting:

function createWebView(pageURL){
const webView = WKWebView.alloc().init();

// Set handler for messages from script

const userContentController = webView.configuration().userContentController();

const scriptMessageHandler = new MochaJSDelegate({
“userContentController:didReceiveScriptMessage:”: (_, wkMessage) => {
/* handle message here */
}
}).getClassInstance();

userContentController.addScriptMessageHandler_name(
scriptMessageHandler, “sketchPlugin”
);

// Load page into web view

webView.loadFileURL_allowingReadAccessToURL(pageURL, pageURL.URLByDeletingLastPathComponent());

return webView;
};

The code we just added creates the native object we need. It also defines a method on that object named userContentController:didReceiveScriptMessage: — this method is then called with the message we want as the second argument. Since we’re not actually sending any messages yet, we’ll have to come back here at a later time and add some code to actually parse and handle the messages we receive.

Next, we need to add some code to our web interface to send us those messages. Head over to /Resources/web-ui/script.js. You’ll find I’ve already written most of the code that handles retrieving the values of the HTML <inputs /> the user will enter their options into.

What’s still left for us to do is to add the code that actually sends the values over to our Sketch code:

Find the apply function and add the following to the end of it:

// Send user inputs to sketch plugin

window.webkit.messageHandlers.sketchPlugin.postMessage(JSON.stringify({
stepCount, startingOptions, stepOptions
}));

Here we use window.webkit.messageHandlers API we mentioned earlier to access the message handler we registered above as sketchPlugin. Then send a message to it with a JSON string containing the user’s inputs.

Let’s make sure everything is set up properly. Head back to /Sketch/ui.js. In order to make sure we’re getting messages as we expect, we’ll modify the method we defined earlier so that it displays a dialog when we get a message:

function createWebView(pageURL){
// …

const scriptMessageHandler = new MochaJSDelegate({
“userContentController:didReceiveScriptMessage:”: (_, wkMessage) => {
const UI = require(“sketch/ui”);

UI.alert(“Hey, a message!”, wkMessage.body());
}
}).getClassInstance();

userContentController.addScriptMessageHandler_name(
scriptMessageHandler, “sketchPlugin”
);

// …
};

Now run the plugin (you may need to first close any existing Mosaic window you have opened), enter some values, then click “Apply”. You should see an alert like the one below — this means everything is wired up correctly and our message went through successfully! If not, go back over the previous steps and ensure that everything was done as described.

Image showing the dialog you should see after clicking the ‘apply’ button in the plugin’s UI.

The dialog you should see appear once you click Apply. (Large preview)

Now that we’re able to send messages from our interface to our plugin, we can move on to writing the code that actually does something useful with that information: generating our layer mosaics.

Generating The Layer Mosaics

Let’s take stock of what’s necessary in order to make this happen. Simplifying things a bit, what our code needs to do is:

Find the current document.
Find the current document’s selected layer.
Duplicate the selected layer (we’ll call it the template layer) x number of times.
For each duplicate, tweak its position, rotation, opacity, etc., by the specific values (amounts) set by the user.

Now that we’ve got a reasonable plan, let’s continue writing. Sticking with our pattern of modularizing our code, let’s create a new file, mosaic.js in the Sketch/ folder, and add to it the following code:

function mosaic(options){

};

module.export = mosaic;

We’ll use this function as the only export of this module since it makes for a simpler API to use once we import it — we can just call mosaic() with whatever options we get from the web interface.

The first two steps we need to take are getting the current document, and then its selected layer. The Sketch API has a built-in library for document manipulation which we can get access to by importing the sketch/dom module. We only need the Document object right now, so we’ll pull it out explicitly. At the top of the file, add:

const { Document } = require(“sketch/dom”);

The Document object has a method specifically for accessing the current document we can use, called getSelectedDocument(). Once we have the current document instance, we can access whatever layers the user has selected via the document’s selectedLayers property. In our case, though, we only care about single-layer selections, so we’ll only grab the first layer the user has selected:

function mosaic(options){
const document = Document.getSelectedDocument();
const selectedLayer = document.selectedLayers.layers[0];
};

module.export = mosaic;

Note: You might have been expecting selectedLayers itself to be an array, but it’s not. Instead, it’s an instance of the Selection class. There’s a reason for this: the Selection class contains a bunch of useful helper methods for manipulating the selection like clear, map, reduce, and forEach. It exposes the actual layer array via the layer property.

Let’s also add some warning feedback in case the user forgets to open a document or to select something:

const UI = require(“sketch/ui”);

function mosaic(options){
const document = Document.getSelectedDocument();

// Safety check:

if(!document){
UI.alert(“Mosaic”, “⚠️ Please select/focus a document.”);

return;
}

// Safety check:

const selectedLayer = document.selectedLayers.layers[0];

if(!selectedLayer){
UI.alert(“Mosaic”, “⚠️ Please select a layer to duplicate.”);

return;
}
};

module.export = mosaic;

Now that we’ve written the code for steps 1 and 2 (finding the current document and selected layer), we need to address steps 3 and 4:

Duplicate the template layer x number of times.
For each duplicate, tweak its position, rotation, opacity, etc., by the specific values set by the user.

Let’s start by pulling all the relevant information we need out of options: the number of times to duplicate, starting options, and step options. We can once again use destructuring (like we did earlier with Document) to pull those properties out of options:

function mosaic(options) {
// …

// Destructure options:

var { stepCount, startingOptions, stepOptions } = options;
}

Next, let’s sanitize our inputs and ensure that step count is always at least 1:

function mosaic(options) {
// …

// Destructure options:

var { stepCount, startingOptions, stepOptions } = options;

stepCount = Math.max(1, stepCount);
}

Now we need to make sure that the template layer’s opacity, rotation, etc., all match up with the user’s desired starting values. Since applying the user’s options to a layer is going to be something we’ll do a lot of, we’ll move this work into its own method:

function configureLayer(layer, options, shouldAdjustSpacing){
const { opacity, rotation, direction, spacing } = options;

layer.style.opacity = opacity / 100;
layer.transform.rotation = rotation;

if(shouldAdjustSpacing){
const directionAsRadians = direction * (Math.PI / 180);
const vector = {
x: Math.cos(directionAsRadians),
y: Math.sin(directionAsRadians)
};

layer.frame.x += vector.x * spacing;
layer.frame.y += vector.y * spacing;
}
};

And because spacing only needs to be applied in-between the duplicates and not the template layer, we’ve added a specific flag, shouldAdjustSpacing, that we can set to true or false depending on whether we’re applying options to a template layer or not. That way we can ensure that rotation and opacity will be applied to the template, but not spacing.

Back in the mosaic method, let’s now ensure that the starting options are applied to the template layer:

function mosaic(options){
// …

// Configure template layer

var layer = group.layers[0];

configureLayer(layer, startingOptions, false);
}

Next, we need to create our duplicates. First, let’s create a variable that we can use to track what the options for the current duplicate are:

function mosaic(options){
// …

var currentOptions; // …
}

Since we already applied the starting options to the template layer, we need to take those options we just applied and add the relative values of stepOptions in order to get the options to apply to the next layer. Since we’ll also be doing this several more times in our loop, we’ll also move this work into a specific method, stepOptionsBy:

function stepOptionsBy(start, step){
const newOptions = {};

for(let key in start){
newOptions[key] = start[key] + step[key];
}

return newOptions;
};

After that, we need to write a loop that duplicates the previous layer, applies the current options to it, then offsets (or “steps”) the current options in order to get the options for the next duplicate:

function mosaic(options) {
// …

var currentOptions = stepOptionsBy(startingOptions, stepOptions);

for(let i = 0; i < (stepCount – 1); i++){
let duplicateLayer = layer.duplicate();

configureLayer(duplicateLayer, currentOptions, true);

currentOptions = stepOptionsBy(currentOptions, stepOptions);
layer = duplicateLayer;
}
}

All done — we’ve successfully written the core of what our plugin is supposed to do! Now, we need to wire things up so that when the user actually clicks the “Apply” button our mosaic code is invoked.

Let’s head back to ui.js and adjust our message handling code. What we’ll need to do is parse the JSON string of options we’re getting so that they’re turned into an object we can actually use. Once we have these options, we can then call the mosaic function with them.

First, parsing. We’ll need to update our message handling function to parse the JSON message we get:

function createWebView(pageURL){
// …

const scriptMessageHandler = new MochaJSDelegate({
“userContentController:didReceiveScriptMessage:”: (_, wkMessage) => {
const message = JSON.parse(wkMessage.body());
}
});
}

Next, we’ll need to pass this over to our mosaic function. However, this isn’t really something our code in ui.js should be doing — it’s supposed to be primarily concerned with what’s necessary to display interface-related things on screen — not creating mosaics itself. To keep these responsibilities separate, we’ll add a second argument to createWebView that takes a function, and we’ll call that function whenever we receive options from the web interface.

Let’s name this argument onApplyMessage:

function createWebView(pageURL, onApplyMessage){
// …

const scriptMessageHandler = new MochaJSDelegate({
“userContentController:didReceiveScriptMessage:”: (_, wkMessage) => {
const message = JSON.parse(wkMessage.body());

onApplyMessage(message);
}
});
}

We’ll also need to modify our exported method, loadAndShow, to take this onApplyMessage argument as well and pass it off to createWebView:

function loadAndShow(baseURL, onApplyMessage){
// …

const webView = createWebView(pageURL, onApplyMessage);
}

Finally, head over to main.js. We now need to import our mosaic function, and call it with the options we receive from the plugin’s user interface:

const mosaic = require(“./mosaic”);

function onRun(context){
UI.loadAndShow(context.scriptURL, options => {
mosaic(options);
});
};

We’re almost done!

However, if we ran our code now and clicked the “Apply” button in the plugin interface, nothing would happen. Why? The reason is due to how Sketch scripts are run: by default, they “live” only until the bottom of your script is reached, after which Sketch destroys it and frees up whatever resources it was using.

This is a problem for us since it means that anything we need to have asynchronously happen (in this case, that’s after the bottom of our code is reached), like receiving messages, cannot, because our script has been destroyed. This means we wouldn’t get any of our messages from the web interface since we’re not around to receive and respond to them!

There’s a way to signal to Sketch that we need our script to stay alive beyond this point, using Fibers. By creating a Fiber, we tell Sketch that something asynchronous is happening and that it needs to keep our script around. Sketch will then only destroy our script when absolutely necessary (like the user closing Sketch, or when the Mosaic plugin needs to be updated):

// …

const Async = require(“sketch/async”);

var fiber;

function onRun(context){
if(!fiber){
fiber = Async.createFiber();
fiber.onCleanup(() => {
UI.cleanup();
});
}

UI.loadAndShow(context.scriptURL, options => {
mosaic(options);
});
};

Voilà! Let’s try out our plugin now. With a layer selected in Sketch, enter some settings, then click apply:

Let’s try out our plugin now — with a layer selected in Sketch, enter some settings, then click “Apply.”

Final Improvements

Now that we’ve got the majority of our plugin’s functionality implemented, we can try to “zoom out” a bit and take a look at the big picture.

Improving The User’s Experience

If you’ve played around with the plugin in its current state, you might’ve noticed that one of the biggest points of friction appears when you try to edit a Mosaic. Once you create one, you have to hit undo, adjust the options, then click ‘Apply’ (or press Enter). It also makes it harder to edit a Mosaic after you’ve left your document and returned to it later, since your undo/redo history will have been wiped out, leaving you to manually delete the duplicate layers yourself.

In a more ideal flow, the user could just select a Mosaic group, adjust options and watch the Mosaic update until they get the exact arrangement they’re looking for. To implement this, we have two problems to solve:

First, we’ll need a way to group the duplicates that make up a Mosaic together. Sketch provides the concept of Groups, which we can use to solve this problem.
Second, we’ll need a way to tell the difference between a normal, user-created group and a Mosaic group. Sketch’s API also gives us a way to store information on any given layer, which we can use as a way tag and later identify a group as one of our ‘special’ Mosaic groups.

Let’s revisit the logic we wrote in the previous section to address this. Our original code follows the following steps:

Find the current document.
Find the current document’s selected layer.
Duplicate the selected layer (we’ll call it the template layer) x number of times.
For each duplicate, tweak its position, rotation, opacity, etc., by the specific values (amounts) set by the user.

In order to make our new user flow possible, we need to change these steps to:

Grab the current document.
Grab the current document’s selected layer.
Determine whether the selected layer is a Mosaic group or not.

If it’s some other layer, use it as the template layer and go to step 4.
If it is a Mosaic group, consider the first layer in it as the template layer, and go to step 5.

Wrap the template layer inside a group, and mark that group as a Mosaic group.
Remove all layers from inside the group except the template layer.
Duplicate the template layer x number of times.
For each duplicate, tweak its position, rotation, opacity, etc., by the specific values set by the user.

We’ve got three new steps. For the first new step, step 3, we’ll create a function named findOrMakeSpecialGroupIfNeeded that will look at the layer passed to it to determine whether or not it’s a Mosaic group. If it is, we’ll just return it. Since the user could potentially select a sublayer nested deep in a Mosaic group, we’ll also need to check the parents of the selected layer to tell if they’re one of our Mosaic groups as well:

function findOrMakeSpecialGroupIfNeeded(layer){
// Loop up through the parent hierarchy, looking for a special group

var layerToCheck = layer;

while(layerToCheck){
if(/* TODO: is mosaic layer? */){
return layerToCheck;
}

layerToCheck = layerToCheck.parent;
}
};

If we weren’t able to find a Mosaic group we’ll simply wrap the layer we were passed inside a Group, then tag it as a Mosaic group.

Back at the top of the file, we’ll need to pull out the Group class now too:

const { Document, Group } = require(“sketch/dom”);

function findOrMakeSpecialGroupIfNeeded(layer){
// Loop up through the parent hierarchy, looking for a special group

var layerToCheck = layer;

while(layerToCheck){
if(/* TODO: is mosaic layer? */){
return layerToCheck;
}

layerToCheck = layerToCheck.parent;
}

// Group

const destinationParent = layer.parent;
const group = new Group({
name: “Mosaic Group”,
layers: [ layer ],
parent: destinationParent
});

/* TODO: mark group as mosaic layer */

return group;
};

Now we need to fill in the gaps (todo’s). To begin with, we need a means of identifying whether or not a group is one of the special groups belonging to us or not. Here, the Settings module of the Sketch library comes to our rescue. We can use it to store custom information on a particular layer, and also to read it back.

Once we import the module at the top of the file:

const Settings = require(“sketch/settings”);

We can then use two key methods it provides, setLayerSettingForKey and layerSettingForKey, to set and read data off a layer:

function findOrMakeSpecialGroupIfNeeded(layer){
const isSpecialGroupKey = “is-mosaic-group”;

// Loop up through the parent hierarchy, looking for a special group

var layerToCheck = layer;

while(layerToCheck){
let isSpecialGroup = Settings.layerSettingForKey(layerToCheck, isSpecialGroupKey);

if(isSpecialGroup) return layerToCheck;

layerToCheck = layerToCheck.parent;
}

// Group

const destinationParent = layer.parent;

layer.remove(); // explicitly remove layer from it’s existing parent before adding it to group

const group = new Group({
name: “Mosaic Group”,
layers: [ layer ],
parent: destinationParent
});

Settings.setLayerSettingForKey(group, isSpecialGroupKey, true);

return group;
};

Now that we’ve got a method that handles wrapping a layer in a mosaic group (or, if already a mosaic group, just returns it) we can now plug it into our main mosaic method just after our safety checks:

function mosaic(options){
// … safety checks …

// Group selection if needed:

const group = findOrMakeSpecialGroupIfNeeded(selectedLayer);
}

Next we’ll add a loop to remove all layers from the group except the template layer (which is the first):

function mosaic(options) {
// …

// Remove all layers except the first:

while(group.layers.length > 1){
group.layers[group.layers.length – 1].remove();
}
}

Lastly, we’ll make sure that the group’s size is fitted to its new contents since the user might have originally selected a layer nested within the old group (a layer that we might have removed).

We’ll also need to make sure to set the current selection to our mosaic group itself. This will ensure that if the user is making a bunch of rapid changes to the same mosaic group it won’t become deselected. After the code we already wrote to duplicate a layer, add:

function mosaic(options) {
// …

// Fit group to duplicates

group.adjustToFit();

// Set selection to the group

document.selectedLayers.clear();
group.selected = true;
}

Try out the plugin again. You should find that editing a mosaic is much smoother now!

Improving The Interface

One other thing you might notice is the lack of synchronization between the display window and the interface inside it, in terms of them both becoming visible at the same time. This is due to the fact that when we display the window, the web interface isn’t guaranteed to have finished loading, so sometimes it’ll “pop” or “flash in” afterwards.

One way to fix this is by listening for when the web interface has finished loading, and only then show our window. There is a method, webView:didFinishNavigation:, that WKWebView will call when the current page has finished loading. We can use it to get exactly the notification we’re looking for.

Back in ui.js, we’ll extend the MochaJSDelegate instance we created to implement this method, which will in turn call the onLoadFinish argument we’ll pass to createWebView:

function createWebView(pageURL, onApplyMessage, onLoadFinish){
const webView = WKWebView.alloc().init();

// Create delegate

const delegate = new MochaJSDelegate({
“webView:didFinishNavigation:”: (webView, navigation) => {
onLoadFinish();
},
“userContentController:didReceiveScriptMessage:”: (_, wkMessage) => {
const message = JSON.parse(wkMessage.body());

onApplyMessage(message);
}
}).getClassInstance();

// Set load complete handler

webView.navigationDelegate = delegate;

// Set handler for messages from script

const userContentController = webView.configuration().userContentController();

userContentController.addScriptMessageHandler_name(delegate, “sketchPlugin”);

// Load page into web view

webView.loadFileURL_allowingReadAccessToURL(pageURL, pageURL.URLByDeletingLastPathComponent());

return webView;
};

And back in the loadAndShow method, we’ll adjust it so that it only shows the window once the web view has loaded:

function loadAndShow(baseURL, onApplyMessage){
// …

const window = createWindow();
const webView = createWebView(pageURL, onApplyMessage, () => {
showWindow(window);
});

window.contentView = webView;

_window = window;
};

Bingo! Now our window displays only when the web view has finished loading, avoiding that annoying visual flicker.

Conclusion

Congratulations, you’ve built your first Sketch plugin! ?

If you’d like to install and play around with Mosaic, you can download the complete plugin from GitHub. And before you go, here are a few resources that might be handy during the rest of your journey:

developer.sketchapp.com
The official resource regarding Sketch plugin development. Contains several useful guides, as well as an API reference for the Sketch JavaScript library.
sketchplugins.com
A fantastic and helpful community of Sketch plugin developers. Great for getting all your burning questions answered.
github.com/sketchplugins/plugin-directory
Official, central GitHub repository of Sketch plugins. You can submit your plugins here and share them with the rest of the Sketch community!

Smashing Editorial
(mb, yk, il)

SitePoint Premium New Releases: Modern JavaScript, Kanban + DevTools

Original Source: https://www.sitepoint.com/sitepoint-premium-new-releases-modern-javascript-kanban-devtools/?utm_source=rss

We’re working hard to keep you on the cutting edge of your field with SitePoint Premium. We’ve got plenty of new books to check out in the library — let us introduce you to them.

The Versioning Guide to Modern JavaScript

A guided tour of the breadth of modern JavaScript, including frameworks, state management, GraphQL, Node, Electron, design patterns, tools, testing and a lot more.

➤ Read The Versioning Guide to Modern JavaScript.

Browser Devtool Secrets

Browser development tools have evolved from basic consoles to fully integrated development environments. It’s become possible to alter and inspect any aspect of your web application, but few of us venture beyond the basics. In this guide, we’ll explore the features you may not have considered.

➤ Read Browser Devtool Secrets.

Practical Kanban

This book will give you practical answers to these questions: Are we using Kanban properly? How can we improve our Kanban? How can we scale our Kanban? How can our work become more predictable? How can we prioritize?

➤ Read Practical Kanban.

And More to Come…

We’re releasing new content on SitePoint Premium almost every day, so we’ll be back next week with the latest updates. And don’t forget: if you haven’t checked out our offering yet, take our library for a spin.

The post SitePoint Premium New Releases: Modern JavaScript, Kanban + DevTools appeared first on SitePoint.

How to Streamline Web Development Workflow with Yeoman

Original Source: https://www.hongkiat.com/blog/yeoman-getting-started/

There are many tools for building web-apps yet putting them all together and making them fit in our workflow could be real cumbersome. We also tend to do repetitive tasks when building web apps such…

Visit hongkiat.com for full content.

3 Design Strategies That Won’t Work in the Next 3 Years

Original Source: http://feedproxy.google.com/~r/Designrfix/~3/CZwWZWHr0II/3-design-strategies-that-wont-work-in-the-next-3-years

Web design strategies change continuously. The attraction of the older strategies fades away and the traction of newer strategies of web designing increases. The web development industry continuously adapts to changes in strategies to create a better user experience and raise the bar for businesses to come. The fast changes in strategies pose different types […]

The post 3 Design Strategies That Won’t Work in the Next 3 Years appeared first on designrfix.com.