<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sam Smith</title>
    <description>The latest articles on DEV Community by Sam Smith (@smth).</description>
    <link>https://dev.to/smth</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F216526%2Fadf26c2b-ce83-44e6-bdea-09bf772f4e29.png</url>
      <title>DEV Community: Sam Smith</title>
      <link>https://dev.to/smth</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/smth"/>
    <language>en</language>
    <item>
      <title>A modern front-end workflow for Wordpress</title>
      <dc:creator>Sam Smith</dc:creator>
      <pubDate>Wed, 05 Feb 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/smth/a-modern-front-end-workflow-for-wordpress-55d9</link>
      <guid>https://dev.to/smth/a-modern-front-end-workflow-for-wordpress-55d9</guid>
      <description>&lt;p&gt;For all intents and purposes, this is a first look at the Wordpress starter theme &lt;a href="https://roots.io/sage/"&gt;Sage&lt;/a&gt;. I think I did, a long time ago, try an earlier incarnation of this theme, when it was called Roots, but I can't remember much about it (I must be going back the best part of a decade here). &lt;a href="https://roots.io/"&gt;Roots&lt;/a&gt; is now a suit of Wordpress development tools, one of which being the starter theme, now known as Sage. Shortly after trying the original Roots, I for whatever reason switched to &lt;a href="https://underscores.me/"&gt;Underscores&lt;/a&gt;, which I continued to use as a starter theme for many years. Underscores has served me well, and I've not really had any major gripes with it; but when something recently drew my attention to Sage it made me (re)consider what I / Underscores was potentially missing. In short the missing pieces are a bunch of developer experience stuff, that we've become used to, especially working with other stacks. Specifically that means a templating engine, and a configured build script with concatenation, minification and live reloading. If these are things you tend to add to your Wordpress workflow, or like me, you'd quite like to have but not sure it's worth the setup time, then read on.&lt;/p&gt;

&lt;p&gt;With my interest piqued I needed something Wordpressy to build. I decided to make a little shop; then set about designing a couple of pages, to give myself something to work towards.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PwvUOb1X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://smth.uk/img/hc-home.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PwvUOb1X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://smth.uk/img/hc-home.jpg" alt="Web page showing mug for sale. It is branded Hate Capitalism"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to skip to the end result, it can be found at &lt;a href="https://hatecapitalism.com/"&gt;hatecapitalism.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Setting up your project is pretty straight forward. Recently I've been using &lt;a href="https://localbyflywheel.com/"&gt;Local by Flywheel&lt;/a&gt; as my local Wordpress environment, and I continued to do so here. New Sage projects are created with &lt;a href="https://getcomposer.org/"&gt;Composer&lt;/a&gt; (which I ran outside of Local).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# wp-content/themes/$ composer create-project roots/sage my-theme-name
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;During the setup you can choose to include one of a selection of CSS frameworks, but I opted for a blank slate. In your new project you run &lt;code&gt;yarn&lt;/code&gt; to install dependancies, then when you've got got things configured &lt;code&gt;yarn start&lt;/code&gt; to run the development server. When running the dev server, you'll want to switch the to the BrowserSync address (localhost:3000 by default), not only because this is where the live reloading happens, but once run, your updated assets do not exist in their build location. To build your assets, so they are available at my-new-site.local you need to run &lt;code&gt;yarn build&lt;/code&gt;. When you're ready to go live &lt;code&gt;yarn build:production&lt;/code&gt;. I suggest reading the &lt;a href="https://roots.io/sage/docs/"&gt;docs&lt;/a&gt; before getting started. I found them to be pretty good, if maybe a little thin, given how much there is to cover. The &lt;a href="https://discourse.roots.io/"&gt;forum&lt;/a&gt; does a good job of bolstering the docs, should you be left wanting.&lt;/p&gt;

&lt;p&gt;Once up and running I had a couple of little niggles with dependancies being out of date. I quickly found that I couldn't disable the Webpack specific Browsersync (in browser) notifications. There wasn't much recourse for this as the &lt;a href="https://github.com/qwp6t/browsersync-webpack-plugin"&gt;plugin being used&lt;/a&gt; is no longer maintained. If this is the only problem that this plugin causes, then it's not too big of a deal (I can hide the notifications with CSS, I guess), but a bit of a concern. Less of a concern was Stylelint flagging stuff that it shouldn't be, like the &lt;code&gt;system-ui&lt;/code&gt; font-family keyword. Updating Stylelint resolved that problem.&lt;/p&gt;

