starting perk, settings icons

This commit is contained in:
Renan LE CARO 2025-04-02 10:41:35 +02:00
parent 991e7a1d85
commit 1cf82d6641
12 changed files with 467 additions and 185 deletions

View file

@ -16,10 +16,19 @@ Break colourful bricks, catch bouncing coins and select powerful upgrades !
# changelog # changelog
## next goals ## next goals
- choose starting perks
- wind : move coins based on puck movement not position - wind : move coins based on puck movement not position
## next release ## next release.
- choose starting perks
- fixed issue with reloading with [R] key
- gameover screen restarts in the same game mode
- Trampoline render sides in red.
- tooltips stuck on mobile
- Check in fullscreen worked, otherwise resume playing
## 29058981
- [jaceys] A visual indication of whether a ball has hit a brick this serve (as an option) - [jaceys] A visual indication of whether a ball has hit a brick this serve (as an option)
- Top down /reach: now only the lowest level of N bricks resets combo, and all other bricks do +N combo - Top down /reach: now only the lowest level of N bricks resets combo, and all other bricks do +N combo
@ -106,13 +115,13 @@ Break colourful bricks, catch bouncing coins and select powerful upgrades !
- on mobile, relative movement of the touch would be amplified and added to the puck - on mobile, relative movement of the touch would be amplified and added to the puck
- option : don't pause on mobile when lifting finger - option : don't pause on mobile when lifting finger
- [obigre] Offer to level ups perks separately - [obigre] Offer to level ups perks separately from picking new ones
- https://weblate.org/fr/
- strict sample size red borders ? - strict sample size red borders ?
- on mobile, add an element that feels like it can be "grabbed" and make it shine while writing "Push here to play" - on mobile, add an element that feels like it can be "grabbed" and make it shine while writing "Push here to play"
- add a clickable button to allow sound to play in chrome android - add a clickable button to allow sound to play in chrome android
- see how to do fullscreen on ios, or at least explain to do aA/hide toolbars - see how to do fullscreen on ios, or at least explain to do aA/hide toolbars
- when game resumes near bottom, be unvulnerable for .5s ? , once per level - when game resumes near bottom, be unvulnerable for .5s ? , once per level
- https://weblate.org/fr/ quite annoying actually
## Game engine features ideas ## Game engine features ideas
@ -159,9 +168,10 @@ Break colourful bricks, catch bouncing coins and select powerful upgrades !
- [colin] varied diet - your combo grows by 2 when your ball changes color, but decreses by one when a brick is broken ? - [colin] varied diet - your combo grows by 2 when your ball changes color, but decreses by one when a brick is broken ?
- [colin] trickle up - inverse of reach more or less - [colin] trickle up - inverse of reach more or less
- Dividends — +1 combo per 10 coins lost (band-aid for players who struggle, useful addition when choosing Ascetism) - Dividends — +1 combo per 10 coins lost (band-aid for players who struggle, useful addition when choosing Ascetism)
- +1 combo per bricks / resets after 5/lvl seconds without explosion - +lvl combo per bricks / resets after 5/lvl seconds without explosion ?
- +1 combo per bricks / resets after 5/lvl seconds without coin catch - +lvl combo per bricks / resets after 5/lvl seconds without coin catch ?
- +1 combo per bricks / resets after 5/lvl seconds without coin puck bounce - +lvl combo per bricks / resets after 5/lvl seconds without ball color change ?
- +lvl combo per bricks / resets after 5/lvl seconds without sides hit ?
## Medium difficulty perks ideas ## Medium difficulty perks ideas
- balls collision split them into 4 smaller balls, lvl times (requires rework) - balls collision split them into 4 smaller balls, lvl times (requires rework)

231
dist/index.html vendored

File diff suppressed because one or more lines are too long

View file

