feat(app): ship James's tuned sidebar motion defaults (#58151)

This commit is contained in:
James Long
2026-10-22 11:23:43 -04:00
committed by GitHub
Unverified
parent 2493af967d
commit 47d6a9d0e4
2 changed files with 15 additions and 10 deletions
+12 -7
View File
@@ -67,14 +67,14 @@ const jamesFade = motionTuning.easing("sidebars.james.fade", {
label: "Fade",
group,
when: james,
value: [0.44, 0.75, 0.63, 1.03],
value: [0.17, 0.85, 0.63, 1.03],
})
const jamesFadeDuration = motionTuning.number("sidebars.james.fadeDuration", {
label: "Fade duration",
group,
when: james,
value: 0.18,
value: 0.24,
min: 0.05,
max: 0.6,
step: 0.01,
@@ -87,7 +87,7 @@ export const jamesPanelShift = motionTuning.number("sidebars.james.panelShift",
label: "Panel shift",
group,
when: james,
value: 30,
value: 46,
min: 0,
max: 48,
step: 1,
@@ -111,9 +111,9 @@ const layoutSpring = (direction: string, label: string) =>
when: () => james() && jamesLayout() !== "off",
shipped: "smooth",
presets: {
snappy: { duration: 0.12, bounce: 0 },
smooth: { duration: 0.16, bounce: 0 },
calm: { duration: 0.24, bounce: 0 },
snappy: { duration: 0.16, bounce: 0 },
smooth: { duration: 0.24, bounce: 0 },
calm: { duration: 0.32, bounce: 0 },
},
})
@@ -430,7 +430,7 @@ export function createPanelMotion(input: {
{ opacity: [start.opacity, end.opacity] },
{
duration: jamesFadeDuration() * 1000,
easing: `cubic-bezier(${jamesFade().join(", ")})`,
easing: `cubic-bezier(${(open ? jamesFade() : reverseBezier(jamesFade())).join(", ")})`,
fill: "both",
},
),
@@ -519,6 +519,11 @@ function springEasing(tuning: DurationOptions) {
return { duration: ((points.length - 1) * 1000) / 60, easing: `linear(${points.join(", ")})` }
}
/** The curve that plays `curve` backwards in time, so a close looks like its open in reverse. */
function reverseBezier([x1, y1, x2, y2]: readonly number[]) {
return [1 - x2, 1 - y2, 1 - x1, 1 - y1].map((value) => Math.round(value * 1000) / 1000)
}
function anchorX(element: HTMLElement, anchor: Anchor) {
const box = element.getBoundingClientRect()
@@ -385,7 +385,7 @@ it("James opens with the layout first, then shifts the panel in on a spring and
expect(point).toBeCloseTo(1 - (1 + omega * t) * Math.exp(-omega * t), 2)
})
expect(fade.keyframes.opacity).toEqual([0.15, 1])
expect(fade.options).toMatchObject({ duration: 180, easing: "cubic-bezier(0.44, 0.75, 0.63, 1.03)" })
expect(fade.options).toMatchObject({ duration: 240, easing: "cubic-bezier(0.17, 0.85, 0.63, 1.03)" })
expect(panelsMoving()).toBe(true)
const ran: string[] = []
@@ -439,6 +439,6 @@ it("ships the spring as the default sidebar motion, with James one choice away",
expect(knob?.kind).toBe("mode")
expect(knob?.initial).toBe(false)
// The side panel shifts 30px by default; the left sidebar stays at 10px.
expect(motionTuning.list().find((item) => item.id === "sidebars.james.panelShift")?.initial).toBe(30)
// The side panel shifts 46px by default; the left sidebar stays at 10px.
expect(motionTuning.list().find((item) => item.id === "sidebars.james.panelShift")?.initial).toBe(46)
})