&lt;p&gt;On to the good stuff - as I thought would be the case, having a templating language in place was nice. I've never used a templating language in Wordpress before, frankly because I've never really felt the need enough to warrant looking into it. Sage uses &lt;a href="https://laravel.com/docs/5.8/blade"&gt;Laravel's Blade templates&lt;/a&gt; out of the box, so you get templating for free. The main benefit of using a templating language, such as Blade, is the ability to define, inherit and extend layouts. Many of us are used to working in this way, via various templating languages, in other environments, whether that be Liquid templates in Jekyll or Jinja templates in a Python project. A secondary advantage is less opening and closing of &lt;code&gt;PHP&lt;/code&gt; tags in your templates, specifically when echoing variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h1&amp;gt;Hello &amp;lt;?php echo $name; ?&amp;gt;.&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;becomes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h1&amp;gt;Hello {{ $name }}.&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Blade also gives you "shortcuts" for common PHP control structures; for example you can put if statements and loops right in your templates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@if($products) &amp;lt;ul&amp;gt; @foreach($products as $i=&amp;gt;$product) &amp;lt;li&amp;gt;{{ $product-&amp;gt;name }}&amp;lt;/li&amp;gt; @endforeach &amp;lt;/ul&amp;gt;@endif
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When you need to, breaking into regular PHP is easy; you just wrap it like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@php //php here@endphp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I found myself doing this out of habit - I wrote a little switch statement (to handle the words that come before the price on the home page) before realising that Blade has its own syntax for this. If you're going to put such things in your templates though, I don't think using one syntax over the other will make a huge difference to the cleanliness of those templates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@php switch ($i) { case 1: First case... break; case 2: Second case... break; default: Default case... break; }@endphp

@switch($i) @case(1) First case... @break @case(2) Second case... @break @default Default case...@endswitch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When it came to writing styles I felt at home working with CSS in Sage. First of all, this is probably the point when you appreciate that Sage has BrowserSync ready to go, out of the box. In addition to that, Sass and PostCSS are wired up in a Webpack configuration. If I were constructing this build process from scratch I would probably forgo Sass in favour of PostCSS plugins, and opt for something less gnarly than Webpack, but I think the choices here are reasonable, and given that they are configured for us, I'm perfectly happy to use them.&lt;/p&gt;

&lt;p&gt;The Sage build process really started to shine when it came to adding Javascript. Sage provides DOM-based routing, giving you an easy way to specify which scripts run on what pages. For example, if I wanted the Javascript for the slider on my homepage to only run the homepage, that can be achieved pretty much just by putting it in a file named &lt;code&gt;home.js&lt;/code&gt; (the is based on body classes, of which &lt;code&gt;home&lt;/code&gt; is one). Global Javascript, such as the slide-out navigation for example, lives in &lt;code&gt;common.js&lt;/code&gt;. From a developer experience point of view, I found this to be a really nice answer to the question of what to do with page specific Javascript. From a user experience point of view, the appropriateness of this technique will vary with each project. You will need to consider whether putting all the Javascript in a single file the best approach.&lt;/p&gt;

&lt;p&gt;Ironically, given that this was an exercise in exploring a Wordpress starter theme, I felt like I didn't spend much time engaging with Wordpress while working on this little &lt;a href="https://hatecapitalism.com/"&gt;project&lt;/a&gt;. That is perhaps the biggest compliment I could give Sage, it puts a layer of modern tooling between you and Wordpress. I still had the odd Wordpress moment, like writing a PHP function in order to change the contents of the &lt;code&gt;title&lt;/code&gt; tag, but for the most part I felt free to focus on the sort of front-end stuff that I wanted to be focusing on. That was a breath of fresh air.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>wordpress</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Use design tokens to customise Bootstrap</title>
      <dc:creator>Sam Smith</dc:creator>
      <pubDate>Sun, 12 Jan 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/smth/use-design-tokens-to-customise-bootstrap-30kh</link>
      <guid>https://dev.to/smth/use-design-tokens-to-customise-bootstrap-30kh</guid>
      <description>&lt;p&gt;If you are creating a customised version of Bootstrap, and especially if you intend to use it for more than one website / app, I think design tokens can make for a nice authoring experience, as well as bring a bit of future-proofing along for free. This is the approach I took with a recent project; if you just want to see what I did, skip down to .. What I did. First, a little about how I arrived at this method.&lt;/p&gt;

&lt;p&gt;I was working on a project which involved updating the visual identity of two websites, which share that visual identity. The two codebases were pretty disparate, though they were both built on Bootstrap. A benefit of using a framework such as Bootstrap is that you can create a custom version then not only use it to build one site, but reuse it to build other sites with the same visual identity.&lt;/p&gt;

&lt;p&gt;There are various approaches to sharing a customised Bootstrap between sites. The worst case scenario (which was the case here) is that you rely on those maintaining the sites to make sure that they are visually consistent. Achievable but inefficient. Another approach I've seen is to compile your bespoke Bootstrap then share that code between sites, probably via a CDN. There is value in the CDN here, but more often than not I think this will lead to you having to override your shared Bootstrap styles with site specific ones. This is where frameworks start creating more problems than they solve, in my opinion - causing bloated and overly complicated code. An approach I have favoured in the past is to just maintain a version of the Bootstrap SCSS variables file which can be included into each site's main SCSS file, along with a freshly NPM installed Bootstrap. This is a clean, simple, and flexible approach, but there is room for improvement. If you have taken this approach, you have potentially created a single source of truth for the brand's styles. Nice. The problem is that this single source of truth is heavily tied into Bootstrap. Even if you have taken the time make your &lt;code&gt;variables.scss&lt;/code&gt; more versatile with additional, less bootstrapy variables; you are still tied into SCSS at this point. The danger here is that if/when you build something without SASS, not only is your single source of truth going to be of limited use, you are probably going to stop caring about maintaining it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design tokens
&lt;/h2&gt;

