Converting SVG to an Image via Blob

There are a few important things to keep in mind.

  1. Any CSS will be lost when converting to a Blob.
    • You’ll have to convert all styles to SVG attributes.
  2. SVG resources must be self contained.
    • Fonts will need to be converted to Base64 (this post has a handy tool)
    • Images will need to be converted to Base64

Adding @font-face to an SVG in JSX (React) will look like this:

<defs>
    <style type='text/css'>
      { `@font-face {
          font-family: SharpSansNo2;
          font-weight: 900;
          font-style: normal;
          src: url(data:application/font-woff;charset=utf-8;base64,${SharpSansDisplayNo2});
      }` }
    </style>
  </defs>
</svg>

Here is my JS for converting my SVG to a Blob. Notice that I clone the element before making modifications, such as converting CSS styles to SVG attributes.

const $clonedSvgElement = $svgElement.cloneNode(true) as SVGElement;

// make any tweaks to colors (such as replacing css variables with calculated values)
const $background = $svgElement.querySelector('[data-background]') as SVGGraphicsElement;
const $clonedBackground = $clonedSvgElement.querySelector('[data-background]') as SVGGraphicsElement;
$clonedBackground.setAttribute('fill', getComputedStyle($background).fill);

const $textElements = $svgElement.querySelectorAll('text');
const $clonedTextElements = $clonedSvgElement.querySelectorAll('text');
for (let i = 0; i < $clonedTextElements.length; i++) {
const $textElement = $textElements[i];
const $clonedTextElement = $clonedTextElements[i];
const computedStyles = getComputedStyle($textElement);
const attributes = {
  color: computedStyles.color,
  fill: computedStyles.color,
  'font-family': 'SharpSansNo2',
  'font-size': computedStyles.fontSize,
  'font-weight': computedStyles.fontWeight,
  'letter-spacing': computedStyles.letterSpacing
};
for (const key in attributes) {
  const value = key ? attributes[key] : '';
  if (value) {
    $clonedTextElement.setAttribute(key, value);
  }
}
}

// export current state to HTML
const data = new XMLSerializer().serializeToString($clonedSvgElement);

// generate blob with base64 data of image
const blob = new Blob([data], { type: 'image/svg+xml;charset=utf-8' });
const URL = window.URL || window.webkitURL || window;
const blobURL = URL.createObjectURL(blob);

// generate image with canvas data (to convert to PNG and other formats)
const image = new Image();
document.body.appendChild(image);
const canvas = document.createElement('canvas');
canvas.width = this.currentPoster.width * scale;
canvas.height = this.currentPoster.height * scale;
const context = canvas.getContext('2d');
let png: string;

// wait for image to load
image.onload = () => {
if (context) {
  context.drawImage(image, 0, 0, this.currentPoster.width * scale, this.currentPoster.height * scale);
  png = canvas.toDataURL();

  // trigger download
  const download = function (href, name) {
    const link = document.createElement('a');
    link.download = name;
    link.style.opacity = '0';
    document.body.append(link);
    link.href = href;
    link.click();
    link.remove();
  };
  download(png, 'sddw-poster.png');
}
};
image.src = blobURL;

Next.JS Newbie Lessons

  1. <Link href="/home"> all need to start with a /. If they do not, there will be a local/server synchronization error.
  2. Pay close attention to which arrow functions are strictly returns (which are wrapped in parenthesis) versus those that are not. Examples:

    Arrow function purely as a return:
    {poop.map(({ id }) => ( <>Poop { id }</> );

    Normal arrow function:
    {poop.map(({ id }) => { return <>Poop { id }</>; };

Calculate CSS letter-spacing from Sketch

When calculating from Sketch to CSS, common wisdom to determine em is to divide by 1000. For example, -0.69 in Sketch would become -0.00069em.

This will not be consistently visually accurate. If your font-size is being set in rem, it is better and more consistent to use rem for letter-spacing as well.

In my case, I reset rem to 10 pixels (by setting body font-size to 62.5%), then divide sketch letter-spacing values by 10. For our example above, -0.69 would become -0.069rem.

How to replace git branch with another (and still maintain history)

git checkout new-branch
git merge -s ours old-branch
git checkout old-branch
git merge new-branch

Line 2 says that any changes to old-branch will be replaced with updates in new-branch.

It may seem odd that we switched to new-branch to prepare old-branch, but this establishes the priority for when we ultimately merge old-branch in step 4.

This resolves any number of heads, but the resulting tree of the merge is always that of the current branch head, effectively ignoring all changes from all other branches. It is meant to be used to supersede old development history of side branches. Note that this is different from the -Xours option to the recursive merge strategy.

https://stackoverflow.com/questions/2862590/how-to-replace-master-branch-in-git-entirely-from-another-branch

Connect BitBucket Pipelines to FortRabbit

  1. Generate SSH key in BitBucket.
  2. Add the SSH key to the FortRabbit server via terminal.
    1. ssh your-account@deploy.us1.frbit.co
    2. cd ~/.ssh
    3. vi authorized_keys
    4. Paste the BitBucket SSH key.
    5. Press escape, then type : and wq to write and quit.
  3. In BitBucket, add the deploy.us1.frbit.com FortRabbit url found in SFTP tab as a known host. The fingerprint should be generated automatically.
  4. Create a bitbucket-pipelines.yml file in your project root. The code below is a good starting template.

image: php:7.0.0
pipelines:
branches:
your-project-name:
- step:
deployment: staging
script:
- apt-get update && apt-get install -y unzip git ssh
- git remote add fortrabbit your-project-name@deploy.us1.frbit.com:your-project-name.git
- git push fortrabbit your-project-name -f

  1. Note that your-project name should also match one of your branch names. This branch will be used to deploy. Other branches will still push to BitBucket but won’t be uploaded onto FortRabbit.

Git: Get All Branches (even new remotes)

tldr;

git fetch --all (or git remote update)
git pull --all

Important for projects with multiple remotes:
git checkout -t origin/branch-name

This last piece will prevent a detached-head situation when adding branches that currently only exist on remote.


https://stackoverflow.com/questions/10312521/how-to-fetch-all-git-branches

https://stackoverflow.com/questions/1783405/how-do-i-check-out-a-remote-git-branch


💩

Bitbucket + FortRabbit (or how to Git with multiple remotes)

Say you are using FortRabbit, which runs its own Git repository just for deployment purposes. You want commit history and user control, so you want something else like BitBucket as your primary repository.

You can have both (wow).

Step 1: Create a new repository in BitBucket. Do NOT create a readme file. There has to be no commit history or you will receive errors from FortRabbit.

Step 2: Clone your FortRabbit repository into a new folder on your computer. Let’s use double-repo for this example.

Step 3: Follow the steps below to remove FortRabbit as double-repo‘s remote and add BitBucket. Then push all the files to BitBucket.
https://www.atlassian.com/git/tutorials/git-move-repository

Step 4: Add FortRabbit as a remote using the syntax below. This will provide a unique name for the remote (fortrabbit) rather than the default, origin:
https://help.fortrabbit.com/github

Now the repositories have shared histories. It’s important that both repositories were synched when they were new to avoid history conflicts (which are more difficult when the repositories are managed without controls, by FortRabbit for example).

Now you can:

  • Push to BitBucket with git push origin master.
  • Push to FortRabbit with git push fortrabbit master.
  • Add new contributers to BitBucket without allowing them deployment privileges.

💩