diff --git a/package.json b/package.json index cf2cdd1..78f04fe 100644 --- a/package.json +++ b/package.json @@ -13,13 +13,16 @@ }, "dependencies": { "compression": "^1.7.1", + "eases-jsnext": "^1.0.10", "polka": "^0.4.0", "sapper": "^0.14.0", - "sirv": "^0.1.1" + "sirv": "^0.1.1", + "svelte-transitions": "^1.2.0", + "yootils": "^0.0.9" }, "devDependencies": { "npm-run-all": "^4.1.2", - "svelte": "^2.0.0", + "svelte": "^2.9.0", "svelte-loader": "^2.9.0", "webpack": "^4.7.0" } diff --git a/routes/blog/[slug].html b/routes/blog/[slug].html index 27354be..ab22608 100644 --- a/routes/blog/[slug].html +++ b/routes/blog/[slug].html @@ -2,13 +2,23 @@ {post.title} -

{post.title}

+
+

{post.title}

-
- {@html post.html} +
+ {@html post.html} +
\ No newline at end of file diff --git a/routes/blog/_crossfade.js b/routes/blog/_crossfade.js new file mode 100644 index 0000000..81a7efd --- /dev/null +++ b/routes/blog/_crossfade.js @@ -0,0 +1,82 @@ +import * as eases from 'eases-jsnext'; +import * as yootils from 'yootils'; + +export default function crossfade({ fallback }) { + let requested = new Map(); + let provided = new Map(); + + function crossfade(from, node) { + const to = node.getBoundingClientRect(); + console.log({ from, to }); + const dx = from.left - to.left; + const dy = from.top - to.top; + + const dsx = (from.right - from.left) / (to.right - to.left); + const dsy = (from.bottom - from.top) / (to.bottom - to.top); + + console.log({ dsx, dsy }); + + const sx = yootils.linearScale([0, 1], [dsx, 1]); + const sy = yootils.linearScale([0, 1], [dsy, 1]); + + const style = getComputedStyle(node); + const transform = style.transform === 'none' ? '' : style.transform; + + return { + duration: 4000, + easing: eases.quintOut, + css: (t, u) => ` + opacity: ${t}; + transform-origin: 0 0; + transform: ${transform} translate(${u * dx}px,${u * dy}px) scale(${sx(t)}, ${sy(t)}); + `, + tick: (t, u) => { + // console.log({ + // sx: 1 + u * dsx, + // sy: 1 + u * dsy, + // }); + } + }; + } + + return { + send(node, params) { + provided.set(params.key, { + rect: node.getBoundingClientRect() + }); + + return () => { + if (requested.has(params.key)) { + const { rect } = requested.get(params.key); + requested.delete(params.key); + + return crossfade(rect, node); + } + + // if the node is disappearing altogether + // (i.e. wasn't claimed by the other list) + // then we need to supply an outro + provided.delete(params.key); + return fallback(node, params); + }; + }, + + receive(node, params) { + requested.set(params.key, { + rect: node.getBoundingClientRect() + }); + + return () => { + if (provided.has(params.key)) { + const { rect } = provided.get(params.key); + provided.delete(params.key); + + return crossfade(rect, node); + } + + requested.delete(params.key); + return fallback(node, params); + }; + } + }; +} \ No newline at end of file diff --git a/routes/blog/_move.js b/routes/blog/_move.js new file mode 100644 index 0000000..3fbd76e --- /dev/null +++ b/routes/blog/_move.js @@ -0,0 +1,75 @@ +import * as eases from 'eases-jsnext'; +import * as yootils from 'yootils'; + +export default function move({ fallback }) { + let requested = new Map(); + let provided = new Map(); + + function move(from, node) { + const to = node.getBoundingClientRect(); + const dx = from.left - to.left; + const dy = from.top - to.top; + + const dsx = (from.right - from.left) / (to.right - to.left); + const dsy = (from.bottom - from.top) / (to.bottom - to.top); + + const sx = yootils.linearScale([0, 1], [dsx, 1]); + const sy = yootils.linearScale([0, 1], [dsy, 1]); + + const style = getComputedStyle(node); + const transform = style.transform === 'none' ? '' : style.transform; + + return { + duration: 400, + easing: eases.quintOut, + css: (t, u) => ` + transform-origin: 0 0; + transform: ${transform} translate(${u * dx}px,${u * dy}px) scale(${sx(t)}, ${sy(t)}); + ` + }; + } + + return { + send(node, params) { + provided.set(params.key, { + rect: node.getBoundingClientRect() + }); + + return () => { + if (requested.has(params.key)) { + const { rect } = requested.get(params.key); + requested.delete(params.key); + + return { + duration: 0, + css: () => `opacity: 0` + }; + } + + // if the node is disappearing altogether + // (i.e. wasn't claimed by the other list) + // then we need to supply an outro + provided.delete(params.key); + return fallback(node, params); + }; + }, + + receive(node, params) { + requested.set(params.key, { + rect: node.getBoundingClientRect() + }); + + return () => { + if (provided.has(params.key)) { + const { rect } = provided.get(params.key); + provided.delete(params.key); + + return move(rect, node); + } + + requested.delete(params.key); + return fallback(node, params); + }; + } + }; +} \ No newline at end of file diff --git a/routes/blog/_transitions.js b/routes/blog/_transitions.js new file mode 100644 index 0000000..975f227 --- /dev/null +++ b/routes/blog/_transitions.js @@ -0,0 +1,12 @@ +import move from './_move.js'; + +const { send, receive } = move({ + fallback(node) { + return { + duration: 0, + css: t => `opacity: ${t}` + }; + } +}); + +export { send, receive }; \ No newline at end of file diff --git a/routes/blog/index.html b/routes/blog/index.html index f1c80ac..d0891f8 100644 --- a/routes/blog/index.html +++ b/routes/blog/index.html @@ -2,31 +2,54 @@ Blog -

Recent posts

+
+

Recent posts

- + +
\ No newline at end of file diff --git a/webpack/client.config.js b/webpack/client.config.js index 9e330c5..3190b69 100644 --- a/webpack/client.config.js +++ b/webpack/client.config.js @@ -20,7 +20,8 @@ module.exports = { options: { dev: isDev, hydratable: true, - hotReload: true + hotReload: true, + nestedTransitions: true } } }