&lt;p&gt;This is where design tokens come in. Design tokens simply offer an agnostic way to store variables. That is to say, those variables can in theory be used in any project, regardless languages involved. A clear use-case for design tokens is to share variables (or tokens) between a web project and a native mobile project. It might sound like over-engineering to use design tokens just to generate Bootstrap variables, but the additional setup is small, and to me the workflow felt good.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did
&lt;/h2&gt;

&lt;p&gt;I used &lt;a href="https://amzn.github.io/style-dictionary"&gt;Style Dictionary&lt;/a&gt; to transform my tokens into SASS variables. I created a new &lt;code&gt;package.json&lt;/code&gt; (&lt;code&gt;npm init&lt;/code&gt;) for my design tokens project, and added Style Dictionary as a dev dependancy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -D style-dictionary
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Style Dictionary has a &lt;a href="https://amzn.github.io/style-dictionary/#/quick_start?id=creating-a-new-project"&gt;command to create a starter project&lt;/a&gt;, which you might find useful. Here though I will detail the project structure I used for this particular use-case. The first thing you need in your project is a &lt;code&gt;config.json&lt;/code&gt;. In this file you tell Style Dictionary what exactly you want outputted (and to where). Here's what you need for our purposes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "source": ["properties/**/*.json"], "platforms": { "scss": { "transformGroup": "scss", "buildPath": "build/scss/", "files": [{ "destination": "_variables.scss", "format": "scss/variables" }] } }}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This tells Style Dictionary to look in the &lt;code&gt;properties&lt;/code&gt; folder (which we haven't made yet), convert the properties there to SCSS variables, in a file named &lt;code&gt;_variables.scss&lt;/code&gt;, at the path &lt;code&gt;build/scss&lt;/code&gt;. Tweak this as you please.&lt;/p&gt;

&lt;p&gt;Now for those properties. My preference here was to first create non-Bootstrap specific variables, then reference these in my Bootstrap variables. I like having a versatile and consistently named collection of variables (not limited by the constraints of Bootstrap), to use for any additional styles that need to be written. Style Dictionary comes with a suggestion about about how you structure your properties, and thus, what your variables will be named. You do not need to follow this suggestion, but doing so gives you access to some helpers. For example you can convert colour values from one format to another. I found the suggested structure to be sensible, and pretty close to what I would have naturally adopted for my non-Bootstrap variables. So I ran with it, without looking too much into the perks. The suggested property structure is &lt;code&gt;Category / Type / Item&lt;/code&gt;. A SASS variable following this structure would look like &lt;code&gt;$size-font-small&lt;/code&gt;, or &lt;code&gt;$color-blue-base&lt;/code&gt;. &lt;code&gt;size&lt;/code&gt; and &lt;code&gt;color&lt;/code&gt; being the &lt;em&gt;categories&lt;/em&gt;, &lt;code&gt;font&lt;/code&gt; and &lt;code&gt;blue&lt;/code&gt; being &lt;em&gt;types&lt;/em&gt;, and &lt;code&gt;small&lt;/code&gt; and &lt;code&gt;base&lt;/code&gt; being &lt;em&gt;items&lt;/em&gt;. If this is confusing or throws up questions, I suggest you either check out the &lt;a href="https://amzn.github.io/style-dictionary/#/properties?id=category-type-item"&gt;docs&lt;/a&gt;, or just put it to the back of your mind. You don't really need to understand this structure to get going; I think it's worth mentioning though, so you know how I decided to structure my properties. With that said, let's create those properties. My &lt;code&gt;properties&lt;/code&gt; folder looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|-- bootstrap
| |-- color.json
| |-- headings.json
| |-- link.json
|-- size
| |-- font.json
| |-- spacing.json
|-- color.json
|-- font.json

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The properties are stored in multiple files, and split into subdirectories for ease of maintenance (this is another reason why I like this design token approach). I don't believe there is any reason you couldn't store all your properties in a single JSON file, if you wanted to. Each JSON file follows the same format. Let's look at &lt;code&gt;color.json&lt;/code&gt; as an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "color": { "gray": { "100": { "value": "#F6F6F6" }, "500": { "value": "#939598" }, "900": { "value": "#231f20" } }, "blue": { "base": { "value": "#00D1FF" } }, "text": { "base": { "value": "{color.gray.900.value}" }, "decoration": { "value": "{color.blue.base.value}" } } }}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Any object in the JSON that has a &lt;code&gt;value&lt;/code&gt; attribute is a &lt;em&gt;property&lt;/em&gt;. So &lt;code&gt;color.gray.100&lt;/code&gt; is a property, as is &lt;code&gt;color.blue.base&lt;/code&gt;. In terms of SASS variables, these will output as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$color-gray-100: #f6f6f6;$color-blue-base: #00d1ff;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can see in the above example that you can reference other properties; so &lt;code&gt;$color-text-base&lt;/code&gt; will have the same value as &lt;code&gt;$color-gray-900&lt;/code&gt;. The &lt;code&gt;size&lt;/code&gt; directory can be thought of as a &lt;code&gt;size.json&lt;/code&gt; file split into two smaller files. Both the JSON files within that directory have &lt;code&gt;size&lt;/code&gt; as the top level object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "size": { "font": { "sm": { "value": "0.875" }, "base": { "value": "1" }, "lg": { "value": "1.125" } } }}

