perf: use a separate icons.svg file (#1067)
* perf: use a separate icons.svg file This splits icons into inline and non-inline. The inline ones are high priority; the rest go in an icons.svg file. * create SvgIcon.html * determine inlined svgs at build time
This commit is contained in:
parent
2fc6897ee3
commit
880bc7a38a
|
@ -11,6 +11,7 @@ tests
|
||||||
/mastodon.log
|
/mastodon.log
|
||||||
/src/template.html
|
/src/template.html
|
||||||
/static/*.css
|
/static/*.css
|
||||||
|
/static/icons.svg
|
||||||
/static/robots.txt
|
/static/robots.txt
|
||||||
/static/inline-script.js.map
|
/static/inline-script.js.map
|
||||||
/static/emoji-mart-all.json
|
/static/emoji-mart-all.json
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -5,6 +5,7 @@
|
||||||
/mastodon.log
|
/mastodon.log
|
||||||
/src/template.html
|
/src/template.html
|
||||||
/static/*.css
|
/static/*.css
|
||||||
|
/static/icons.svg
|
||||||
/static/robots.txt
|
/static/robots.txt
|
||||||
/static/inline-script.js.map
|
/static/inline-script.js.map
|
||||||
/static/emoji-mart-all.json
|
/static/emoji-mart-all.json
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
/mastodon.log
|
/mastodon.log
|
||||||
/src/template.html
|
/src/template.html
|
||||||
/static/*.css
|
/static/*.css
|
||||||
|
/static/icons.svg
|
||||||
/static/inline-script.js.map
|
/static/inline-script.js.map
|
||||||
/static/emoji-mart-all.json
|
/static/emoji-mart-all.json
|
||||||
/src/inline-script/checksum.js
|
/src/inline-script/checksum.js
|
||||||
|
|
|
@ -7,20 +7,32 @@ import $ from 'cheerio'
|
||||||
|
|
||||||
const svgo = new SVGO()
|
const svgo = new SVGO()
|
||||||
const readFile = promisify(fs.readFile)
|
const readFile = promisify(fs.readFile)
|
||||||
|
const writeFile = promisify(fs.writeFile)
|
||||||
|
|
||||||
|
async function readSvg (svg) {
|
||||||
|
let filepath = path.join(__dirname, '../', svg.src)
|
||||||
|
let content = await readFile(filepath, 'utf8')
|
||||||
|
let optimized = (await svgo.optimize(content))
|
||||||
|
let $optimized = $(optimized.data)
|
||||||
|
let $path = $optimized.find('path').removeAttr('fill')
|
||||||
|
let $symbol = $('<symbol></symbol>')
|
||||||
|
.attr('id', svg.id)
|
||||||
|
.attr('viewBox', `0 0 ${optimized.info.width} ${optimized.info.height}`)
|
||||||
|
.append($path)
|
||||||
|
return $.xml($symbol)
|
||||||
|
}
|
||||||
|
|
||||||
export async function buildSvg () {
|
export async function buildSvg () {
|
||||||
let result = (await Promise.all(svgs.map(async svg => {
|
let inlineSvgs = svgs.filter(_ => _.inline)
|
||||||
let filepath = path.join(__dirname, '../', svg.src)
|
let regularSvgs = svgs.filter(_ => !_.inline)
|
||||||
let content = await readFile(filepath, 'utf8')
|
|
||||||
let optimized = (await svgo.optimize(content))
|
|
||||||
let $optimized = $(optimized.data)
|
|
||||||
let $path = $optimized.find('path').removeAttr('fill')
|
|
||||||
let $symbol = $('<symbol></symbol>')
|
|
||||||
.attr('id', svg.id)
|
|
||||||
.attr('viewBox', `0 0 ${optimized.info.width} ${optimized.info.height}`)
|
|
||||||
.append($path)
|
|
||||||
return $.xml($symbol)
|
|
||||||
}))).join('\n')
|
|
||||||
|
|
||||||
return `<svg xmlns="http://www.w3.org/2000/svg" style="display:none;">\n${result}\n</svg>`
|
let inlineSvgStrings = (await Promise.all(inlineSvgs.map(readSvg))).join('')
|
||||||
|
let regularSvgStrings = (await Promise.all(regularSvgs.map(readSvg))).join('')
|
||||||
|
|
||||||
|
let inlineOutput = `<svg xmlns="http://www.w3.org/2000/svg" style="display:none">${inlineSvgStrings}</svg>`
|
||||||
|
let regularOutput = `<svg xmlns="http://www.w3.org/2000/svg">${regularSvgStrings}</svg>`
|
||||||
|
|
||||||
|
await writeFile(path.resolve(__dirname, '../static/icons.svg'), regularOutput, 'utf8')
|
||||||
|
|
||||||
|
return inlineOutput
|
||||||
}
|
}
|
||||||
|
|
12
bin/svgs.js
12
bin/svgs.js
|
@ -1,9 +1,9 @@
|
||||||
module.exports = [
|
module.exports = [
|
||||||
{ id: 'pinafore-logo', src: 'src/static/sailboat.svg' },
|
{ id: 'pinafore-logo', src: 'src/static/sailboat.svg', inline: true },
|
||||||
{ id: 'fa-bell', src: 'src/thirdparty/font-awesome-svg-png/white/svg/bell.svg' },
|
{ id: 'fa-bell', src: 'src/thirdparty/font-awesome-svg-png/white/svg/bell.svg', inline: true },
|
||||||
{ id: 'fa-users', src: 'src/thirdparty/font-awesome-svg-png/white/svg/users.svg' },
|
{ id: 'fa-users', src: 'src/thirdparty/font-awesome-svg-png/white/svg/users.svg', inline: true },
|
||||||
{ id: 'fa-globe', src: 'src/thirdparty/font-awesome-svg-png/white/svg/globe.svg' },
|
{ id: 'fa-globe', src: 'src/thirdparty/font-awesome-svg-png/white/svg/globe.svg' },
|
||||||
{ id: 'fa-gear', src: 'src/thirdparty/font-awesome-svg-png/white/svg/gear.svg' },
|
{ id: 'fa-gear', src: 'src/thirdparty/font-awesome-svg-png/white/svg/gear.svg', inline: true },
|
||||||
{ id: 'fa-reply', src: 'src/thirdparty/font-awesome-svg-png/white/svg/reply.svg' },
|
{ id: 'fa-reply', src: 'src/thirdparty/font-awesome-svg-png/white/svg/reply.svg' },
|
||||||
{ id: 'fa-reply-all', src: 'src/thirdparty/font-awesome-svg-png/white/svg/reply-all.svg' },
|
{ id: 'fa-reply-all', src: 'src/thirdparty/font-awesome-svg-png/white/svg/reply-all.svg' },
|
||||||
{ id: 'fa-retweet', src: 'src/thirdparty/font-awesome-svg-png/white/svg/retweet.svg' },
|
{ id: 'fa-retweet', src: 'src/thirdparty/font-awesome-svg-png/white/svg/retweet.svg' },
|
||||||
|
@ -21,8 +21,8 @@ module.exports = [
|
||||||
{ id: 'fa-user-times', src: 'src/thirdparty/font-awesome-svg-png/white/svg/user-times.svg' },
|
{ id: 'fa-user-times', src: 'src/thirdparty/font-awesome-svg-png/white/svg/user-times.svg' },
|
||||||
{ id: 'fa-user-plus', src: 'src/thirdparty/font-awesome-svg-png/white/svg/user-plus.svg' },
|
{ id: 'fa-user-plus', src: 'src/thirdparty/font-awesome-svg-png/white/svg/user-plus.svg' },
|
||||||
{ id: 'fa-external-link', src: 'src/thirdparty/font-awesome-svg-png/white/svg/external-link.svg' },
|
{ id: 'fa-external-link', src: 'src/thirdparty/font-awesome-svg-png/white/svg/external-link.svg' },
|
||||||
{ id: 'fa-search', src: 'src/thirdparty/font-awesome-svg-png/white/svg/search.svg' },
|
{ id: 'fa-search', src: 'src/thirdparty/font-awesome-svg-png/white/svg/search.svg', inline: true },
|
||||||
{ id: 'fa-comments', src: 'src/thirdparty/font-awesome-svg-png/white/svg/comments.svg' },
|
{ id: 'fa-comments', src: 'src/thirdparty/font-awesome-svg-png/white/svg/comments.svg', inline: true },
|
||||||
{ id: 'fa-paperclip', src: 'src/thirdparty/font-awesome-svg-png/white/svg/paperclip.svg' },
|
{ id: 'fa-paperclip', src: 'src/thirdparty/font-awesome-svg-png/white/svg/paperclip.svg' },
|
||||||
{ id: 'fa-thumb-tack', src: 'src/thirdparty/font-awesome-svg-png/white/svg/thumb-tack.svg' },
|
{ id: 'fa-thumb-tack', src: 'src/thirdparty/font-awesome-svg-png/white/svg/thumb-tack.svg' },
|
||||||
{ id: 'fa-bars', src: 'src/thirdparty/font-awesome-svg-png/white/svg/bars.svg' },
|
{ id: 'fa-bars', src: 'src/thirdparty/font-awesome-svg-png/white/svg/bars.svg' },
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "standard && standard --plugin html 'src/routes/**/*.html'",
|
"lint": "standard && standard --plugin html 'src/routes/**/*.html'",
|
||||||
"lint-fix": "standard --fix && standard --fix --plugin html 'src/routes/**/*.html'",
|
"lint-fix": "standard --fix && standard --fix --plugin html 'src/routes/**/*.html'",
|
||||||
"dev": "run-s build-template-html build-third-party-assets serve-dev",
|
"dev": "run-s build-template-html build-assets serve-dev",
|
||||||
"serve-dev": "run-p --race build-template-html-watch sapper-dev",
|
"serve-dev": "run-p --race build-template-html-watch sapper-dev",
|
||||||
"sapper-dev": "cross-env NODE_ENV=development PORT=4002 sapper dev",
|
"sapper-dev": "cross-env NODE_ENV=development PORT=4002 sapper dev",
|
||||||
"before-build": "run-s build-template-html build-third-party-assets",
|
"before-build": "run-s build-template-html build-assets",
|
||||||
"build": "cross-env NODE_ENV=production run-s build-steps",
|
"build": "cross-env NODE_ENV=production run-s build-steps",
|
||||||
"build-steps": "run-s before-build sapper-export build-now-json",
|
"build-steps": "run-s before-build sapper-export build-now-json",
|
||||||
"sapper-build": "sapper build",
|
"sapper-build": "sapper build",
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
"build-and-start": "run-s build start",
|
"build-and-start": "run-s build start",
|
||||||
"build-template-html": "node -r esm ./bin/build-template-html.js",
|
"build-template-html": "node -r esm ./bin/build-template-html.js",
|
||||||
"build-template-html-watch": "node -r esm ./bin/build-template-html.js --watch",
|
"build-template-html-watch": "node -r esm ./bin/build-template-html.js --watch",
|
||||||
"build-third-party-assets": "node -r esm ./bin/build-third-party-assets.js",
|
"build-assets": "node -r esm ./bin/build-assets.js",
|
||||||
"run-mastodon": "node -r esm ./bin/run-mastodon.js",
|
"run-mastodon": "node -r esm ./bin/run-mastodon.js",
|
||||||
"test": "cross-env BROWSER=chrome:headless run-s test-browser",
|
"test": "cross-env BROWSER=chrome:headless run-s test-browser",
|
||||||
"test-browser": "run-p --race run-mastodon build-and-start test-mastodon",
|
"test-browser": "run-p --race run-mastodon build-and-start test-mastodon",
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
{#if error}
|
{#if error}
|
||||||
<svg class={computedClass} style={svgStyle} aria-hidden="true">
|
<SvgIcon className={computedClass} style={svgStyle} href="#fa-user" />
|
||||||
<use xlink:href="#fa-user" />
|
|
||||||
</svg>
|
|
||||||
{:elseif $autoplayGifs}
|
{:elseif $autoplayGifs}
|
||||||
<LazyImage
|
<LazyImage
|
||||||
className={computedClass}
|
className={computedClass}
|
||||||
|
@ -37,7 +35,7 @@
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
svg.avatar {
|
:global(svg.avatar) {
|
||||||
fill: var(--deemphasized-text-color);
|
fill: var(--deemphasized-text-color);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -46,6 +44,7 @@
|
||||||
import NonAutoplayImg from './NonAutoplayImg.html'
|
import NonAutoplayImg from './NonAutoplayImg.html'
|
||||||
import { classname } from '../_utils/classname'
|
import { classname } from '../_utils/classname'
|
||||||
import LazyImage from './LazyImage.html'
|
import LazyImage from './LazyImage.html'
|
||||||
|
import SvgIcon from './SvgIcon.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data: () => ({
|
data: () => ({
|
||||||
|
@ -80,7 +79,8 @@
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
NonAutoplayImg,
|
NonAutoplayImg,
|
||||||
LazyImage
|
LazyImage,
|
||||||
|
SvgIcon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
role="navigation" aria-label="Page header"
|
role="navigation" aria-label="Page header"
|
||||||
>
|
>
|
||||||
{#if icon}
|
{#if icon}
|
||||||
<svg class="dynamic-page-banner-svg">
|
<SvgIcon className="dynamic-page-banner-svg" href={icon} />
|
||||||
<use xlink:href={icon} />
|
|
||||||
</svg>
|
|
||||||
{/if}
|
{/if}
|
||||||
<h1 class="dynamic-page-title" aria-label={ariaTitle}>{title}</h1>
|
<h1 class="dynamic-page-title" aria-label={ariaTitle}>{title}</h1>
|
||||||
<button type="button"
|
<button type="button"
|
||||||
|
@ -24,7 +22,7 @@
|
||||||
.dynamic-page-banner.dynamic-page-with-icon {
|
.dynamic-page-banner.dynamic-page-with-icon {
|
||||||
grid-template-columns: min-content 1fr min-content;
|
grid-template-columns: min-content 1fr min-content;
|
||||||
}
|
}
|
||||||
.dynamic-page-banner-svg {
|
:global(.dynamic-page-banner-svg) {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
fill: var(--body-text-color);
|
fill: var(--body-text-color);
|
||||||
|
@ -64,13 +62,17 @@
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import Shortcut from './shortcut/Shortcut.html'
|
import Shortcut from './shortcut/Shortcut.html'
|
||||||
|
import SvgIcon from './SvgIcon.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data: () => ({
|
data: () => ({
|
||||||
icon: void 0,
|
icon: void 0,
|
||||||
ariaTitle: ''
|
ariaTitle: ''
|
||||||
}),
|
}),
|
||||||
components: { Shortcut },
|
components: {
|
||||||
|
Shortcut,
|
||||||
|
SvgIcon
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onGoBack () {
|
onGoBack () {
|
||||||
window.history.back()
|
window.history.back()
|
||||||
|
|
|
@ -4,27 +4,26 @@
|
||||||
aria-label={ariaLabel}
|
aria-label={ariaLabel}
|
||||||
class={computedClass}>
|
class={computedClass}>
|
||||||
<slot></slot>{#if showIcon}
|
<slot></slot>{#if showIcon}
|
||||||
<svg class="external-link-svg">
|
<SvgIcon className="external-link-svg" href="#fa-external-link" />
|
||||||
<use xlink:href="#fa-external-link" />
|
|
||||||
</svg>
|
|
||||||
{/if}</a>
|
{/if}</a>
|
||||||
<style>
|
<style>
|
||||||
.external-link-with-icon {
|
.external-link-with-icon {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
.external-link-with-icon .external-link-svg {
|
:global(.external-link-with-icon .external-link-svg) {
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
fill: var(--deemphasized-text-color);
|
fill: var(--deemphasized-text-color);
|
||||||
}
|
}
|
||||||
.external-link-with-icon.normal-icon-color .external-link-svg {
|
:global(.external-link-with-icon.normal-icon-color .external-link-svg) {
|
||||||
fill: var(--body-text-color);
|
fill: var(--body-text-color);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import { classname } from '../_utils/classname'
|
import { classname } from '../_utils/classname'
|
||||||
|
import SvgIcon from './SvgIcon.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data: () => ({
|
data: () => ({
|
||||||
|
@ -40,6 +39,9 @@
|
||||||
showIcon && 'external-link-with-icon',
|
showIcon && 'external-link-with-icon',
|
||||||
normalIconColor && 'normal-icon-color'
|
normalIconColor && 'normal-icon-color'
|
||||||
))
|
))
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
SvgIcon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -7,9 +7,7 @@
|
||||||
{disabled}
|
{disabled}
|
||||||
ref:node
|
ref:node
|
||||||
>
|
>
|
||||||
<svg class="icon-button-svg {svgClassName || ''}" ref:svg>
|
<SvgIcon className="icon-button-svg {svgClassName || ''}" ref:svg {href} />
|
||||||
<use xlink:href={href} />
|
|
||||||
</svg>
|
|
||||||
</button>
|
</button>
|
||||||
<style>
|
<style>
|
||||||
.icon-button {
|
.icon-button {
|
||||||
|
@ -21,14 +19,14 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-button-svg {
|
:global(.icon-button-svg) {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
fill: var(--action-button-fill-color);
|
fill: var(--action-button-fill-color);
|
||||||
pointer-events: none; /* hack for Edge */
|
pointer-events: none; /* hack for Edge */
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-button.big-icon .icon-button-svg {
|
:global(.icon-button.big-icon .icon-button-svg) {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
}
|
}
|
||||||
|
@ -37,24 +35,24 @@
|
||||||
* regular styles
|
* regular styles
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.icon-button:hover .icon-button-svg {
|
:global(.icon-button:hover .icon-button-svg) {
|
||||||
fill: var(--action-button-fill-color-hover);
|
fill: var(--action-button-fill-color-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-button.not-pressable:active .icon-button-svg,
|
:global(.icon-button.not-pressable:active .icon-button-svg,
|
||||||
.icon-button.same-pressed:active .icon-button-svg {
|
.icon-button.same-pressed:active .icon-button-svg) {
|
||||||
fill: var(--action-button-fill-color-active);
|
fill: var(--action-button-fill-color-active);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-button.pressed.not-same-pressed .icon-button-svg {
|
:global(.icon-button.pressed.not-same-pressed .icon-button-svg) {
|
||||||
fill: var(--action-button-fill-color-pressed);
|
fill: var(--action-button-fill-color-pressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-button.pressed.not-same-pressed:hover .icon-button-svg {
|
:global(.icon-button.pressed.not-same-pressed:hover .icon-button-svg) {
|
||||||
fill: var(--action-button-fill-color-pressed-hover);
|
fill: var(--action-button-fill-color-pressed-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-button.pressed.not-same-pressed:active .icon-button-svg {
|
:global(.icon-button.pressed.not-same-pressed:active .icon-button-svg) {
|
||||||
fill: var(--action-button-fill-color-pressed-active);
|
fill: var(--action-button-fill-color-pressed-active);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,28 +60,28 @@
|
||||||
* muted
|
* muted
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.icon-button.muted-style .icon-button-svg {
|
:global(.icon-button.muted-style .icon-button-svg) {
|
||||||
fill: var(--action-button-deemphasized-fill-color);
|
fill: var(--action-button-deemphasized-fill-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-button.muted-style:hover .icon-button-svg {
|
:global(.icon-button.muted-style:hover .icon-button-svg) {
|
||||||
fill: var(--action-button-deemphasized-fill-color-hover);
|
fill: var(--action-button-deemphasized-fill-color-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-button.muted-style.not-pressable:active .icon-button-svg,
|
:global(.icon-button.muted-style.not-pressable:active .icon-button-svg,
|
||||||
.icon-button.muted-style.same-pressed:active .icon-button-svg {
|
.icon-button.muted-style.same-pressed:active .icon-button-svg) {
|
||||||
fill: var(--action-button-deemphasized-fill-color-active);
|
fill: var(--action-button-deemphasized-fill-color-active);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-button.muted-style.pressed.not-same-pressed .icon-button-svg {
|
:global(.icon-button.muted-style.pressed.not-same-pressed .icon-button-svg) {
|
||||||
fill: var(--action-button-deemphasized-fill-color-pressed);
|
fill: var(--action-button-deemphasized-fill-color-pressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-button.muted-style.pressed.not-same-pressed:hover .icon-button-svg {
|
:global(.icon-button.muted-style.pressed.not-same-pressed:hover .icon-button-svg) {
|
||||||
fill: var(--action-button-deemphasized-fill-color-pressed-hover);
|
fill: var(--action-button-deemphasized-fill-color-pressed-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-button.muted-style.pressed.not-same-pressed:active .icon-button-svg {
|
:global(.icon-button.muted-style.pressed.not-same-pressed:active .icon-button-svg) {
|
||||||
fill: var(--action-button-deemphasized-fill-color-pressed-active);
|
fill: var(--action-button-deemphasized-fill-color-pressed-active);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +89,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { classname } from '../_utils/classname'
|
import { classname } from '../_utils/classname'
|
||||||
import { store } from '../_store/store'
|
import { store } from '../_store/store'
|
||||||
import { animate } from '../_utils/animate'
|
import SvgIcon from './SvgIcon.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate () {
|
oncreate () {
|
||||||
|
@ -139,16 +137,14 @@
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
animate (animation) {
|
animate (animation) {
|
||||||
let { reduceMotion } = this.store.get()
|
this.refs.svg.animate(animation)
|
||||||
if (!animation || reduceMotion) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let svg = this.refs.svg
|
|
||||||
animate(svg, animation)
|
|
||||||
},
|
},
|
||||||
onClick (e) {
|
onClick (e) {
|
||||||
this.fire('click', e)
|
this.fire('click', e)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
SvgIcon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,23 +1,27 @@
|
||||||
<svg class="loading-spinner-icon spin {maskStyle ? 'mask-style' : ''}"
|
<SvgIcon className="loading-spinner-icon spin {maskStyle ? 'mask-style' : ''}"
|
||||||
style="width: {size}px; height: {size}px;"
|
style="width: {size}px; height: {size}px;"
|
||||||
aria-label="Loading"
|
href="#fa-spinner"
|
||||||
>
|
ariaLabel="Loading"
|
||||||
<use xlink:href="#fa-spinner" />
|
/>
|
||||||
</svg>
|
|
||||||
<style>
|
<style>
|
||||||
.loading-spinner-icon {
|
:global(.loading-spinner-icon) {
|
||||||
fill: var(--svg-fill);
|
fill: var(--svg-fill);
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading-spinner-icon.mask-style {
|
:global(.loading-spinner-icon.mask-style) {
|
||||||
fill: var(--mask-svg-fill);
|
fill: var(--mask-svg-fill);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
|
import SvgIcon from './SvgIcon.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data: () => ({
|
data: () => ({
|
||||||
maskStyle: false,
|
maskStyle: false,
|
||||||
size: 64
|
size: 64
|
||||||
})
|
}),
|
||||||
|
components: {
|
||||||
|
SvgIcon
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
Before Width: | Height: | Size: 443 B After Width: | Height: | Size: 543 B |
|
@ -1,16 +1,12 @@
|
||||||
{#if showBadge}
|
{#if showBadge}
|
||||||
<div class="nav-link-svg-wrapper">
|
<div class="nav-link-svg-wrapper">
|
||||||
<svg class="nav-link-svg">
|
<SvgIcon className="nav-link-svg" href={svg} />
|
||||||
<use xlink:href={svg} />
|
|
||||||
</svg>
|
|
||||||
<span class="nav-link-badge nav-link-badge-digits-{badgeDigits}" aria-hidden="true">
|
<span class="nav-link-badge nav-link-badge-digits-{badgeDigits}" aria-hidden="true">
|
||||||
{badgeNumberToShow}
|
{badgeNumberToShow}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<svg class="nav-link-svg">
|
<SvgIcon className="nav-link-svg" href={svg} />
|
||||||
<use xlink:href={svg} />
|
|
||||||
</svg>
|
|
||||||
{/if}
|
{/if}
|
||||||
<style>
|
<style>
|
||||||
.nav-link-svg-wrapper {
|
.nav-link-svg-wrapper {
|
||||||
|
@ -18,7 +14,7 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-link-svg-wrapper, .nav-link-svg {
|
:global(.nav-link-svg-wrapper, .nav-link-svg) {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
|
@ -51,7 +47,7 @@
|
||||||
font-size: 0.6em;
|
font-size: 0.6em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-link-svg {
|
:global(.nav-link-svg) {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
fill: var(--nav-svg-fill);
|
fill: var(--nav-svg-fill);
|
||||||
}
|
}
|
||||||
|
@ -61,7 +57,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 991px) {
|
@media (max-width: 991px) {
|
||||||
.nav-link-svg-wrapper, .nav-link-svg {
|
:global(.nav-link-svg-wrapper, .nav-link-svg) {
|
||||||
width: 25px;
|
width: 25px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
}
|
}
|
||||||
|
@ -72,6 +68,8 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
|
import SvgIcon from './SvgIcon.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data: () => ({
|
data: () => ({
|
||||||
showBadge: false,
|
showBadge: false,
|
||||||
|
@ -80,6 +78,9 @@
|
||||||
computed: {
|
computed: {
|
||||||
badgeDigits: ({ badgeNumber }) => Math.min(3, badgeNumber.toString().length),
|
badgeDigits: ({ badgeNumber }) => Math.min(3, badgeNumber.toString().length),
|
||||||
badgeNumberToShow: ({ badgeNumber }) => (badgeNumber < 100 ? badgeNumber.toString() : '99+')
|
badgeNumberToShow: ({ badgeNumber }) => (badgeNumber < 100 ? badgeNumber.toString() : '99+')
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
SvgIcon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
<FreeTextLayout>
|
<FreeTextLayout>
|
||||||
<div class="not-logged-in-home">
|
<div class="not-logged-in-home">
|
||||||
<div class="banner">
|
<div class="banner">
|
||||||
<svg aria-hidden="true" class="not-logged-in-home-svg">
|
<SvgIcon className="not-logged-in-home-svg" href="#pinafore-logo" />
|
||||||
<use xlink:href="#pinafore-logo" />
|
|
||||||
</svg>
|
|
||||||
<h1>Pinafore</h1>
|
<h1>Pinafore</h1>
|
||||||
</div>
|
</div>
|
||||||
<p>Pinafore is a web client for <ExternalLink href="https://joinmastodon.org">Mastodon</ExternalLink>, designed for speed and simplicity.</p>
|
<p>Pinafore is a web client for <ExternalLink href="https://joinmastodon.org">Mastodon</ExternalLink>, designed for speed and simplicity.</p>
|
||||||
|
@ -24,7 +22,7 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin: 0 0 30px;
|
margin: 0 0 30px;
|
||||||
}
|
}
|
||||||
.not-logged-in-home-svg {
|
:global(.not-logged-in-home-svg) {
|
||||||
width: 70px;
|
width: 70px;
|
||||||
height: 70px;
|
height: 70px;
|
||||||
fill: var(--banner-fill);
|
fill: var(--banner-fill);
|
||||||
|
@ -47,12 +45,14 @@
|
||||||
import FreeTextLayout from './FreeTextLayout.html'
|
import FreeTextLayout from './FreeTextLayout.html'
|
||||||
import HiddenFromSSR from './HiddenFromSSR.html'
|
import HiddenFromSSR from './HiddenFromSSR.html'
|
||||||
import ExternalLink from './ExternalLink.html'
|
import ExternalLink from './ExternalLink.html'
|
||||||
|
import SvgIcon from './SvgIcon.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
FreeTextLayout,
|
FreeTextLayout,
|
||||||
HiddenFromSSR,
|
HiddenFromSSR,
|
||||||
ExternalLink
|
ExternalLink,
|
||||||
|
SvgIcon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<div class="play-video-icon {className || ''}">
|
<div class="play-video-icon {className || ''}">
|
||||||
<svg class="play-video-icon-svg">
|
<SvgIcon className="play-video-icon-svg" href="#fa-play-circle" />
|
||||||
<use xlink:href="#fa-play-circle" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
<style>
|
<style>
|
||||||
.play-video-icon {
|
.play-video-icon {
|
||||||
|
@ -16,7 +14,7 @@
|
||||||
z-index: 40;
|
z-index: 40;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
.play-video-icon-svg {
|
:global(.play-video-icon-svg) {
|
||||||
width: 72px;
|
width: 72px;
|
||||||
height: 72px;
|
height: 72px;
|
||||||
fill: var(--mask-svg-fill);
|
fill: var(--mask-svg-fill);
|
||||||
|
@ -25,9 +23,14 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
|
import SvgIcon from './SvgIcon.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data: () => ({
|
data: () => ({
|
||||||
className: void 0
|
className: void 0
|
||||||
})
|
}),
|
||||||
|
components: {
|
||||||
|
SvgIcon
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
37
src/routes/_components/SvgIcon.html
Normal file
37
src/routes/_components/SvgIcon.html
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<svg
|
||||||
|
class={className}
|
||||||
|
{style}
|
||||||
|
aria-hidden={!ariaLabel}
|
||||||
|
aria-label={ariaLabel}
|
||||||
|
ref:svg>
|
||||||
|
<use xlink:href="{inline ? '' : '/icons.svg'}{href}" />
|
||||||
|
</svg>
|
||||||
|
<script>
|
||||||
|
import { animate } from '../_utils/animate'
|
||||||
|
import { store } from '../_store/store'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data: () => ({
|
||||||
|
className: '',
|
||||||
|
style: '',
|
||||||
|
ariaLabel: ''
|
||||||
|
}),
|
||||||
|
store: () => store,
|
||||||
|
computed: {
|
||||||
|
inline: ({ href }) => {
|
||||||
|
// filled in during build
|
||||||
|
return process.env.INLINE_SVGS.includes(href)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
animate (animation) {
|
||||||
|
let { reduceMotion } = this.store.get()
|
||||||
|
if (!animation || reduceMotion) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let svg = this.refs.svg
|
||||||
|
animate(svg, animation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
After Width: | Height: | Size: 790 B |
|
@ -1,8 +1,6 @@
|
||||||
<li class="page-list-item">
|
<li class="page-list-item">
|
||||||
<a {href} rel="prefetch">
|
<a {href} rel="prefetch">
|
||||||
<svg class="page-list-item-svg">
|
<SvgIcon className="page-list-item-svg" href={icon} />
|
||||||
<use xlink:href={icon} />
|
|
||||||
</svg>
|
|
||||||
<span aria-label={ariaLabel}>
|
<span aria-label={ariaLabel}>
|
||||||
{label}
|
{label}
|
||||||
</span>
|
</span>
|
||||||
|
@ -40,7 +38,7 @@
|
||||||
.page-list-item a:active {
|
.page-list-item a:active {
|
||||||
background: var(--settings-list-item-bg-active);
|
background: var(--settings-list-item-bg-active);
|
||||||
}
|
}
|
||||||
.page-list-item-svg {
|
:global(.page-list-item-svg) {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -57,7 +55,7 @@
|
||||||
.page-list-item a {
|
.page-list-item a {
|
||||||
padding: 20px 10px;
|
padding: 20px 10px;
|
||||||
}
|
}
|
||||||
.page-list-item-svg {
|
:global(.page-list-item-svg) {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,6 +64,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { store } from '../../_store/store'
|
import { store } from '../../_store/store'
|
||||||
import IconButton from '../IconButton'
|
import IconButton from '../IconButton'
|
||||||
|
import SvgIcon from '../SvgIcon.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
store: () => store,
|
store: () => store,
|
||||||
|
@ -82,7 +81,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
IconButton
|
IconButton,
|
||||||
|
SvgIcon
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onPinClick (e) {
|
onPinClick (e) {
|
||||||
|
|
|
@ -8,16 +8,14 @@
|
||||||
</span>
|
</span>
|
||||||
<div class="compose-box-button-spinner"
|
<div class="compose-box-button-spinner"
|
||||||
aria-hidden="true">
|
aria-hidden="true">
|
||||||
<svg class="compose-box-button-svg {$postingStatus ? 'spin' : 'hidden'}">
|
<SvgIcon className="compose-box-button-svg {$postingStatus ? 'spin' : 'hidden'}"
|
||||||
<use xlink:href="#fa-spinner" />
|
href="#fa-spinner" />
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="compose-box-button-compose {sticky ? '' : 'hidden'}"
|
<div class="compose-box-button-compose {sticky ? '' : 'hidden'}"
|
||||||
aria-hidden="true">
|
aria-hidden="true">
|
||||||
<svg class="compose-box-button-svg">
|
<SvgIcon className="compose-box-button-svg"
|
||||||
<use xlink:href="#fa-pencil" />
|
href="#fa-pencil" />
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -49,7 +47,7 @@
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
.compose-box-button-svg {
|
:global(.compose-box-button-svg) {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
fill: var(--button-primary-text);
|
fill: var(--button-primary-text);
|
||||||
|
@ -65,12 +63,16 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
|
import SvgIcon from '../SvgIcon.html'
|
||||||
import { store } from '../../_store/store'
|
import { store } from '../../_store/store'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
store: () => store,
|
store: () => store,
|
||||||
computed: {
|
computed: {
|
||||||
disabled: ({ $postingStatus, overLimit }) => $postingStatus || overLimit
|
disabled: ({ $postingStatus, overLimit }) => $postingStatus || overLimit
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
SvgIcon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -4,9 +4,7 @@
|
||||||
<button class="compose-media-delete-button"
|
<button class="compose-media-delete-button"
|
||||||
aria-label="Delete {shortName}"
|
aria-label="Delete {shortName}"
|
||||||
on:click="onDeleteMedia()" >
|
on:click="onDeleteMedia()" >
|
||||||
<svg class="compose-media-delete-button-svg">
|
<SvgIcon className="compose-media-delete-button-svg" href="#fa-times" />
|
||||||
<use xlink:href="#fa-times" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="compose-media-alt">
|
<div class="compose-media-alt">
|
||||||
|
@ -73,7 +71,7 @@
|
||||||
.compose-media-delete-button:hover {
|
.compose-media-delete-button:hover {
|
||||||
background: var(--toast-border);
|
background: var(--toast-border);
|
||||||
}
|
}
|
||||||
.compose-media-delete-button-svg {
|
:global(.compose-media-delete-button-svg) {
|
||||||
fill: var(--button-text);
|
fill: var(--button-text);
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
|
@ -95,6 +93,7 @@
|
||||||
import debounce from 'lodash-es/debounce'
|
import debounce from 'lodash-es/debounce'
|
||||||
import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
|
import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
|
||||||
import { observe } from 'svelte-extras'
|
import { observe } from 'svelte-extras'
|
||||||
|
import SvgIcon from '../SvgIcon.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate () {
|
oncreate () {
|
||||||
|
@ -147,6 +146,9 @@
|
||||||
} = this.get()
|
} = this.get()
|
||||||
deleteMedia(realm, index)
|
deleteMedia(realm, index)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
SvgIcon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -2,16 +2,13 @@
|
||||||
{#each items as item (item.key)}
|
{#each items as item (item.key)}
|
||||||
<li class="generic-dialog-list-item">
|
<li class="generic-dialog-list-item">
|
||||||
<button class="generic-dialog-list-button" on:click="fire('click', item)">
|
<button class="generic-dialog-list-button" on:click="fire('click', item)">
|
||||||
<svg class="generic-dialog-list-item-svg">
|
<SvgIcon className="generic-dialog-list-item-svg" href={item.icon} />
|
||||||
<use xlink:href={item.icon} />
|
|
||||||
</svg>
|
|
||||||
<span class="generic-dialog-list-button-span">
|
<span class="generic-dialog-list-button-span">
|
||||||
{item.label}
|
{item.label}
|
||||||
</span>
|
</span>
|
||||||
{#if selectable}
|
{#if selectable}
|
||||||
<svg class="generic-dialog-list-item-svg {item.selected ? '' : 'hidden'}" aria-hidden={!item.selected}>
|
<SvgIcon className="generic-dialog-list-item-svg {item.selected ? '' : 'hidden'}"
|
||||||
<use xlink:href="#fa-check" />
|
href="#fa-check" />
|
||||||
</svg>
|
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
@ -31,7 +28,7 @@
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
.generic-dialog-list-item-svg {
|
:global(.generic-dialog-list-item-svg) {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
fill: var(--svg-fill);
|
fill: var(--svg-fill);
|
||||||
|
@ -88,3 +85,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<script>
|
||||||
|
import SvgIcon from '../../SvgIcon.html'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
SvgIcon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
|
@ -15,9 +15,7 @@
|
||||||
<div class="close-dialog-button-wrapper">
|
<div class="close-dialog-button-wrapper">
|
||||||
<button class="close-dialog-button"
|
<button class="close-dialog-button"
|
||||||
data-a11y-dialog-hide aria-label="Close dialog">
|
data-a11y-dialog-hide aria-label="Close dialog">
|
||||||
<svg class="close-dialog-button-svg">
|
<SvgIcon className="close-dialog-button-svg" href="#fa-times" />
|
||||||
<use xlink:href="#fa-times" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -102,7 +100,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
.close-dialog-button-svg {
|
:global(.close-dialog-button-svg) {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
fill: var(--button-primary-text);
|
fill: var(--button-primary-text);
|
||||||
width: 24px;
|
width: 24px;
|
||||||
|
@ -129,7 +127,7 @@
|
||||||
.modal-dialog-title {
|
.modal-dialog-title {
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
}
|
}
|
||||||
.close-dialog-button-svg {
|
:global(.close-dialog-button-svg) {
|
||||||
padding: 7px;
|
padding: 7px;
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
|
@ -138,6 +136,7 @@
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import Shortcut from '../../shortcut/Shortcut.html'
|
import Shortcut from '../../shortcut/Shortcut.html'
|
||||||
|
import SvgIcon from '../../SvgIcon.html'
|
||||||
import { A11yDialog } from '../../../_thirdparty/a11y-dialog/a11y-dialog'
|
import { A11yDialog } from '../../../_thirdparty/a11y-dialog/a11y-dialog'
|
||||||
import { classname } from '../../../_utils/classname'
|
import { classname } from '../../../_utils/classname'
|
||||||
import { on, emit } from '../../../_utils/eventBus'
|
import { on, emit } from '../../../_utils/eventBus'
|
||||||
|
@ -164,7 +163,7 @@
|
||||||
ondestroy () {
|
ondestroy () {
|
||||||
popShortcutScope('modal')
|
popShortcutScope('modal')
|
||||||
},
|
},
|
||||||
components: { Shortcut },
|
components: { Shortcut, SvgIcon },
|
||||||
data: () => ({
|
data: () => ({
|
||||||
// don't animate if we're showing a modal dialog on top of another modal dialog. it looks ugly
|
// don't animate if we're showing a modal dialog on top of another modal dialog. it looks ugly
|
||||||
shouldAnimate: !process.browser || document.getElementsByClassName('modal-dialog').length < 2,
|
shouldAnimate: !process.browser || document.getElementsByClassName('modal-dialog').length < 2,
|
||||||
|
|
|
@ -19,9 +19,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="account-profile-meta-cell account-profile-meta-verified">
|
<div class="account-profile-meta-cell account-profile-meta-verified">
|
||||||
{#if field.verified}
|
{#if field.verified}
|
||||||
<svg class="account-profile-meta-verified-svg">
|
<SvgIcon className="account-profile-meta-verified-svg" href="#fa-check" />
|
||||||
<use xlink:href='#fa-check' />
|
|
||||||
</svg>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -54,7 +52,7 @@
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.account-profile-meta-verified-svg {
|
:global(.account-profile-meta-verified-svg) {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
fill: var(--svg-fill);
|
fill: var(--svg-fill);
|
||||||
|
@ -102,6 +100,7 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
|
import SvgIcon from '../SvgIcon.html'
|
||||||
import { emojifyText } from '../../_utils/emojifyText'
|
import { emojifyText } from '../../_utils/emojifyText'
|
||||||
import { store } from '../../_store/store'
|
import { store } from '../../_store/store'
|
||||||
|
|
||||||
|
@ -115,6 +114,9 @@
|
||||||
value: emojifyText(field.value, emojis, $autoplayGifs),
|
value: emojifyText(field.value, emojis, $autoplayGifs),
|
||||||
verified: !!field.verified_at
|
verified: !!field.verified_at
|
||||||
})))
|
})))
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
SvgIcon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
<div class="account-profile-moved-banner">
|
<div class="account-profile-moved-banner">
|
||||||
<Avatar className="from-avatar" size="extra-small" {account} />
|
<Avatar className="from-avatar" size="extra-small" {account} />
|
||||||
<div class="moved-label">
|
<div class="moved-label">
|
||||||
<svg class="moved-svg">
|
<SvgIcon className="moved-svg" href="#fa-suitcase" />
|
||||||
<use xlink:href="#fa-suitcase"/>
|
|
||||||
</svg>
|
|
||||||
{accessibleName} has moved:
|
{accessibleName} has moved:
|
||||||
</div>
|
</div>
|
||||||
<a class="moved-avatar" href="/accounts/{moved.id}">
|
<a class="moved-avatar" href="/accounts/{moved.id}">
|
||||||
|
@ -27,7 +25,7 @@
|
||||||
grid-area: from-avatar;
|
grid-area: from-avatar;
|
||||||
justify-self: flex-end;
|
justify-self: flex-end;
|
||||||
}
|
}
|
||||||
.moved-svg {
|
:global(.moved-svg) {
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
fill: var(--deemphasized-text-color);
|
fill: var(--deemphasized-text-color);
|
||||||
|
@ -64,6 +62,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { removeEmoji } from '../../_utils/removeEmoji'
|
import { removeEmoji } from '../../_utils/removeEmoji'
|
||||||
import Avatar from '../Avatar.html'
|
import Avatar from '../Avatar.html'
|
||||||
|
import SvgIcon from '../SvgIcon.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -84,7 +83,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Avatar
|
Avatar,
|
||||||
|
SvgIcon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
bind:value="$queryInSearch">
|
bind:value="$queryInSearch">
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="primary search-button" aria-label="Search" disabled={$searchLoading}>
|
<button type="submit" class="primary search-button" aria-label="Search" disabled={$searchLoading}>
|
||||||
<svg class="search-button-svg">
|
<SvgIcon className="search-button-svg" href="#fa-search" />
|
||||||
<use xlink:href="#fa-search" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
{#if $searchLoading}
|
{#if $searchLoading}
|
||||||
|
@ -39,7 +37,7 @@
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
.search-button-svg {
|
:global(.search-button-svg) {
|
||||||
fill: var(--button-primary-text);
|
fill: var(--button-primary-text);
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
|
@ -60,12 +58,14 @@
|
||||||
import LoadingPage from '../LoadingPage.html'
|
import LoadingPage from '../LoadingPage.html'
|
||||||
import { doSearch } from '../../_actions/search'
|
import { doSearch } from '../../_actions/search'
|
||||||
import SearchResults from './SearchResults.html'
|
import SearchResults from './SearchResults.html'
|
||||||
|
import SvgIcon from '../SvgIcon.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
store: () => store,
|
store: () => store,
|
||||||
components: {
|
components: {
|
||||||
LoadingPage,
|
LoadingPage,
|
||||||
SearchResults
|
SearchResults,
|
||||||
|
SvgIcon
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async onSubmit (e) {
|
async onSubmit (e) {
|
||||||
|
@ -74,4 +74,4 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -28,18 +28,14 @@
|
||||||
rel="prefetch"
|
rel="prefetch"
|
||||||
href="/statuses/{originalStatusId}/reblogs"
|
href="/statuses/{originalStatusId}/reblogs"
|
||||||
aria-label={reblogsLabel}>
|
aria-label={reblogsLabel}>
|
||||||
<svg class="status-favs-reblogs-svg">
|
<SvgIcon className="status-favs-reblogs-svg" href="#fa-retweet" />
|
||||||
<use xlink:href="#fa-retweet"/>
|
|
||||||
</svg>
|
|
||||||
<span>{numReblogs}</span>
|
<span>{numReblogs}</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="status-favs-reblogs status-favs"
|
<a class="status-favs-reblogs status-favs"
|
||||||
rel="prefetch"
|
rel="prefetch"
|
||||||
href="/statuses/{originalStatusId}/favorites"
|
href="/statuses/{originalStatusId}/favorites"
|
||||||
aria-label={favoritesLabel}>
|
aria-label={favoritesLabel}>
|
||||||
<svg class="status-favs-reblogs-svg">
|
<SvgIcon className="status-favs-reblogs-svg" href="#fa-star" />
|
||||||
<use xlink:href="#fa-star" />
|
|
||||||
</svg>
|
|
||||||
<span>{numFavs}</span>
|
<span>{numFavs}</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -105,7 +101,7 @@
|
||||||
color: var(--deemphasized-text-color);
|
color: var(--deemphasized-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-favs-reblogs-svg {
|
:global(.status-favs-reblogs-svg) {
|
||||||
fill: var(--deemphasized-text-color);
|
fill: var(--deemphasized-text-color);
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
|
@ -137,6 +133,7 @@
|
||||||
import ExternalLink from '../ExternalLink.html'
|
import ExternalLink from '../ExternalLink.html'
|
||||||
import { store } from '../../_store/store'
|
import { store } from '../../_store/store'
|
||||||
import { absoluteDateFormatter, shortAbsoluteDateFormatter } from '../../_utils/formatters'
|
import { absoluteDateFormatter, shortAbsoluteDateFormatter } from '../../_utils/formatters'
|
||||||
|
import SvgIcon from '../SvgIcon.html'
|
||||||
import { on } from '../../_utils/eventBus'
|
import { on } from '../../_utils/eventBus'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -191,7 +188,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
ExternalLink
|
ExternalLink,
|
||||||
|
SvgIcon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
<div class="status-header-avatar {timelineType === 'pinned' ? 'hidden' : ''}">
|
<div class="status-header-avatar {timelineType === 'pinned' ? 'hidden' : ''}">
|
||||||
<Avatar {account} size="extra-small"/>
|
<Avatar {account} size="extra-small"/>
|
||||||
</div>
|
</div>
|
||||||
<svg class="status-header-svg">
|
<SvgIcon className="status-header-svg" href={icon} />
|
||||||
<use xlink:href={icon}/>
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
<div class="status-header-content">
|
<div class="status-header-content">
|
||||||
{#if timelineType === 'pinned'}
|
{#if timelineType === 'pinned'}
|
||||||
|
@ -50,7 +48,7 @@
|
||||||
margin-left: 19px; /* offset for avatar, 48px - 24px - 5px */
|
margin-left: 19px; /* offset for avatar, 48px - 24px - 5px */
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-header-svg {
|
:global(.status-header-svg) {
|
||||||
min-width: 18px;
|
min-width: 18px;
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
width: 18px;
|
width: 18px;
|
||||||
|
@ -58,7 +56,7 @@
|
||||||
fill: var(--deemphasized-text-color);
|
fill: var(--deemphasized-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-header.status-in-notification .status-header-svg {
|
:global(.status-header.status-in-notification .status-header-svg) {
|
||||||
fill: var(--body-text-color);
|
fill: var(--body-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +96,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
.status-header-svg {
|
:global(.status-header-svg) {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,11 +104,13 @@
|
||||||
<script>
|
<script>
|
||||||
import Avatar from '../Avatar.html'
|
import Avatar from '../Avatar.html'
|
||||||
import AccountDisplayName from '../profile/AccountDisplayName.html'
|
import AccountDisplayName from '../profile/AccountDisplayName.html'
|
||||||
|
import SvgIcon from '../SvgIcon.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Avatar,
|
Avatar,
|
||||||
AccountDisplayName
|
AccountDisplayName,
|
||||||
|
SvgIcon
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
elementId: ({ uuid }) => `status-header-${uuid}`,
|
elementId: ({ uuid }) => `status-header-${uuid}`,
|
||||||
|
|
|
@ -7,9 +7,7 @@
|
||||||
class="status-sensitive-media-button"
|
class="status-sensitive-media-button"
|
||||||
aria-label="Hide sensitive media" >
|
aria-label="Hide sensitive media" >
|
||||||
<div class="svg-wrapper">
|
<div class="svg-wrapper">
|
||||||
<svg class="status-sensitive-media-svg">
|
<SvgIcon className="status-sensitive-media-svg" href="#fa-eye-slash" />
|
||||||
<use xlink:href="#fa-eye-slash" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<MediaAttachments {mediaAttachments} {sensitive} {uuid} />
|
<MediaAttachments {mediaAttachments} {sensitive} {uuid} />
|
||||||
|
@ -23,9 +21,7 @@
|
||||||
Sensitive content. Click to show.
|
Sensitive content. Click to show.
|
||||||
</div>
|
</div>
|
||||||
<div class="svg-wrapper">
|
<div class="svg-wrapper">
|
||||||
<svg class="status-sensitive-media-svg">
|
<SvgIcon className="status-sensitive-media-svg" href="#fa-eye" />
|
||||||
<use xlink:href="#fa-eye" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -135,7 +131,7 @@
|
||||||
.status-sensitive-media-container.status-sensitive-media-shown .svg-wrapper {
|
.status-sensitive-media-container.status-sensitive-media-shown .svg-wrapper {
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
.status-sensitive-media-svg {
|
:global(.status-sensitive-media-svg) {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
fill: var(--mask-svg-fill);
|
fill: var(--mask-svg-fill);
|
||||||
|
@ -144,7 +140,7 @@
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
}
|
}
|
||||||
.status-sensitive-media-container.status-sensitive-media-hidden .status-sensitive-media-svg {
|
:global(.status-sensitive-media-container.status-sensitive-media-hidden .status-sensitive-media-svg) {
|
||||||
fill: var(--deemphasized-text-color);
|
fill: var(--deemphasized-text-color);
|
||||||
background: var(--mask-opaque-bg);
|
background: var(--mask-opaque-bg);
|
||||||
}
|
}
|
||||||
|
@ -152,6 +148,7 @@
|
||||||
<script>
|
<script>
|
||||||
import MediaAttachments from './MediaAttachments.html'
|
import MediaAttachments from './MediaAttachments.html'
|
||||||
import Shortcut from '../shortcut/Shortcut.html'
|
import Shortcut from '../shortcut/Shortcut.html'
|
||||||
|
import SvgIcon from '../SvgIcon.html'
|
||||||
import { store } from '../../_store/store'
|
import { store } from '../../_store/store'
|
||||||
import { registerClickDelegate } from '../../_utils/delegate'
|
import { registerClickDelegate } from '../../_utils/delegate'
|
||||||
import { classname } from '../../_utils/classname'
|
import { classname } from '../../_utils/classname'
|
||||||
|
@ -163,7 +160,8 @@
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
MediaAttachments,
|
MediaAttachments,
|
||||||
Shortcut
|
Shortcut,
|
||||||
|
SvgIcon
|
||||||
},
|
},
|
||||||
store: () => store,
|
store: () => store,
|
||||||
computed: {
|
computed: {
|
||||||
|
|
|
@ -16,9 +16,8 @@
|
||||||
title={instance.switchLabel}
|
title={instance.switchLabel}
|
||||||
aria-pressed={instance.current}
|
aria-pressed={instance.current}
|
||||||
on:click="onSwitchToThisInstance(event, instance.name)">
|
on:click="onSwitchToThisInstance(event, instance.name)">
|
||||||
<svg class="instance-switcher-button-svg">
|
<SvgIcon className="instance-switcher-button-svg"
|
||||||
<use xlink:href="{instance.current ? '#fa-star' : '#fa-star-o'}" />
|
href={instance.current ? '#fa-star' : '#fa-star-o'} />
|
||||||
</svg>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</SettingsListRow>
|
</SettingsListRow>
|
||||||
|
@ -55,7 +54,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: 1px;
|
margin: 1px;
|
||||||
}
|
}
|
||||||
.instance-switcher-button-svg {
|
:global(.instance-switcher-button-svg) {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -69,13 +68,15 @@
|
||||||
import SettingsList from '../../../_components/settings/SettingsList.html'
|
import SettingsList from '../../../_components/settings/SettingsList.html'
|
||||||
import SettingsListRow from '../../../_components/settings/SettingsListRow.html'
|
import SettingsListRow from '../../../_components/settings/SettingsListRow.html'
|
||||||
import SettingsListButton from '../../../_components/settings/SettingsListButton.html'
|
import SettingsListButton from '../../../_components/settings/SettingsListButton.html'
|
||||||
|
import SvgIcon from '../../../_components/SvgIcon.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
SettingsLayout,
|
SettingsLayout,
|
||||||
SettingsList,
|
SettingsList,
|
||||||
SettingsListRow,
|
SettingsListRow,
|
||||||
SettingsListButton
|
SettingsListButton,
|
||||||
|
SvgIcon
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onSwitchToThisInstance (e, instanceName) {
|
onSwitchToThisInstance (e, instanceName) {
|
||||||
|
|
|
@ -4,7 +4,7 @@ const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPl
|
||||||
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin')
|
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin')
|
||||||
const terser = require('./terser.config')
|
const terser = require('./terser.config')
|
||||||
const CircularDependencyPlugin = require('circular-dependency-plugin')
|
const CircularDependencyPlugin = require('circular-dependency-plugin')
|
||||||
const { mode, dev, resolve } = require('./shared.config')
|
const { mode, dev, resolve, inlineSvgs } = require('./shared.config')
|
||||||
|
|
||||||
const output = Object.assign(config.client.output(), {
|
const output = Object.assign(config.client.output(), {
|
||||||
// enables HMR in workers
|
// enables HMR in workers
|
||||||
|
@ -51,6 +51,11 @@ module.exports = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.browser': true,
|
||||||
|
'process.env.NODE_ENV': JSON.stringify(mode),
|
||||||
|
'process.env.INLINE_SVGS': JSON.stringify(inlineSvgs)
|
||||||
|
}),
|
||||||
new webpack.NormalModuleReplacementPlugin(
|
new webpack.NormalModuleReplacementPlugin(
|
||||||
/\/_database\/database\.js$/, // this version plays nicer with IDEs
|
/\/_database\/database\.js$/, // this version plays nicer with IDEs
|
||||||
'./database.prod.js'
|
'./database.prod.js'
|
||||||
|
@ -66,10 +71,6 @@ module.exports = {
|
||||||
requestTimeout: 120000
|
requestTimeout: 120000
|
||||||
})
|
})
|
||||||
] : [
|
] : [
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.browser': true,
|
|
||||||
'process.env.NODE_ENV': JSON.stringify(mode)
|
|
||||||
}),
|
|
||||||
new BundleAnalyzerPlugin({ // generates report.html and stats.json
|
new BundleAnalyzerPlugin({ // generates report.html and stats.json
|
||||||
analyzerMode: 'static',
|
analyzerMode: 'static',
|
||||||
generateStatsFile: true,
|
generateStatsFile: true,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
const webpack = require('webpack')
|
||||||
const config = require('sapper/config/webpack.js')
|
const config = require('sapper/config/webpack.js')
|
||||||
const pkg = require('../package.json')
|
const pkg = require('../package.json')
|
||||||
const { mode, dev, resolve } = require('./shared.config')
|
const { mode, dev, resolve, inlineSvgs } = require('./shared.config')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: config.server.entry(),
|
entry: config.server.entry(),
|
||||||
|
@ -28,5 +29,10 @@ module.exports = {
|
||||||
mode,
|
mode,
|
||||||
performance: {
|
performance: {
|
||||||
hints: false // it doesn't matter if server.js is large
|
hints: false // it doesn't matter if server.js is large
|
||||||
}
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env.INLINE_SVGS': JSON.stringify(inlineSvgs)
|
||||||
|
})
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
const mode = process.env.NODE_ENV
|
const svgs = require('../bin/svgs')
|
||||||
|
|
||||||
|
const inlineSvgs = svgs.filter(_ => _.inline).map(_ => `#${_.id}`)
|
||||||
|
const mode = process.env.NODE_ENV || 'production'
|
||||||
const dev = mode === 'development'
|
const dev = mode === 'development'
|
||||||
|
|
||||||
const resolve = {
|
const resolve = {
|
||||||
|
@ -14,5 +17,6 @@ const resolve = {
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mode,
|
mode,
|
||||||
dev,
|
dev,
|
||||||
resolve
|
resolve,
|
||||||
|
inlineSvgs
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue