diff --git a/dist/index.html b/dist/index.html index df8b7e2..ad7d694 100644 --- a/dist/index.html +++ b/dist/index.html @@ -7188,7 +7188,7 @@ var root_4$3 = /* @__PURE__ */ from_html(``); var root_6$2 = /* @__PURE__ */ from_html(`
`, 1); var root_7$1 = /* @__PURE__ */ from_html(`
Loading radar...
`); -var root_8 = /* @__PURE__ */ from_html(`
`); +var root_8$1 = /* @__PURE__ */ from_html(`
`); var root_9 = /* @__PURE__ */ from_html(`
⏳ Loading lightning...
`); var root_10 = /* @__PURE__ */ from_html(`
`); var root_11 = /* @__PURE__ */ from_html(`
⚡ No recent strikes nearby
`); @@ -7536,7 +7536,7 @@ function PrecipitationRadar($$anchor, $$props) { }); var node_7 = sibling(node_6, 2); var consequent_6 = ($$anchor) => { - var div_8 = root_8(); + var div_8 = root_8$1(); var span_2 = child(div_8); var text_1 = child(span_2); reset(span_2); @@ -8250,9 +8250,10 @@ var root_1 = /* @__PURE__ */ from_html(` `); var root_3 = /* @__PURE__ */ from_html(`
🌍

Welcome to WeatherLens

`); var root_4 = /* @__PURE__ */ from_html(`

Loading weather data...

`); -var root_5 = /* @__PURE__ */ from_html(`
`); -var root_6 = /* @__PURE__ */ from_html(`
`, 1); -var root_7 = /* @__PURE__ */ from_html(`

`); +var root_5 = /* @__PURE__ */ from_html(``); +var root_6 = /* @__PURE__ */ from_html(`
`); +var root_7 = /* @__PURE__ */ from_html(`
`, 1); +var root_8 = /* @__PURE__ */ from_html(`

`); function App($$anchor, $$props) { push($$props, true); let viewMode = /* @__PURE__ */ state(proxy(parseHash(typeof window !== "undefined" ? window.location.hash : ""))); @@ -8270,26 +8271,94 @@ function App($$anchor, $$props) { window.addEventListener("hashchange", onHash); return () => window.removeEventListener("hashchange", onHash); }); - const SWIPE_THRESHOLD = 60; - let touchAnchor = /* @__PURE__ */ state(null); + const SWIPE_THRESHOLD = 70; + const AXIS_THRESHOLD = 12; + const SWIPE_TIMEOUT = 160; + const TAB_LABELS = { + current: "Now", + hourly: "Hourly", + daily: "Daily", + detail: "More", + radar: "Radar" + }; + let contentEl = /* @__PURE__ */ state(null); + let swiping = /* @__PURE__ */ state(false); + let swipeAnchor = /* @__PURE__ */ state(null); + let swipeDX = /* @__PURE__ */ state(0); + let swipeLock = /* @__PURE__ */ state(null); + let settling = /* @__PURE__ */ state(false); + const clampIdx = (i) => Math.min(Math.max(i, 0), VALID_VIEWS.length - 1); + const peekView = /* @__PURE__ */ user_derived(() => get(swiping) && get(swipeLock) === "x" && VALID_VIEWS.includes(get(viewMode)) ? VALID_VIEWS[clampIdx(VALID_VIEWS.indexOf(get(viewMode)) + (get(swipeDX) < 0 ? 1 : -1))] : null); function onSwipeStart(e) { if (get(viewMode) === "radar" || !e.touches || !e.touches[0]) return; - set(touchAnchor, { - x: e.touches[0].clientX, - y: e.touches[0].clientY + const t = e.touches[0]; + set(swipeAnchor, { + x: t.clientX, + y: t.clientY }, true); + set(swipeDX, 0); + set(swipeLock, null); + set(settling, false); + set(swiping, true); } - function onSwipeEnd(e) { - if (get(viewMode) === "radar" || !get(touchAnchor) || !e.changedTouches || !e.changedTouches[0]) return; - const t = e.changedTouches[0]; - const dx = t.clientX - get(touchAnchor).x; - const dy = t.clientY - get(touchAnchor).y; - set(touchAnchor, null); - if (Math.abs(dx) < SWIPE_THRESHOLD || Math.abs(dx) < Math.abs(dy)) return; - const idx = VALID_VIEWS.indexOf(get(viewMode)); - const next = VALID_VIEWS[Math.min(Math.max(idx + (dx < 0 ? 1 : -1), 0), VALID_VIEWS.length - 1)]; - if (next !== get(viewMode)) setView(next); + function onSwipeMove(e) { + if (!get(swiping) || !get(swipeAnchor)) return; + const t = e.touches[0]; + const dx = t.clientX - get(swipeAnchor).x; + const dy = t.clientY - get(swipeAnchor).y; + if (!get(swipeLock)) { + if (Math.abs(dx) > AXIS_THRESHOLD && Math.abs(dx) > Math.abs(dy)) set(swipeLock, "x"); + else if (Math.abs(dy) > AXIS_THRESHOLD) set(swipeLock, "y"); + } + if (get(swipeLock) === "x") { + e.preventDefault(); + set(swipeDX, dx); + } else if (get(swipeLock) === "y") set(swipeDX, 0); } + function finishSwipe(e) { + if (!get(swiping)) return; + const t = e.changedTouches && e.changedTouches[0]; + const dx = get(swipeLock) === "x" ? t ? t.clientX - get(swipeAnchor).x : get(swipeDX) : get(swipeDX); + const dy = t ? t.clientY - get(swipeAnchor).y : 0; + if (get(swipeLock) === "x" && Math.abs(dx) >= SWIPE_THRESHOLD && Math.abs(dx) >= Math.abs(dy) && get(viewMode) !== "radar") { + const idx = VALID_VIEWS.indexOf(get(viewMode)); + const step = dx < 0 ? 1 : -1; + const next = VALID_VIEWS[clampIdx(idx + step)]; + if (next !== get(viewMode)) { + set(settling, true); + set(swipeDX, (get(contentEl) ? get(contentEl).clientWidth : 420) * step * -1); + setTimeout(() => { + setView(next); + set(swiping, false); + set(swipeDX, 0); + set(swipeLock, null); + set(swipeAnchor, null); + set(settling, false); + }, SWIPE_TIMEOUT); + return; + } + } + set(settling, true); + set(swipeDX, 0); + setTimeout(() => { + set(swiping, false); + set(swipeLock, null); + set(swipeAnchor, null); + set(settling, false); + }, SWIPE_TIMEOUT); + } + function cancelSwipe(e) { + if (!get(swiping)) return; + set(settling, true); + set(swipeDX, 0); + setTimeout(() => { + set(swiping, false); + set(swipeLock, null); + set(swipeAnchor, null); + set(settling, false); + }, SWIPE_TIMEOUT); + } + const slideStyle = /* @__PURE__ */ user_derived(() => get(swipeDX) ? `transform: translateX(${get(swipeDX)}px)` : ""); let initDone = /* @__PURE__ */ state(false); let geoError = /* @__PURE__ */ state(""); user_effect(() => { @@ -8361,7 +8430,7 @@ function App($$anchor, $$props) { const newest = updated[updated.length - 1]; if (newest) app$1.selectLocation(newest.id); } - var div = root_7(); + var div = root_8(); var div_1 = child(div); var button = child(div_1); var text = child(button, true); @@ -8441,8 +8510,8 @@ function App($$anchor, $$props) { if (app$1.loading && !app$1.forecastData) $$render(consequent_4); }); var node_8 = sibling(node_7, 2); - var consequent_10 = ($$anchor) => { - var fragment = root_6(); + var consequent_11 = ($$anchor) => { + var fragment = root_7(); var div_8 = first_child(fragment); var button_5 = child(div_8); let classes_1; @@ -8468,45 +8537,68 @@ function App($$anchor, $$props) { let classes_10; reset(div_9); var div_10 = sibling(div_9, 2); - var node_9 = child(div_10); + let classes_11; + var div_11 = child(div_10); + let classes_12; + var node_9 = child(div_11); var consequent_5 = ($$anchor) => { - var div_11 = root_5(); - CurrentWeather(child(div_11), {}); - reset(div_11); - append($$anchor, div_11); + var span_3 = root_5(); + let classes_13; + var text_5 = child(span_3, true); + reset(span_3); + template_effect(() => { + classes_13 = set_class(span_3, 1, "swipe-peek svelte-1n46o8q", null, classes_13, { + "from-left": get(swipeDX) >= 0, + "from-right": get(swipeDX) < 0 + }); + set_text(text_5, TAB_LABELS[get(peekView)]); + }); + append($$anchor, span_3); }; + if_block(node_9, ($$render) => { + if (get(peekView) && TAB_LABELS[get(peekView)]) $$render(consequent_5); + }); + var node_10 = sibling(node_9, 2); var consequent_6 = ($$anchor) => { - var div_12 = root_5(); - HourlyForecast(child(div_12), {}); + var div_12 = root_6(); + CurrentWeather(child(div_12), {}); reset(div_12); append($$anchor, div_12); }; var consequent_7 = ($$anchor) => { - var div_13 = root_5(); - DailyForecast(child(div_13), {}); + var div_13 = root_6(); + HourlyForecast(child(div_13), {}); reset(div_13); append($$anchor, div_13); }; var consequent_8 = ($$anchor) => { - var div_14 = root_5(); - WeatherDetail(child(div_14), {}); + var div_14 = root_6(); + DailyForecast(child(div_14), {}); reset(div_14); append($$anchor, div_14); }; var consequent_9 = ($$anchor) => { - var div_15 = root_5(); - PrecipitationRadar(child(div_15), {}); + var div_15 = root_6(); + WeatherDetail(child(div_15), {}); reset(div_15); append($$anchor, div_15); }; - if_block(node_9, ($$render) => { - if (get(viewMode) === "current") $$render(consequent_5); - else if (get(viewMode) === "hourly") $$render(consequent_6, 1); - else if (get(viewMode) === "daily") $$render(consequent_7, 2); - else if (get(viewMode) === "detail") $$render(consequent_8, 3); - else if (get(viewMode) === "radar") $$render(consequent_9, 4); + var consequent_10 = ($$anchor) => { + var div_16 = root_6(); + PrecipitationRadar(child(div_16), {}); + reset(div_16); + append($$anchor, div_16); + }; + if_block(node_10, ($$render) => { + if (get(viewMode) === "current") $$render(consequent_6); + else if (get(viewMode) === "hourly") $$render(consequent_7, 1); + else if (get(viewMode) === "daily") $$render(consequent_8, 2); + else if (get(viewMode) === "detail") $$render(consequent_9, 3); + else if (get(viewMode) === "radar") $$render(consequent_10, 4); }); + reset(div_11); reset(div_10); + bind_this(div_10, ($$value) => set(contentEl, $$value), () => get(contentEl)); template_effect(() => { classes_1 = set_class(button_5, 1, "nav-btn svelte-1n46o8q", null, classes_1, { active: get(viewMode) === "current" }); classes_2 = set_class(button_6, 1, "nav-btn svelte-1n46o8q", null, classes_2, { active: get(viewMode) === "hourly" }); @@ -8518,6 +8610,9 @@ function App($$anchor, $$props) { classes_8 = set_class(button_12, 1, "tab-btn svelte-1n46o8q", null, classes_8, { active: get(viewMode) === "daily" }); classes_9 = set_class(button_13, 1, "tab-btn svelte-1n46o8q", null, classes_9, { active: get(viewMode) === "detail" }); classes_10 = set_class(button_14, 1, "tab-btn svelte-1n46o8q", null, classes_10, { active: get(viewMode) === "radar" }); + classes_11 = set_class(div_10, 1, "content-area svelte-1n46o8q", null, classes_11, { swiping: get(swiping) }); + classes_12 = set_class(div_11, 1, "swipe-layer svelte-1n46o8q", null, classes_12, { settle: get(settling) }); + set_style(div_11, get(slideStyle)); }); delegated("click", button_5, () => setView("current")); delegated("click", button_6, () => setView("hourly")); @@ -8530,22 +8625,24 @@ function App($$anchor, $$props) { delegated("click", button_13, () => setView("detail")); delegated("click", button_14, () => setView("radar")); delegated("touchstart", div_10, onSwipeStart, void 0, true); - delegated("touchend", div_10, onSwipeEnd); + delegated("touchmove", div_10, onSwipeMove, void 0, true); + delegated("touchend", div_10, finishSwipe); + event("touchcancel", div_10, cancelSwipe); append($$anchor, fragment); }; if_block(node_8, ($$render) => { - if (app$1.forecastData && app$1.selectedLocation) $$render(consequent_10); + if (app$1.forecastData && app$1.selectedLocation) $$render(consequent_11); }); reset(main); - var node_15 = sibling(main, 2); - var consequent_11 = ($$anchor) => { + var node_16 = sibling(main, 2); + var consequent_12 = ($$anchor) => { SettingsDialog($$anchor, { onClose: () => app$1.showSettings = false }); }; - if_block(node_15, ($$render) => { - if (app$1.showSettings) $$render(consequent_11); + if_block(node_16, ($$render) => { + if (app$1.showSettings) $$render(consequent_12); }); - var node_16 = sibling(node_15, 2); - var consequent_12 = ($$anchor) => { + var node_17 = sibling(node_16, 2); + var consequent_13 = ($$anchor) => { AddLocationDialog($$anchor, { onClose: () => { app$1.showAddLocation = false; @@ -8554,8 +8651,8 @@ function App($$anchor, $$props) { onAdd: handleAddLocation }); }; - if_block(node_16, ($$render) => { - if (app$1.showAddLocation) $$render(consequent_12); + if_block(node_17, ($$render) => { + if (app$1.showAddLocation) $$render(consequent_13); }); reset(div); template_effect(() => { @@ -8572,11 +8669,12 @@ function App($$anchor, $$props) { delegate([ "click", "touchstart", + "touchmove", "touchend" ]); //#endregion //#region src/main.js -console.info({ commit_hash: "93e5660a5c76fd41088193f5ca3e3a35cd7478b1" }); +console.info({ commit_hash: "09cea275b7ac2fd46d2184d84524ee1c3ddcbe60" }); mount(App, { target: document.getElementById("app") }); //#endregion