{ "size": { "spacing": { "sm": { "value": "0.5" }, "base": { "value": "1" }, "lg": { "value": "1.5" } } }}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that these &lt;code&gt;size&lt;/code&gt; properties do not include units (px, rem etc). Because I am using the &lt;code&gt;size&lt;/code&gt; category, units get added by Style Dictionary. For SCSS, the default is &lt;code&gt;rem&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For my Bootstrap properties, I stopped thinking about the &lt;code&gt;Category / Type / Item&lt;/code&gt; structure and focused on generating the required variable names (I found &lt;a href="https://bootstrapvars.com/"&gt;bootstrapvars.com&lt;/a&gt; to be a useful reference here). You can organise these properties how you like, I mostly named the JSON files after the first word in the variable name. For example &lt;code&gt;headings.json&lt;/code&gt; could contain properties for &lt;code&gt;$headings-font-family&lt;/code&gt;, &lt;code&gt;$headings-font-weight&lt;/code&gt;, &lt;code&gt;$headings-line-height&lt;/code&gt; etc. Because I had already created a comprehensive set of variables, no new values were included in these Bootstrap properties - they were all aliases of existing properties. This may not be the case for you, and if you are only interested in creating Bootstrap specific variables, you could skip straight to this part and include actual values here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "headings": { "font": { "family": { "value": "{font.family.base.value}", "comment": "Bootstrap" }, "weight": { "value": "{font.weight.black.value}", "comment": "Bootstrap" } } }}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I used Style Dictionary's comment feature to add a comment to each Bootstrap property, so it could be recognised as such in the outputted &lt;code&gt;_variables.scss&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Once you have your properties defined, you can generate your SCSS file with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx style-dictionary build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That will generate the file at the path specified in your config. That file is now ready to be included in your Bootstrap builds. There are a few ways you could get it into your project. I included the whole design tokens repo as a Git subtree, so I could continue to build the variables from within the Bootstrap project, and push the changes back. I had my task runner watch the design tokens directory, and run the build command from there.&lt;/p&gt;

&lt;p&gt;What is primarily achieved by following this method is the ability to easily build your variables into a different format, CSS custom properties for example. Even without taking advantage of that though, I found the structure described above, and the JSON format made for a nice way to structure and keep track of the large number of variables that a customised Bootstrap tends to require.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>css</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Top static site generators of 2019</title>
      <dc:creator>Sam Smith</dc:creator>
      <pubDate>Fri, 20 Dec 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/smth/top-static-site-generators-of-2019-3b5k</link>
      <guid>https://dev.to/smth/top-static-site-generators-of-2019-3b5k</guid>
      <description>&lt;p&gt;OK, this is not going to be an all encompassing, objective review of available static site generators (SSGs). In this article I will talk about what SSGs I have been enjoying this year, and why.&lt;/p&gt;

&lt;p&gt;Recently someone commented that I seem to use a different static site generator (SSG) for every project. This prompted a conversation about the pros and cons of sticking with a familiar stack VS trying something new. I explained my position - for projects that are time sensitive (most projects) I prefer to use technologies that are familiar and predictable to me. However, for projects where I have more freedom, i.e personal projects, I like to try new things. And yes, I have a bit of a thing for SSGs. It's only through trying new things that you can find and familiarise yourself with those killer solutions, that you'll come to rely on later. I think SSGs are a great example of this. There are lots of products that we call static site generators, and they differ greatly. I like to keep my hand in with a few, so I know what to reach for when I don't have the luxury of time to experiment.&lt;/p&gt;

&lt;p&gt;I wrote a &lt;a href="https://smth.uk/welcome-to-jekyll/"&gt;similar post&lt;/a&gt; to this back in early 2016; I thought an interesting way to frame this today might be to look at how the landscape and my preferences have changed since then. One of the points I made in that 2016 post was that I hadn't found a non-developer friendly way to manage content for static sites. Maybe I wasn't looking in the right places, but it feels like this is an area that has really improved since then. Headless CMSs are very much part of the &lt;a href="https://cdn-images-1.medium.com/max/1200/1*R65rmc0x432_s9EmAbGlOA.png"&gt;JAMstack landscape&lt;/a&gt;, of which SSGs are now almost synonymous. This brings me to my first SSG mention:&lt;/p&gt;