@ -1121,5 +1121,47 @@
"bricks": "bbb______tttttt________tttttt________tttttt______bbtttttt______bbbbbttt______bbbbbb________bbbbbb________bbbbbb______ttbbbbbb______tttttbbb______tttttt________tttttt________tttttt______bbtttttt______bbbbbttt______bbbbbb________bbbbbb________bbbbbb________bbbbbb___________bbb______________", "bricks": "bbb______tttttt________tttttt________tttttt______bbtttttt______bbbbbttt______bbbbbb________bbbbbb________bbbbbb______ttbbbbbb______tttttbbb______tttttt________tttttt________tttttt______bbtttttt______bbbbbttt______bbbbbb________bbbbbb________bbbbbb________bbbbbb___________bbb______________",
"svg": null, "svg": null,
"color": "" "color": ""
},
{
"name": "icon:starting_perks",
"size": 8,
"bricks": "_________y_y_y___________l_l_l_l_________l_l_l_l_________l_l_l_l",
"svg": null,
"color": ""
},
{
"name": "icon:download",
"size": 8,
"bricks": "___yy______yy______yy______yy______yy____yyyyyy___yyyy__gggyyggg",
"svg": null,
"color": ""
},
{
"name": "icon:upload",
"size": 8,
"bricks": "gggyyggg__yyyy___yyyyyy____yy______yy______yy______yy______yy___",
"svg": null,
"color": ""
},
{
"name": "icon:coins",
"size": 8,
"bricks": "__yyyy___yyOOyy_yyOOOOyyyOOOOOOyyOOOOOOyyyOOOOyy_yyOOyy___yyyy__",
"svg": null,
"color": ""
},
{
"name": "icon:particles",
"size": 8,
"bricks": "_y_y_y__________y_yyy_y___yyy___y_yyy__y_____y___y_y__y________y",
"svg": null,
"color": ""
},
{
"name": "icon:reset",
"size": 8,
"bricks": "__rrrr___r____r_r_r__r_rr__rr__rr__rr__rr_r__r_r_r____r___rrrr__",
"svg": null,
"color": ""
} }
] ]

View file

@ -1,6 +1,5 @@
* { * {
font-family: font-family: Courier New,
Courier New,
Courier, Courier,
Lucida Sans Typewriter, Lucida Sans Typewriter,
Lucida Typewriter, Lucida Typewriter,
@ -47,6 +46,7 @@ body {
line-height: 20px; line-height: 20px;
max-width: calc(100vw - 80px); max-width: calc(100vw - 80px);
overflow: hidden; overflow: hidden;
&:hover, &:hover,
&:focus { &:focus {
background: rgba(0, 0, 0, 0.3); background: rgba(0, 0, 0, 0.3);
@ -173,10 +173,12 @@ body:not(.has-alert-open) #popup {
filter: saturate(0); filter: saturate(0);
} }
} }
&[disabled] { &[disabled] {
opacity: 0.2; opacity: 0.2;
} }
} }
} }
} }
} }
@ -193,6 +195,7 @@ body:not(.has-alert-open) #popup {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
} }
section { section {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
@ -379,15 +382,18 @@ h2.histogram-title strong {
width: 32px; width: 32px;
height: 32px; height: 32px;
} }
p { p {
flex-grow: 1; flex-grow: 1;
color: rgba(255, 255, 255, 0.6); color: rgba(255, 255, 255, 0.6);
margin: 0 20px; margin: 0 20px;
} }
&.used p strong { &.used p strong {
color: white; color: white;
} }
& > span { & > span {
flex-grow: 0; flex-grow: 0;
@ -410,6 +416,7 @@ h2.histogram-title strong {
background: red; background: red;
} }
} }
&.used { &.used {
opacity: 1; opacity: 1;
} }

View file

