Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix tagmenu oob #636

Merged
merged 4 commits into from
Sep 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions src/lib/actions/stayInView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
export interface StayInViewOptions {
/**
* If the `node` contains an element (like an arrow for menus),
* that should be shifted over to account for any shifting
* of the `node` itself, then pass a selector for it here.
*/
elToShiftSelector?: string;
}

export default function stayInView(node: HTMLElement, opts: StayInViewOptions) {
console.debug("stayInView: Initial opts:", opts);
let { elToShiftSelector } = opts;
let viewDeb: ReturnType<typeof setTimeout>;

/**
* Move element to in view, if it isn't.
*
* Currently only supports moving `node` back into view if oob
* on the left. May need to support other sides and/or resizing
* when `node` still wont fit after shifting it in the future.
*/
const getInView = () => {
const nrect = node.getBoundingClientRect();
const brect = document.body.getBoundingClientRect();
console.debug("stayInView->getInView: Called.", nrect, brect);
if (nrect.x <= brect.x) {
const diff = nrect.x - brect.x + 10;
console.debug(
"stayInView->getInView: Node is out of bounds on the left, shifting forwards to:",
diff
);
node.style.left = `${diff}px`;
if (elToShiftSelector) {
const elToShift = node.querySelector(elToShiftSelector) as HTMLElement;
if (elToShift) {
console.debug("stayInView->getInView: Shifting elToShift.");
const nrectNew = node.getBoundingClientRect();
const arrowDiff = nrectNew.left - nrect.left;
elToShift.style.left = `${elToShift.offsetLeft - arrowDiff}px`;
} else {
console.warn("elToShift not found.", elToShiftSelector);
}
}
}
};

const getInViewDeb = () => {
clearTimeout(viewDeb);
viewDeb = setTimeout(getInView, 200);
};

window.addEventListener("resize", getInViewDeb);
getInView();

return {
update(opts: StayInViewOptions) {
console.debug("stayInView: Opts updated", opts);
elToShiftSelector = opts.elToShiftSelector;
getInView();
},
destroy() {
window.removeEventListener("resize", getInViewDeb);
}
};
}
8 changes: 5 additions & 3 deletions src/lib/tag/TagMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import type { Tag as TagT } from "@/types";
import Tag from "./Tag.svelte";
import DeleteTagModal from "./DeleteTagModal.svelte";
import stayInView from "../actions/stayInView";

export let titleText: string | undefined = undefined;
export let classes: string | undefined = undefined;
Expand All @@ -29,7 +30,8 @@
}
</script>

<div class={[`menu`, classes].join(" ")}>
<div class={[`menu`, classes].join(" ")} use:stayInView={{ elToShiftSelector: "& > .arrow" }}>
<i class="arrow"></i>
<div class="inner">
<div class="title">
<h4 class="norm sm-caps">{titleText ? titleText : "my tags"}</h4>
Expand Down Expand Up @@ -86,15 +88,15 @@
width: 200px;
right: 47px;

&:before {
.arrow {
left: 78px;
}

&.from-add-to-tag-btn {
top: 50px;
right: -78px;

&:before {
.arrow {
left: 87px;
/* The place where this button will be is always dark, so white works for both themes */
border-bottom-color: white;
Expand Down
6 changes: 5 additions & 1 deletion src/norm.scss
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,11 @@
z-index: 50;

// The lil arrow, adjust its pos under each specific menu.
&:before {
&:not(:has(> .arrow)):before,
:global(.arrow) {
// Works by showing arrow in ::before pseudoelement,
// or if more control is needed, applies to any .arrow
// element.
content: "";
position: absolute;
bottom: 100%;
Expand Down