&lt;h2&gt;
  
  
  Gridsome
&lt;/h2&gt;

&lt;p&gt;Getting your data from an external source (such as a headless CMS) can be a little fiddly. Some SSGs are more focused on making this easier than others. I don't have a huge amount of experience with &lt;a href="https://gridsome.org/"&gt;Gridsome&lt;/a&gt;, but enough to know that CMSs feel like first-class citizens here. It's early days, but the &lt;a href="https://gridsome.org/starters/"&gt;&lt;em&gt;Starters&lt;/em&gt; page&lt;/a&gt; at least sets out a direction for ready-made integrations with a really good selection of content / data sources. To try this out, I recreated a &lt;a href="https://gigs.smth.uk/"&gt;simple site&lt;/a&gt; I had previously made with &lt;a href="https://nuxtjs.org/"&gt;Nuxt&lt;/a&gt;. Like Nuxt, Gridsome is &lt;a href="https://vuejs.org/"&gt;Vue.js&lt;/a&gt; based, which made this migration quick and easy. It's worth mentioning that the two versions are different in that the Nuxt version was server side rendered, while Gridsome creates pre-rendered HTML. That said, the code required to fetch and query the data felt much simpler with Gridsome, thanks to the CMS specific plugin, and the leveraging of GraphQL. If you're into JavaScript frameworks, and in particular Vue, this is a SSG to keep an eye on.&lt;/p&gt;

&lt;p&gt;While I wasn't strictly integrating CMSs with static sites in 2016, I was pulling data from APIs. This is a staple of JAMstack today, but just a few years ago the ability to pre-render HTML from remote APIs didn't feel like a common SSG feature. In fact, one of the SSGs I mentioned in the 2016 post, I chose purely for this feature. That SSG was &lt;em&gt;Roots&lt;/em&gt;, which is no longer under active development. At the time I used it to build my &lt;a href="https://samsmith.name/"&gt;portfolio site&lt;/a&gt;. Today I use my next SSG mention:&lt;/p&gt;

&lt;h2&gt;
  
  
  Hugo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;, much like many modern SSGs offers the ability to work with remote data. It does so via its &lt;code&gt;getJSON&lt;/code&gt; and &lt;code&gt;getCSV&lt;/code&gt; functions. What perhaps sets Hugo apart from other SSGs is that this, and other common features are ready to use, out of the box. So whether you want taxonomies, shortcodes, word count, theming - these things are all ready to go in your freshly created Hugo site. For a lot of use cases, you only need to concern yourself with templating. About those templates though, Hugo uses Go's templating language, so unless you are familiar with Go, templating logic will take a bit of getting used to. I didn't find this to be too much of a pain, I do however think the templating in Hugo is the thing most likely to put me off reaching for it. Not so much because you need to work with the ways of Go, but because I've found myself tending to put a lot of logic and variables in these templates at times, which while gets the job done, leads to messy and complicated templates. If I'm going to pinpoint what is most likely to put me off using Hugo, I should say what is most attractive about it. Besides being feature rich and capable, I think the community might be the biggest attraction. The Hugo website has a dedicated and active forum, where in my experience, your questions will be answered. I much prefer the forum format over something like a Discord or Gitter, which seem to be popular with other projects.&lt;/p&gt;

&lt;p&gt;In 2016 I mentioned two other SSGs, Jekyll, which was powering my &lt;a href="https://smth.uk/"&gt;blog&lt;/a&gt; at the time, and Middleman, which I identified as my go-to SSG. These two have in common their dependancy on Ruby. This commonality is a significant factor in why I no longer use them. After using Jekyll for many years, a macOS update broke Jekyll on my machine. I was only maintaining one Jekyll site (my blog) by this time, so after spending a significant amount of time troubleshooting I decided it would be quicker to just rebuild my blog with a different SSG. I don't imagine this extreme scenario is common, but I think some consideration should be given to whether you want to setup / maintain a Ruby development environment, just for static sites. This is probably in part why out of the top ten SSGs on &lt;a href="https://www.staticgen.com/"&gt;staticgen.com&lt;/a&gt; eight are written in JavaScript. As it turns out, since moving away from Jekyll I haven't looked back. The SSG that now powers my blog, has become my new go-to SSG (so I guess its a sort of winner). That SSG is:&lt;/p&gt;

&lt;h2&gt;
  
  
  Eleventy
&lt;/h2&gt;

&lt;p&gt;Coming back to my point about trying new things - finding an excuse to try &lt;a href="https://www.11ty.dev/"&gt;Eleventy&lt;/a&gt; was really worthwhile. Not only did I find it to be a good drop-in replacement for Jekyll, but having made a few sites with it I found it to be very versatile. Versatility runs right through Elevently. If you are making something simple, it can get out of the way, with zero configuration; making something more complex, it can be very powerful. The options available for working with data I've found to be particularly powerful. JavaScript data files mean you can prepare your data in any way that JavaScript allows, and make it available to your templates. The versatility extends to the templating language too, you can configure Eleventy to use the languages you want. No more putting up with what the SSG dictates. What I think Eleventy generally does really well is allow you to bend and shape it to your needs. It doesn't really presuppose anything about your code. I would say this is less true of other SSGs, to varying degrees. Something like Gridsome is dictating a lot, you are definitely building a Vue app in that case. Hugo on the other hand doesn't necessarily dictate the code that reaches the browser, but your templates will probably be less concise, as you jump though Hugos hoops. If you don't mind doing your own wiring, and you value elegance and simplicity, then Eleventy should be on your shortlist of SSGs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honorable mention
&lt;/h2&gt;

&lt;p&gt;A lot has changed in SSG land in a past few years, including my preferred tools. I was wondering if there are any SSGs I was using in 2016 that I would still use today. I could think of one: &lt;a href="https://www.getlektor.com/"&gt;Lektor&lt;/a&gt;. I don't think Lektor has changed much over those years, and it feels kind of pre JAMstack. That said, the value it had to me in 2016 it still has now. Lektor is a static content management system, it only deals with flat-file data. What makes Lektor interesting is while most SSGs tend to be centred around Markdown files with metadata, Lektor has its own file format which allows any number of fields. It's like the difference between Wordpress with and without &lt;a href="https://www.advancedcustomfields.com/"&gt;Advanced Custom Fields&lt;/a&gt;. You even get an admin GUI to edit the content once the fields are configured. I find the idea of a very simple setup for a site where pages can be configured to have any combination of fields to be quite liberating; I can see myself using Lektor again in the future.&lt;/p&gt;

</description>
      <category>html</category>
      <category>javascript</category>
      <category>jamstack</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building a swipeable card stack with interact.js and Svelte</title>
      <dc:creator>Sam Smith</dc:creator>
      <pubDate>Mon, 07 Oct 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/smth/building-a-swipeable-card-stack-with-interact-js-and-svelte-47pg</link>
      <guid>https://dev.to/smth/building-a-swipeable-card-stack-with-interact-js-and-svelte-47pg</guid>
      <description>&lt;p&gt;I've been waiting for an opportunity to dip my toe into some &lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt; for a while. Faced with a little free time, I decided to create that opportunity. For anyone who hasn't heard of Svelte, it is a JavaScript / component framework, along the lines of React and Vue, but with an added compile step at build time. So what did I decide to use it for? Inspired by &lt;a href="https://css-tricks.com/swipeable-card-stack-using-vue-js-and-interact-js/"&gt;this post by Mateusz Rybczonek&lt;/a&gt;, I set myself the challenge of building a swipeable card stack interface. You can see the result &lt;a href="https://36q.app/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this article I will explain the steps I took in building the above interface, and detail some of the approaches I took.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Sapper
&lt;/h2&gt;

&lt;p&gt;I really like static site generators (SSG), and will usually reach for one if a project has static content (such as this one). Fortunately there is a Svelte based SSG; its called &lt;a href="https://sapper.svelte.dev/"&gt;Sapper&lt;/a&gt;. The &lt;a href="https://github.com/sveltejs/sapper-template"&gt;Sapper template&lt;/a&gt; makes a pretty good starting point for a project like this, and comes in Rollup and Webpack variants. I went for Rollup, getting up and running like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx degit &lt;span class="s2"&gt;"sveltejs/sapper-template#rollup"&lt;/span&gt; my-app
&lt;span class="nb"&gt;cd &lt;/span&gt;my-app
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There were a few things in this template that I didn't need, which were either deleted or repurposed. The &lt;code&gt;about&lt;/code&gt; and &lt;code&gt;blog&lt;/code&gt; routes were removed, but not before repurposing &lt;code&gt;blog/_posts.js&lt;/code&gt;, &lt;code&gt;blog/index.json.js&lt;/code&gt; and &lt;code&gt;blog/index.svelte&lt;/code&gt; to deliver the content for my app.&lt;/p&gt;

&lt;p&gt;I used the include &lt;code&gt;Nav&lt;/code&gt; component as a guide to creating my first Svelte component, the only component in this app. I'll get back to that in a moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: (optional) PostCSS
&lt;/h2&gt;

