Skip to content

Instantly share code, notes, and snippets.

@shwilliam
Last active October 16, 2019 06:01
Show Gist options
  • Save shwilliam/c25620cd065350ae319bb36c70f9d40f to your computer and use it in GitHub Desktop.
Save shwilliam/c25620cd065350ae319bb36c70f9d40f to your computer and use it in GitHub Desktop.
🍬 Tasty frontend recipes

goodies

contents

generate hash string

const genHash = (
  length,
  string = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-',
) => {
  let i = 0
  let hash = ''
  while (i < length) {
    hash += string.charAt(Math.floor(Math.random()*string.length))
    i++
  }
  return hash
}

truncate

function truncate({ text, chars = 100, clean = true, ellipses = false }) {
  const over = text.length > chars
  const a = text.substring(0, chars)
  const end = clean ? a.lastIndexOf(' ') : a.length
  const b = over ? a.substring(0, end) : text
  const e = over && ellipses ? '...' : ''
  return `${b}${e}`
}

remove duplicates from array of primitives

[... new Set(arr)]

fetch sequentially

function getResources(urls){
  let targetURL = urls.shift()
  if (targetURL){
    fetch(targetURL)
      .then(res => {
        // loaded
      })
      .catch(() => {
        // failed
      })
      .finally(() => {
        getResources(urls)
      })
  }
}

fetch all

Promise.all(urls.map(url => fetch(url)))
  .then(res => {
    // all loaded
    console.log('load')
  }, () => {
    console.log('failed')
    // one or more failed
  })

throttling

let scrollCache = undefined
window.addEventListener('scroll', e => {
  if (!cached) {
    setTimeout(() => {
      scrollCache = undefined
    }, 100)
  }
  scrollCache = e
})

fetch get status

fetch(url)
  .then(r =>  r.json().then(d => ({status: r.status, body: d})))

sr only

.sr-only {
  border: 0 !important;
  clip: rect(1px, 1px, 1px, 1px) !important;
  -webkit-clip-path: inset(50%) !important;
  clip-path: inset(50%) !important;
  height: 1px !important;
  margin: -1px !important;
  overflow: hidden !important;
  padding: 0 !important;
  position: absolute !important;
  width: 1px !important;
  white-space: nowrap !important;
}

/* show on focus */
.sr-only-focusable:focus,
.sr-only-focusable:active {
  clip: auto !important;
  -webkit-clip-path: none !important;
  clip-path: none !important;
  height: auto !important;
  margin: auto !important;
  overflow: visible !important;
  width: auto !important;
  white-space: normal !important;
}

scroll to el

function scrollTo(el, offset = 0) {
  const top = el.getBoundingClientRect().top + offset
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop
  const destY = scrollTop + top
  window.scrollTo(0, destY)
}

scroll snap

horizontal gallery

<style>
#gallery {
  scroll-snap-type: x mandatory;
  overflow-x: scroll;
  display: flex;
}

#gallery img {
   scroll-snap-align: center;
}
</style>

<div id="gallery">
  <img src="cat.jpg">
  <img src="dog.jpg">
  <img src="another_cute_animal.jpg">
</div>

journeyed product page

<style>
article {
  scroll-snap-type: y proximity;
  /* pad for header */
  scroll-padding-top: 15vh;
  overflow-y: scroll;
}
section {
  scroll-snap-align: start;
}
header {
  position: fixed;
  height: 10vh;
}
</style>

<article>
  <header> Header </header>
  <section> Section One </section>
  <section> Section Two </section>
  <section> Section Three </section>
</article>

lazy loading images

const lazyLoad = target => {
  const io = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target
        const src = img.getAttribute('data-lazy')

        img.setAttribute('src', src)
        img.classList.add('fade')

        observer.disconnect()
      }
    })
  })

  io.observe(target)
}

document.querySelectorAll('img').forEach(lazyLoad)

detect mobile

const isMobile = {
  android: () => navigator.userAgent.match(/Android/i),

  blackberry: () => navigator.userAgent.match(/BlackBerry/i),

  ios: () => navigator.userAgent.match(/iPhone|iPad|iPod/i),

  opera: () => navigator.userAgent.match(/Opera Mini/i),

  windows: () => navigator.userAgent.match(/IEMobile/i),

  any: () => (
    isMobile.android() ||
    isMobile.blackberry() ||
    isMobile.ios() ||
    isMobile.opera() ||
    isMobile.windows()
  ),
}

react clone children

React.Children.map(children, child => {
  return React.cloneElement(child, {
    someProp: someVal
  })
})

netlify redirect

create a _redirects file in your build folder to redirect back home regardless of the requested URL

/*    /index.html   200

alternatively, change your build script to do this for you

"build": "react-scripts build && echo '/*    /index.html   200' > build/_redirects"

conventional commits

squash feature branches with master using conventional commit messages and semantic versioning

<type>: <description>

[optional body]

[optional footer (eg. 'Fixes #13')]

types:

  • build: changes to build system/dependencies
  • docs: doc changes
  • feat: new feature
  • fix: bug fix
  • perf: change implemented to improve performance
  • refactor: change of code structure
  • style: white-space/formatting
  • test: add/change tests

fix -> patch release (0.0.X) feat -> minor release (0.X.0) any breaking change regardless of type -> major release (X.0.0)

tag GH version

$ git tag 0.1.0 && git push --tags

add title and desc on GH at https://github.com/shwilliam/<PACKAGE_NAME>/releases/new

delete GH tag

$ git tag -d 0.1.0 && git push origin :refs/tags/0.1.0

publish beta

in package.json add version suffix -beta.0 (increment beta version as necessary)

npm publish --tag beta (now available with npm i <PACKAGE_NAME>@beta)

list global dependencies

npm list -g --depth 0

grant write permission to all users

sudo chmod [-R] 777 [dir]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment