squircle

Make all the squircles you need, in the browser. https://squircley.app/
git clone http://git.hanabi.in/repos/squircle.git
Log | Files | Refs | LICENSE

commit f95a6e42c406497540b7c11285916897d97a0282
parent 26329bde8464e29238f4c8f893ff68aa44ee758d
Author: George Francis <georgedoescode@gmail.com>
Date:   Sat, 11 Jul 2020 07:29:58 +0100

code tidy

Diffstat:
Mreadme.md | 11+++++++++--
Msrc/assets/styles/app.css | 4++--
Dsrc/components/BaseTwoBtnToggle.vue | 73-------------------------------------------------------------------------
Msrc/components/GeneratorControls.vue | 18+++++++++++++-----
Msrc/components/GeneratorExportOptions.vue | 31+++++++++++++++++++++++++++----
Msrc/components/GeneratorPreview.vue | 4++--
Msrc/components/TheGenerator.vue | 20++++++++++++--------
Dsrc/components/test.svg | 11-----------
8 files changed, 65 insertions(+), 107 deletions(-)

diff --git a/readme.md b/readme.md @@ -1 +1,9 @@ -# Squircle land -\ No newline at end of file +# Squircley + +<img src="./public/og-image.png"> + +This is Squircley, an online SVG "squircle" squircle maker. You can check it out at https://squircley.app/ + +Squircley is built with vue.js and hosted on Netlify. + +**PRs are always welcome!** diff --git a/src/assets/styles/app.css b/src/assets/styles/app.css @@ -123,8 +123,6 @@ table { --grey-000: #f0f4f8; } -/* Global Styles */ - body:not(.user-is-tabbing) button:focus, body:not(.user-is-tabbing) input:focus, body:not(.user-is-tabbing) select:focus, @@ -132,6 +130,8 @@ body:not(.user-is-tabbing) textarea:focus { outline: none; } +/* Global Styles */ + body { font-family: var(--font-family); line-height: 1; diff --git a/src/components/BaseTwoBtnToggle.vue b/src/components/BaseTwoBtnToggle.vue @@ -1,73 +0,0 @@ -<script> -export default { - name: 'BaseThreeBtnToggle', - props: { - toggleState: { - type: Array, - required: true, - }, - }, -}; -</script> - -<template> - <div class="base-three-btn-toggle"> - <div - v-for="option in toggleState" - :key="option.id" - class="base-three-btn-toggle__option" - > - <input - :id="option.id" - type="radio" - :name="option.id" - :checked="option.checked ? 'checked' : ''" - @click="$emit('change', $event)" - /> - <label :for="option.id">{{ option.label }}</label> - </div> - </div> -</template> - -<style scoped> -.base-three-btn-toggle { - position: relative; - display: grid; - grid-template-columns: 1fr 1fr; - grid-auto-columns: 1fr; - align-items: center; - height: var(--spacing-5); - border: 1px solid var(--grey-200); - border-radius: 8px; - overflow: hidden; -} - -.base-three-btn-toggle__option { - width: 100%; - height: 100%; -} - -.base-three-btn-toggle label { - display: flex; - justify-content: center; - align-items: center; - width: 100%; - height: 100%; - cursor: pointer; -} - -.base-three-btn-toggle > div:nth-of-type(1) { - border-right: 1px solid var(--grey-200); -} - -.base-three-btn-toggle input { - position: absolute; - width: 0; - height: 0; - opacity: 0; -} - -.base-three-btn-toggle input:checked + label { - background: var(--grey-000); -} -</style> diff --git a/src/components/GeneratorControls.vue b/src/components/GeneratorControls.vue @@ -14,6 +14,14 @@ export default { type: String, required: true, }, + scale: { + type: Number, + required: true, + }, + curvature: { + type: Number, + required: true, + }, }, data() { return { @@ -68,7 +76,7 @@ export default { class="generator-controls__slider" :min="0" :max="200" - :value="100" + :value="scale" :step="1" @change="handleControlChange" /> @@ -80,7 +88,7 @@ export default { class="generator-controls__slider" :min="0" :max="1" - :value="0.5" + :value="curvature" :step="0.01" @change="handleControlChange" /> @@ -123,11 +131,11 @@ export default { /> </div> <hr /> - <label - for="" + <p class="generator-controls__label generator-controls__label--export" - >Export</label > + Export + </p> <GeneratorExportOptions /> </div> </div> diff --git a/src/components/GeneratorExportOptions.vue b/src/components/GeneratorExportOptions.vue @@ -13,22 +13,45 @@ export default { }, methods: { downloadSVG() { - const content = document.querySelector('#squircleSVG').outerHTML; - const blob = new Blob([content], { + const exportSVG = this.createSVG( + document.querySelector('#squircleSVG path') + ); + const blob = new Blob([exportSVG], { type: 'text/plain;charset=utf-8', }); saveAs(blob, 'squircle.svg'); }, copySVGToClipBoard() { - const content = document.querySelector('#squircleSVG').outerHTML; - copy(content); + const exportSVG = this.createSVG( + document.querySelector('#squircleSVG path') + ); + + copy(exportSVG); + this.$toasted.show('Squircle SVG copied to clipboard!', { position: 'bottom-center', duration: 2500, className: 'toast', }); }, + createSVG(originalPath) { + const svg = document.createElement('svg'); + const path = document.createElement('path'); + + svg.appendChild(path); + + svg.setAttribute('viewBox', '0 0 200 200'); + svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); + + const pathD = originalPath.getAttribute('d'); + const pathFill = originalPath.getAttribute('fill'); + + path.setAttribute('d', pathD); + path.setAttribute('fill', pathFill); + + return svg.outerHTML; + }, }, }; </script> diff --git a/src/components/GeneratorPreview.vue b/src/components/GeneratorPreview.vue @@ -11,7 +11,7 @@ export default { required: true, }, scale: { - type: String, + type: Number, required: true, }, }, @@ -25,7 +25,6 @@ export default { viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" version="1.1" - :fill="fill" > <path :d="path" @@ -33,6 +32,7 @@ export default { ${(200 - scale) / 2} ${(200 - scale) / 2} )`" + :fill="fill" /> </svg> </div> diff --git a/src/components/TheGenerator.vue b/src/components/TheGenerator.vue @@ -11,8 +11,8 @@ export default { data() { return { squircleOpts: { - curvature: 0.5, - scale: '100', + curvature: 0.75, + scale: 150, fill: '#FADB5F', }, path: '', @@ -27,19 +27,21 @@ export default { }, methods: { setPath(w = 100, h = 100, curvature = 0.5) { - const shiftW = (w / 2) * (1 - curvature); - const shiftH = (h / 2) * (1 - curvature); + const curveWidth = (w / 2) * (1 - curvature); + const curveHeight = (h / 2) * (1 - curvature); this.path = ` M 0, ${h / 2} - C 0, ${shiftW} ${shiftH}, 0 ${w / 2}, 0 - S ${w}, ${shiftH} ${w}, ${h / 2} - ${w - shiftW}, ${h - 0} ${w / 2}, ${h} - 0, ${w - shiftH} 0, ${h / 2} + C 0, ${curveWidth} ${curveHeight}, 0 ${w / 2}, 0 + S ${w}, ${curveHeight} ${w}, ${h / 2} + ${w - curveWidth}, ${h - 0} ${w / 2}, ${h} + 0, ${w - curveHeight} 0, ${h / 2} `; }, handleControlChange({ id, value }) { + if (id === 'scale') value = ~~value; this.squircleOpts[id] = value; + this.setPath( this.squircleOpts.scale, this.squircleOpts.scale, @@ -59,6 +61,8 @@ export default { /> <GeneratorControls :initial-fill="squircleOpts.fill" + :scale="squircleOpts.scale" + :curvature="squircleOpts.curvature" @controls-changed="handleControlChange" /> </div> diff --git a/src/components/test.svg b/src/components/test.svg @@ -1,10 +0,0 @@ -<svg data-v-48b4e325="" id="squircleSVG" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" version="1.1" fill="#1f2933"><path data-v-48b4e325="" d=" - M 0, 50 - C 0, 25 25, 0 50, 0 - S 100, 25 100, 50 - 75, 100 50, 100 - 0, 75 0, 50 - " transform="translate( - 50 - 50 - )"></path></svg> -\ No newline at end of file