&lt;p&gt;I like processing my styles with &lt;a href="https://postcss.org/"&gt;PostCSS&lt;/a&gt;, I tend to use &lt;a href="https://preset-env.cssdb.org/"&gt;preset-env&lt;/a&gt; to enable nesting and autoprefixing. I used &lt;a href="https://github.com/langbamit/sapper-postcss-tailwind-rollup/commit/9d436a85530fca654882c8f9ece8ace7778aa22b"&gt;this Tailwind template&lt;/a&gt; as a guide to set this up with Sapper. Installing the required/desired packages, editing the Rollup config, and importing the CSS file into &lt;code&gt;server.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; postcss postcss-import rollup-plugin-postcss svelte-preprocess postcss-preset-env cssnano
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// rollup.config.js&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;getPreprocessor&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svelte-preprocess&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;postcss&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rollup-plugin-postcss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postcssPlugins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;postcss-import&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)(),&lt;/span&gt;
    &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;postcss-preset-env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)({&lt;/span&gt;
    &lt;span class="na"&gt;features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nesting-rules&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cssnano&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)()&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;preprocess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getPreprocessor&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;transformers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;postcss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;postcssPlugins&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// ...&lt;/span&gt;
        &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="nx"&gt;postcss&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
            &lt;span class="nx"&gt;svelte&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="c1"&gt;// ...&lt;/span&gt;
                &lt;span class="nx"&gt;preprocess&lt;/span&gt;
            &lt;span class="p"&gt;}),&lt;/span&gt;
            &lt;span class="c1"&gt;// ...&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
        &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="c1"&gt;// ...&lt;/span&gt;
      &lt;span class="nx"&gt;postcss&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;postcssPlugins&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./static/global.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Add styles to &lt;code&gt;src/css/main.css&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/server.js&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./css/main.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Its worth noting that using this particular approach means you won't be taking advantage of Sapper's code splitting when it comes to CSS, but given that this would be a single page app, I didn't see that as being an issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Creating the Card component
&lt;/h2&gt;

&lt;p&gt;There will be multiple cards in this interface, so it makes sense to create a component for them. This simply needs to be a template with some props, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- components/Card.svelte --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;isCurrent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cardContent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt; &lt;span class="na"&gt;data-dragging=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="na"&gt;data-status=&lt;/span&gt;&lt;span class="s"&gt;"{isCurrent === true ? 'current' : 'waiting'}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card_content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{cardContent}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've given the card a class so it can be styled as such, plus a couple of data attributes to hold some contextual information that will become useful later. All three attributes could be handled with classes, but I like to use a different syntax for contextual stuff to &lt;a href="https://c3css.com/"&gt;make my CSS easier to read&lt;/a&gt;. You might also think that the JavaScript to handle the dragging etc should live in this file. When I tried this I found that the script would run for each instance of the component (which is not what I wanted). There's probably a way of making it behave as I wanted, but as I had a layout template not really being used for much, I decided to put all the logic there.&lt;/p&gt;