@ -68,9 +68,11 @@ import { hoursSpentPlaying } from "./pure_functions";
import { helpMenuEntry } from "./help"; import { helpMenuEntry } from "./help";
import { creativeMode } from "./creative"; import { creativeMode } from "./creative";
import { setupTooltips } from "./tooltip"; import { setupTooltips } from "./tooltip";
import {startingPerkMenuButton} from "./startingPerks";
export function play() { export async function play() {
if (applyFullScreenChoice()) return;
if (await applyFullScreenChoice()) return;
if (gameState.running) return; if (gameState.running) return;
gameState.running = true; gameState.running = true;
gameState.ballStickToPuck = false; gameState.ballStickToPuck = false;
@ -556,8 +558,45 @@ function donationNag(gameState) {
async function openSettingsMenu() { async function openSettingsMenu() {
pause(true); pause(true);
const actions: AsyncAlertAction<() => void>[] = []; const actions: AsyncAlertAction<() => void>[] = [
startingPerkMenuButton()
];
const languages= [
{
text: "English",
value: "en",
icon: icons['UK']
},
{
text: "Français",
value: "fr",
icon: icons['France']
}
]
actions.push({
icon:languages.find(l=>l.value===getCurrentLang())?.icon,
text: t("main_menu.language"),
help: t("main_menu.language_help"),
async value() {
const pick = await asyncAlert({
title: t("main_menu.language"),
content: [
t("main_menu.language_help"),
...languages
],
allowClose: true,
});
if (
pick &&
pick !== getCurrentLang() &&
(await confirmRestart(gameState))
) {
setSettingValue("lang", pick);
window.location.reload();
}
},
});
for (const key of Object.keys(options) as OptionId[]) { for (const key of Object.keys(options) as OptionId[]) {
if (options[key]) if (options[key])
actions.push({ actions.push({
@ -575,33 +614,7 @@ async function openSettingsMenu() {
}); });
} }
actions.push({ actions.push({
text: t("main_menu.reset"), icon:icons['icon:download'],
help: t("main_menu.reset_help"),
async value() {
if (
await asyncAlert({
title: t("main_menu.reset"),
content: [
t("main_menu.reset_instruction"),
{
text: t("main_menu.reset_confirm"),
value: true,
},
{
text: t("main_menu.reset_cancel"),
value: false,
},
],
allowClose: true,
})
) {
localStorage.clear();
window.location.reload();
}
},
});
actions.push({
text: t("main_menu.download_save_file"), text: t("main_menu.download_save_file"),
help: t("main_menu.download_save_file_help"), help: t("main_menu.download_save_file_help"),
async value() { async value() {
@ -650,6 +663,7 @@ async function openSettingsMenu() {
}); });
actions.push({ actions.push({
icon:icons['icon:upload'],
text: t("main_menu.load_save_file"), text: t("main_menu.load_save_file"),
help: t("main_menu.load_save_file_help"), help: t("main_menu.load_save_file_help"),
async value() { async value() {
@ -733,37 +747,9 @@ async function openSettingsMenu() {
}, },
}); });
actions.push({
text: t("main_menu.language"),
help: t("main_menu.language_help"),
async value() {
const pick = await asyncAlert({
title: t("main_menu.language"),
content: [
t("main_menu.language_help"),
{
text: "English",
value: "en",
},
{
text: "Français",
value: "fr",
},
],
allowClose: true,
});
if (
pick &&
pick !== getCurrentLang() &&
(await confirmRestart(gameState))
) {
setSettingValue("lang", pick);
window.location.reload();
}
},
});
actions.push({ actions.push({
icon:icons['icon:coins'],
text: t("main_menu.max_coins", { max: getCurrentMaxCoins() }), text: t("main_menu.max_coins", { max: getCurrentMaxCoins() }),
help: t("main_menu.max_coins_help"), help: t("main_menu.max_coins_help"),
async value() { async value() {
@ -772,6 +758,7 @@ async function openSettingsMenu() {
}, },
}); });
actions.push({ actions.push({
icon:icons['icon:particles'],
text: t("main_menu.max_particles", { max: getCurrentMaxParticles() }), text: t("main_menu.max_particles", { max: getCurrentMaxParticles() }),
help: t("main_menu.max_particles_help"), help: t("main_menu.max_particles_help"),
async value() { async value() {
@ -780,6 +767,34 @@ async function openSettingsMenu() {
}, },
}); });
actions.push({
icon:icons['icon:reset'],
text: t("main_menu.reset"),
help: t("main_menu.reset_help"),
async value() {
if (
await asyncAlert({
title: t("main_menu.reset"),
content: [
t("main_menu.reset_instruction"),
{
text: t("main_menu.reset_confirm"),
value: true,
},
{
text: t("main_menu.reset_cancel"),
value: false,
},
],
allowClose: true,
})
) {
localStorage.clear();
window.location.reload();
}
},
});
const cb = await asyncAlert<() => void>({ const cb = await asyncAlert<() => void>({
title: t("main_menu.settings_title"), title: t("main_menu.settings_title"),
content: [t("main_menu.settings_help"), ...actions], content: [t("main_menu.settings_help"), ...actions],
@ -791,7 +806,7 @@ async function openSettingsMenu() {
} }
} }
function applyFullScreenChoice(): boolean { async function applyFullScreenChoice() {
try { try {
if (!(document.fullscreenEnabled || document.webkitFullscreenEnabled)) { if (!(document.fullscreenEnabled || document.webkitFullscreenEnabled)) {
return false; return false;
@ -799,19 +814,19 @@ function applyFullScreenChoice(): boolean {
if (document.fullscreenElement !== null && !isOptionOn("fullscreen")) { if (document.fullscreenElement !== null && !isOptionOn("fullscreen")) {
if (document.exitFullscreen) { if (document.exitFullscreen) {
document.exitFullscreen(); await document.exitFullscreen();
return true; return true;
} else if (document.webkitCancelFullScreen) { } else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen(); await document.webkitCancelFullScreen();
return true; return true;
} }
} else if (isOptionOn("fullscreen") && !document.fullscreenElement) { } else if (isOptionOn("fullscreen") && !document.fullscreenElement) {
const docel = document.documentElement; const docel = document.documentElement;
if (docel.requestFullscreen) { if (docel.requestFullscreen) {
docel.requestFullscreen(); await docel.requestFullscreen()
return true; return true;
} else if (docel.webkitRequestFullscreen) { } else if (docel.webkitRequestFullscreen) {
docel.webkitRequestFullscreen(); await docel.webkitRequestFullscreen();
return true; return true;
} }
} }
@ -926,6 +941,9 @@ document.addEventListener("keydown", async (e) => {
let pageLoad = new Date(); let pageLoad = new Date();
document.addEventListener("keyup", async (e) => { document.addEventListener("keyup", async (e) => {
const focused = document.querySelector("button:focus"); const focused = document.querySelector("button:focus");
if (e.key in pressed) { if (e.key in pressed) {
setKeyPressed(e.key, 0); setKeyPressed(e.key, 0);
@ -950,7 +968,7 @@ document.addEventListener("keyup", async (e) => {
} else if ( } else if (
e.key.toLowerCase() === "r" && e.key.toLowerCase() === "r" &&
!alertsOpen && !alertsOpen &&
pageLoad > Date.now() + 1000 pageLoad < Date.now() - 500
) { ) {
// When doing ctrl + R in dev to refresh, i don't want to instantly restart a run // When doing ctrl + R in dev to refresh, i don't want to instantly restart a run
if (await confirmRestart(gameState)) { if (await confirmRestart(gameState)) {

View file

@ -136,6 +136,7 @@ export function gameOver(title: string, intro: string) {
}).then(() => }).then(() =>
restart({ restart({
levelToAvoid: currentLevelInfo(gameState).name, levelToAvoid: currentLevelInfo(gameState).name,
mode:gameState.mode
}), }),
); );
} }

View file

@ -1732,6 +1732,66 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>starting_perks</name>
<description/>
<comment/>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>starting_perks_checked</name>
<description/>
<comment/>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>starting_perks_help</name>
<description/>
<comment/>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>starting_perks_unchecked</name>
<description/>
<comment/>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>title</name> <name>title</name>
<description/> <description/>

View file

@ -110,6 +110,10 @@
"main_menu.show_stats_help": "Coins, time, bounces, misses", "main_menu.show_stats_help": "Coins, time, bounces, misses",
"main_menu.sounds": "Game sounds", "main_menu.sounds": "Game sounds",
"main_menu.sounds_help": "Can slow down some phones.", "main_menu.sounds_help": "Can slow down some phones.",
"main_menu.starting_perks": "Starting perks",
"main_menu.starting_perks_checked": "When you start a new game, one of those perks will be give to you. You can click the list to exclude some perks from the pool.",
"main_menu.starting_perks_help": "Choose possible starting upgrades",
"main_menu.starting_perks_unchecked": "The perks below are not offered as starting perks, but you can click to add them to the pool. ",
"main_menu.title": "Breakout 71", "main_menu.title": "Breakout 71",
"main_menu.unlocks": "Unlocked content", "main_menu.unlocks": "Unlocked content",
"main_menu.unlocks_help": "Try perks and levels you unlocked", "main_menu.unlocks_help": "Try perks and levels you unlocked",

View file

@ -110,6 +110,10 @@
"main_menu.show_stats_help": "Pièces, temps, rebonds, ratés", "main_menu.show_stats_help": "Pièces, temps, rebonds, ratés",
"main_menu.sounds": "Sons du jeu", "main_menu.sounds": "Sons du jeu",
"main_menu.sounds_help": "Ralentis certains téléphones.", "main_menu.sounds_help": "Ralentis certains téléphones.",
"main_menu.starting_perks": "Avantages de départ",
"main_menu.starting_perks_checked": "Lorsque vous démarrez une nouvelle partie, l'un de ces avantages vous sera attribué. Vous pouvez cliquer sur la liste pour exclure certains avantages de la sélection.",
"main_menu.starting_perks_help": "Choisissez les avantages de départ",
"main_menu.starting_perks_unchecked": "Les avantages ci-dessous ne sont pas proposés comme avantages de départ, mais vous pouvez cliquer pour les ajouter aux avantages de départ possibles.",
"main_menu.title": "Breakout 71", "main_menu.title": "Breakout 71",
"main_menu.unlocks": "Contenu débloqué", "main_menu.unlocks": "Contenu débloqué",
"main_menu.unlocks_help": "Essayez les éléments débloqués", "main_menu.unlocks_help": "Essayez les éléments débloqués",

View file

@ -397,18 +397,16 @@ export function render(gameState: GameState) {
ctx.globalCompositeOperation = "source-over"; ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = gameState.perks.unbounded ? 0.1 : 1; ctx.globalAlpha = gameState.perks.unbounded ? 0.1 : 1;
let redLeftSide = hasCombo &&!gameState.perks.unbounded&& (gameState.perks.left_is_lava || gameState.perks.trampoline)
let redRightSide = hasCombo &&!gameState.perks.unbounded&& (gameState.perks.right_is_lava || gameState.perks.trampoline)
let redTop = hasCombo && gameState.perks.unbounded<=2 && (gameState.perks.top_is_lava || gameState.perks.trampoline)
if (gameState.offsetXRoundedDown) { if (gameState.offsetXRoundedDown) {
// draw outside of gaming area to avoid capturing borders in recordings // draw outside of gaming area to avoid capturing borders in recordings
ctx.fillStyle =
hasCombo && gameState.perks.left_is_lava ? "red" : gameState.puckColor;
drawStraightLine( drawStraightLine(
ctx, ctx,
gameState, gameState,
(hasCombo && (redLeftSide && "red") ||
gameState.perks.left_is_lava &&
!gameState.perks.unbounded &&
"red") ||
"white", "white",
gameState.offsetX - 1, gameState.offsetX - 1,
0, 0,
@ -420,10 +418,7 @@ export function render(gameState: GameState) {
drawStraightLine( drawStraightLine(
ctx, ctx,
gameState, gameState,
(hasCombo && (redRightSide && "red") ||
gameState.perks.right_is_lava &&
!gameState.perks.unbounded &&
"red") ||
"white", "white",
width - gameState.offsetX + 1, width - gameState.offsetX + 1,
0, 0,
@ -432,15 +427,11 @@ export function render(gameState: GameState) {
gameState.perks.unbounded ? 0.1 : 1, gameState.perks.unbounded ? 0.1 : 1,
); );
} else { } else {
ctx.fillStyle = "red";
drawStraightLine( drawStraightLine(
ctx, ctx,
gameState, gameState,
(hasCombo && (redLeftSide && "red") ||
gameState.perks.left_is_lava &&
!gameState.perks.unbounded &&
"red") ||
"", "",
0, 0,
0, 0,
@ -452,10 +443,7 @@ export function render(gameState: GameState) {
drawStraightLine( drawStraightLine(
ctx, ctx,
gameState, gameState,
(hasCombo && (redRightSide && "red") ||
gameState.perks.right_is_lava &&
!gameState.perks.unbounded &&
"red") ||
"", "",
width - 1, width - 1,
0, 0,
@ -464,15 +452,14 @@ export function render(gameState: GameState) {
1, 1,
); );
} }
if(redTop)
ctx.globalAlpha = gameState.perks.unbounded > 1 ? 0.1 : 1;
drawStraightLine( drawStraightLine(
ctx, ctx,
gameState, gameState,
(hasCombo && gameState.perks.top_is_lava && "red") || "", "red",
gameState.offsetXRoundedDown, gameState.perks.unbounded ? 0 : gameState.offsetXRoundedDown,
1, 1,
width - gameState.offsetXRoundedDown, gameState.perks.unbounded ? width : width - gameState.offsetXRoundedDown,
1, 1,
1, 1,
); );

54
src/startingPerks.ts Normal file
View file

@ -0,0 +1,54 @@
import {asyncAlert} from "./asyncAlert";
import {PerkId, Upgrade} from "./types";
import {t} from "./i18n/i18n";
import {icons, upgrades} from "./loadGameData";
import {getSettingValue, getTotalScore, setSettingValue} from "./settings";
export function startingPerkMenuButton(){
return {
icon:icons['icon:starting_perks'],
text:t('main_menu.starting_perks'),
help:t('main_menu.starting_perks_help'),
async value(){
await openStartingPerksEditor()
}
}
}
function isChecked(u:Upgrade):boolean{
return getSettingValue('start_with_'+u.id, u.giftable)
}
export async function openStartingPerksEditor(){
const ts=getTotalScore()
const avaliable=upgrades.filter(u=>!u.requires && !['instant_upgrade'].includes(u.id) && u.threshold<=ts)
const starting = avaliable.filter(u=>isChecked(u))
const buttons=avaliable
.map(u=> {
const checked = isChecked(u);
return {
icon: u.icon,
text: u.name,
tooltip: u.help(1),
value:u,
disabled:checked && starting.length<2,
checked
}
})
const perk :Upgrade|null|void= await asyncAlert({
title:t('main_menu.starting_perks'),
actionsAsGrid:true,
content:[
t('main_menu.starting_perks_checked'),
...buttons.filter(b=>b.checked),
t('main_menu.starting_perks_unchecked'),
...buttons.filter(b=>!b.checked),
]
})
if(perk){
setSettingValue('start_with_'+perk.id,!isChecked(perk))
openStartingPerksEditor()
}
}

View file

@ -7,12 +7,18 @@ export function setupTooltips() {
return; return;
} }
function updateTooltipPosition(e: MouseEvent) { function updateTooltipPosition(e: MouseEvent) {
tooltip.style.transform = tooltip.style.transform =
`translate(${e.clientX}px,${e.clientY + 20}px) ` + `translate(${e.clientX}px,${e.clientY + 20}px) ` +
(e.clientX > window.innerWidth / 2 ? " translate(-100%,0)" : ""); (e.clientX > window.innerWidth / 2 ? " translate(-100%,0)" : "");
} }
function closeToolTip(){
tooltip.style.display = "none";
hovering=null
}
let hovering:HTMLElement|null=null
document.body.addEventListener( document.body.addEventListener(
"mouseenter", "mouseenter",
(e: MouseEvent) => { (e: MouseEvent) => {
@ -21,15 +27,24 @@ export function setupTooltips() {
parent = parent.parentElement; parent = parent.parentElement;
} }
if (parent?.hasAttribute("data-tooltip")) { if (parent?.hasAttribute("data-tooltip")) {
tooltip.innerHTML = parent?.getAttribute("data-tooltip"); hovering=parent as HTMLElement
tooltip.innerHTML = hovering.getAttribute("data-tooltip") || '';
tooltip.style.display = ""; tooltip.style.display = "";
updateTooltipPosition(e); updateTooltipPosition(e);
} else { } else {
tooltip.style.display = "none"; closeToolTip()
} }
}, },
true, true,
); );
setInterval(()=>{
if(hovering){
if(!document.body.contains(hovering)){
closeToolTip()
}
}
},200)
document.body.addEventListener( document.body.addEventListener(
"mousemove", "mousemove",
(e) => { (e) => {
@ -42,8 +57,7 @@ export function setupTooltips() {
document.body.addEventListener( document.body.addEventListener(
"mouseleave", "mouseleave",
(e) => { (e) => {
// tooltip.style.display = 'none'; closeToolTip()
}, }
true,
); );
} }