&lt;p&gt;If you were writing your CSS inside the component, it would live in a &lt;code&gt;style&lt;/code&gt; tag within this file. My CSS lives in a good old CSS file. Its pretty simple so I won't go over it here. Essentially I have a fixed size &lt;code&gt;card&lt;/code&gt; component, absolutely positioned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Putting your cards on the table
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;index.svelte&lt;/code&gt; I add instances of the &lt;code&gt;Card&lt;/code&gt; component to the page. As mentioned earlier, I made use of the blog code to store the content of each card in an array, which I then iterated over like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{#each cards as card, i}
    &lt;span class="nt"&gt;&amp;lt;Card&lt;/span&gt; &lt;span class="na"&gt;cardContent=&lt;/span&gt;&lt;span class="s"&gt;{card.content}&lt;/span&gt; &lt;span class="na"&gt;isCurrent=&lt;/span&gt;&lt;span class="s"&gt;{i&lt;/span&gt; &lt;span class="err"&gt;===&lt;/span&gt; &lt;span class="err"&gt;0}&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
{/each}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting &lt;code&gt;isCurrent&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; for the first item in the array. For simplicity you might just want to put the cards directly into this page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Card&lt;/span&gt; &lt;span class="na"&gt;cardContent=&lt;/span&gt;&lt;span class="s"&gt;{"One"}&lt;/span&gt; &lt;span class="na"&gt;isCurrent=&lt;/span&gt;&lt;span class="s"&gt;{true}/&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Card&lt;/span&gt; &lt;span class="na"&gt;cardContent=&lt;/span&gt;&lt;span class="s"&gt;{"Two"}&lt;/span&gt; &lt;span class="na"&gt;isCurrent=&lt;/span&gt;&lt;span class="s"&gt;{false}/&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Card&lt;/span&gt; &lt;span class="na"&gt;cardContent=&lt;/span&gt;&lt;span class="s"&gt;{"Three"}&lt;/span&gt; &lt;span class="na"&gt;isCurrent=&lt;/span&gt;&lt;span class="s"&gt;{false}/&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In either case, you also need to import the component into the page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Card&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/Card.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Draggable cards
&lt;/h2&gt;

&lt;p&gt;Now for the fun stuff, the interactivity. I put all the interactivity logic in my &lt;code&gt;_layout.svelte&lt;/code&gt; file, which until this point was pretty much empty. The dragging relies on &lt;a href="https://interactjs.io/"&gt;interact.js&lt;/a&gt; which we need to add to our project before importing into our template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; interactjs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The basis for the below code is the dragging example given on the interact.js website. The alterations and additions I will outline here. First thing to note is in Svelte anything that relies on the DOM being ready goes inside an &lt;code&gt;onMount&lt;/code&gt; function. To use this function, we first need to &lt;code&gt;import { onMount } from 'svelte'&lt;/code&gt;. I took the concept of "interact threshold" and how that relates to rotation from Mateusz Rybczonek's article. &lt;code&gt;interactThreshold&lt;/code&gt; represents how far a card needs to be dragged before it is considered dismissed. The interact.js example stores the draggable objects position in data attributes, and adds inline styles to transform its position. Preferring to keep the styles in the style sheet, I used CSS custom properties to store these variables, which are referenced in the CSS. To access the custom properties in the JavaScript, I used &lt;a href="https://hankchizljaw.com/wrote/get-css-custom-property-value-with-javascript/#heading-the-getcsscustomprop-function"&gt;Andy Bell's &lt;code&gt;getCSSCustomProp&lt;/code&gt; function&lt;/a&gt;. Finally, inside the &lt;code&gt;onend&lt;/code&gt; function, we check whether the card has moved a sufficient amount to dismiss. If so we remove its &lt;code&gt;current&lt;/code&gt; status and give it to the next card. We also move it off the screen to the left or right, depending on whether its &lt;code&gt;x&lt;/code&gt; coordinate is positive or negative. If the card has not moved a sufficient amount, we reset its position and rotation custom properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;context=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;interact&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;interactjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;onMount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;interactThreshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;interactMaxRotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// https://hankchizljaw.com/wrote/get-css-custom-property-value-with-javascript/#heading-the-getcsscustomprop-function&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getCSSCustomProp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;propKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;castAs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getComputedStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;getPropertyValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;propKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Tidy up the string if there's something to work with&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="sr"&gt;|"/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Convert the response into a whatever type we wanted&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;castAs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;int&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;float&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;boolean&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bool&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Return the string response by default&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;dragMoveListener&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;

        &lt;span class="c1"&gt;// keep the dragged position in the custom properties&lt;/span&gt;
        &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getCSSCustomProp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--card-x&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;float&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dx&lt;/span&gt;
        &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getCSSCustomProp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--card-y&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;float&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dy&lt;/span&gt;

        &lt;span class="c1"&gt;// add rotation based on card position&lt;/span&gt;
        &lt;span class="nx"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;interactMaxRotation&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;interactThreshold&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;interactMaxRotation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;interactMaxRotation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;interactMaxRotation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;interactMaxRotation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// update styles&lt;/span&gt;
        &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--card-x&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--card-y&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--card-r&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;deg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;onMount&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// get viewport width&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientWidth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// create an off canvas x coordinate&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;offX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vw&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;offX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// interact.js&lt;/span&gt;
        &lt;span class="nx"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.card[data-status="current"]:not(:last-child)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;draggable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;

            &lt;span class="na"&gt;onstart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// signify dragging&lt;/span&gt;
                &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-dragging&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;

            &lt;span class="c1"&gt;// call this function on every dragmove event&lt;/span&gt;
            &lt;span class="na"&gt;onmove&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dragMoveListener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

            &lt;span class="c1"&gt;// call this function on every dragend event&lt;/span&gt;
            &lt;span class="na"&gt;onend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// signify dragging stopped&lt;/span&gt;
                &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-dragging&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="c1"&gt;// calculate how far card moved&lt;/span&gt;
                &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;moved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageY&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moved&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;interactThreshold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// remove card&lt;/span&gt;
                    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;done&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;offX&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offX&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="c1"&gt;// activate next card&lt;/span&gt;
                    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextElementSibling&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;current&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// reset vars&lt;/span&gt;
                    &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="nx"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="c1"&gt;// update rotation&lt;/span&gt;
                    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--card-r&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;deg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="c1"&gt;// update x and y pos&lt;/span&gt;
                &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--card-x&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--card-y&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a big chunk of code, but pretty self explanatory I hope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Details and finessing
&lt;/h2&gt;

&lt;p&gt;With the functionality in place, there remains some refining to do. For example, you're probably going to want to include some transitions in your CSS, to make the moving and rotations smooth. An important point to consider is that having a transition on the card while it is being dragged will cause problems. That's why we added the &lt;code&gt;data-dragging&lt;/code&gt; attribute that is toggled to true when a card is being dragged. It means you can safely add something like this to your CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-dragging&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"false"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt; &lt;span class="m"&gt;0.5s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also added a small rotation to the next card in the stack, to indicate that there is a card below. There are many ways you could design this though, I'll leave that to you.&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>javascript</category>
      <category>css</category>
      <category>html</category>
    </item>
  </channel>
</rss>
