diff --git a/src/lib/click_outside.ts b/src/lib/click_outside.ts index f857ce4e3458c1836e2830c622df83fb6be125d2..bea7216423d1d47adad7e914932e122afd1945d1 100644 --- a/src/lib/click_outside.ts +++ b/src/lib/click_outside.ts @@ -13,7 +13,7 @@ export const clickOutside = ( if ( node && !node.contains(event.target as Node) && - options.excluded?.every( + (options.excluded ?? []).every( (excludeNode) => !excludeNode.contains(event.target as Node), ) && !event.defaultPrevented diff --git a/src/lib/components/NavBar.svelte b/src/lib/components/NavBar.svelte index 60ff03e9ea0b916fed3b923aff95ceb83fb809df..7d3840e99da8a1affc6ff65fe363092b09f9dc29 100644 --- a/src/lib/components/NavBar.svelte +++ b/src/lib/components/NavBar.svelte @@ -13,20 +13,62 @@ import { browser } from "$app/environment" import { goto } from "$app/navigation" import { page } from "$app/stores" - import PersistentPopover from "$lib/components/PersistentPopover.svelte" import NavBarSearch from "$lib/components/search/NavBarSearch.svelte" + import type { DisplayMode } from "$lib/displays" import { trackSearchVariable } from "$lib/matomo" import type { NavbarConfig } from "$lib/navbar" import WithLinkedVariablesSearchWorker from "$lib/search/search_worker_variables_with_linked?worker" import { newSimulationUrl } from "$lib/urls" - import type { DisplayMode } from "$lib/displays" - const isSearchActive = getContext("isSearchActive") as Writable<boolean> + const dispositifsTypes = [ + { + title: "Impôt sur le revenu", + icon: "picto-impot-sur-le-revenu.png", + parametersVariableName: "irpp_economique", + }, + { + title: "Revenu de solidarité active", + icon: "illustration-rsa.png", + parametersVariableName: "rsa", + }, + { + title: "Contribution sociale généralisée (CSG) prélevée sur les salaires", + icon: "picto-csg-salaires.png", + parametersVariableName: "csg_salaire", + }, + { + title: "Allocations familiales", + icon: "picto-allocations-familiales.png", + parametersVariableName: "af_nettes_crds", + }, + { + title: + "Contribution sociale généralisée (CSG) prélevée sur les retraites", + icon: "picto-csg-retraites.png", + parametersVariableName: "csg_retraite", + }, + { + title: "Prime de partage de la valeur", + icon: "illustration-pepa.png", + parametersVariableName: "prime_partage_valeur_exoneree", + }, + { + title: "Taxes sur les carburants", + icon: "illustration-ticpe.png", + parametersVariableName: "essence_sp95_e10_ticpe", + }, + { + title: "Exonération TO-DE", + icon: "illustration-exoneration-tode.png", + parametersVariableName: "exoneration_cotisations_employeur_tode", + }, + ] + const searchActive = getContext("searchActive") as Writable<boolean> let isSearchInProgress = false - let openMobileMenu = false - let openUserMenu = false + let focused = false let pendingQuery: string | null = null const portalUrl = $page.data.portalUrl + let preventBlur = false const searchParameterName = getContext("searchParameterName") as Writable< string | undefined > @@ -58,13 +100,11 @@ $: ({ authenticationEnabled, user } = data) - $: $isSearchActive = searchQuery != undefined && searchQuery.length > 0 - $: loginUrl = `/auth/prepare?action=login` $: logoutUrl = `/auth/prepare?action=logout` - $: if ($isSearchActive) { + $: if ($searchActive) { search(searchQuery) } else { searchResults = [] @@ -92,9 +132,9 @@ } </script> +<!--class:relative={$navbarConfig.position === "relative"}--> <nav class="z-50 w-full md:top-0" - class:relative={$navbarConfig.position === "relative"} class:fixed={$navbarConfig.position === "fixed"} > <div @@ -200,7 +240,16 @@ out:fade={{ duration: 100 }} > <!-- Bloc centre pour la barre de recherche --> - <NavBarSearch isSearchActive={$isSearchActive} bind:searchQuery /> + <NavBarSearch + bind:active={$searchActive} + bind:query={searchQuery} + on:blur={() => { + if (!preventBlur) { + focused = false + } + }} + on:focus={() => (focused = true)} + /> </div> {/if} @@ -297,14 +346,14 @@ </li> {:else} <!-- User profile + se déconnecter --> - <li> - <PersistentPopover - bind:open={openUserMenu} - initialPlacement="bottom-end" - > - <button - slot="activator" - class="rounded py-1 px-2 text-sm capitalize text-white hover:bg-gray-400 hover:bg-opacity-20 hover:text-white focus:outline-none" + <Menu let:open> + <MenuButton> + <div + class="rounded-lg px-1 text-sm capitalize text-white hover:bg-gray-400 hover:bg-opacity-20 active:bg-gray-400 active:bg-opacity-40 hover:text-white focus:outline-none" + class:bg-gray-400={open} + class:bg-opacity-40={open} + class:hover:bg-opacity-50={open} + class:active:bg-opacity-70={open} > <iconify-icon class="align-[-0.4rem] text-2xl" @@ -315,25 +364,24 @@ <span class="hidden xl:flex"> {user.preferred_username.split("@")[0]} </span> - </button> - - <div - slot="content" - class="m-2 rounded bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none" + </div> + </MenuButton> + <MenuItems + class="absolute right-2 top-14 z-50 rounded bg-white text-black shadow-xl ring-1 ring-black ring-opacity-5 focus:outline-none" + > + <MenuItem + as="button" + class="flex gap-1 rounded-sm border-b px-4 py-3 text-sm uppercase text-gray-600 hover:bg-gray-300 hover:bg-opacity-20 hover:text-black focus:outline-none" + on:click={() => goto(logoutUrl)} > - <button - class="flex gap-1 rounded-sm border-b px-4 py-3 text-sm uppercase text-gray-600 hover:bg-gray-300 hover:bg-opacity-20 hover:text-black focus:outline-none" - on:click={() => goto(logoutUrl)} + <span class="hidden whitespace-nowrap pl-1 md:inline-block" + >Se déconnecter</span > - <span class="hidden whitespace-nowrap pl-1 md:inline-block" - >Se déconnecter</span - > - <iconify-icon class="text-lg" icon="ri-logout-box-r-line" /> - </button> - </div> - </PersistentPopover> - </li> + <iconify-icon class="text-lg" icon="ri-logout-box-r-line" /> + </MenuItem> + </MenuItems> + </Menu> {/if} {/if} </ul> @@ -469,45 +517,82 @@ </div> </div> - <NavBarSearch bind:searchQuery isSearchActive={$isSearchActive} /> + <NavBarSearch + bind:active={$searchActive} + bind:query={searchQuery} + on:blur={() => { + if (!preventBlur) { + focused = false + } + }} + on:focus={() => (focused = true)} + /> </div> </div> - {#if searchQuery?.length > 0} + {#if focused || $searchActive} + <div + class="absolute inset-0 -z-10 bg-[rgba(0,0,0,.3)] transition-all" + ></div> <div class="absolute top-24 w-full overflow-hidden rounded-b-lg border bg-white shadow-lg md:left-[calc((100%-350px)/2)] md:top-12 md:w-[350px] lg:left-[calc((100%-500px)/2)] lg:w-[500px] 2xl:left-[calc((100%-600px)/2)] 2xl:top-14 2xl:w-[600px]" > - <ul class="max-h-56 list-none overflow-y-auto py-2 md:max-h-[80vh]"> - {#if searchResults.length > 0} - {#each searchResults as variable, index (`found_variable_$${index}`)} - <li> - <button - class="flex w-full flex-col px-8 py-3 hover:bg-gray-200 2xl:py-4" - on:click={() => { - trackSearchVariable( - searchQuery, - variable.name, - searchResults.length, - ) - searchQuery = "" - $searchParameterName = variable.name - }} - > - <span - class="flex-shrink-0 text-start text-lg font-bold 2xl:text-xl" + {#if $searchActive} + <ul class="max-h-56 list-none overflow-y-auto py-2 md:max-h-[80vh]"> + {#if searchResults.length > 0} + {#each searchResults as variable, index (`found_variable_$${index}`)} + <li> + <button + class="flex w-full flex-col px-8 py-3 hover:bg-gray-200 2xl:py-4" + on:click={() => { + trackSearchVariable( + searchQuery, + variable.name, + searchResults.length, + ) + searchQuery = "" + $searchParameterName = variable.name + }} > - {variable.short_label ?? variable.label ?? variable.name} - </span> - {#if variable.short_label !== undefined && variable.short_label !== variable.label} - <span class="text-start">{variable.label}</span> - {/if} - </button> - </li> - {/each} - {:else} - <li class="px-8 py-3 2xl:py-4">Aucun résultat trouvé</li> - {/if} - </ul> + <span + class="flex-shrink-0 text-start font-bold text-lg 2xl:text-xl" + > + {variable.short_label ?? variable.label ?? variable.name} + </span> + {#if variable.short_label !== undefined && variable.short_label !== variable.label} + <span class="text-start">{variable.label}</span> + {/if} + </button> + </li> + {/each} + {:else} + <li class="px-8 py-3 2xl:py-4">Aucun résultat trouvé</li> + {/if} + </ul> + {:else} + {#each dispositifsTypes as dispositif} + <button + class="w-full flex items-center gap-5 px-3 py-2 2xl:py-3 hover:bg-gray-200/70 active:bg-gray-200 transition" + on:click={() => { + $searchParameterName = dispositif.parametersVariableName + focused = false + }} + on:mousedown={() => (preventBlur = true)} + on:touchstart={() => (preventBlur = true)} + on:mouseup={() => (preventBlur = false)} + on:touchend={() => (preventBlur = false)} + > + <img + class="max-h-8 md:max-h-10" + src={dispositif.icon} + alt="Icône {dispositif.title}" + /> + <span class="font-bold text-start text-lg 2xl:text-xl"> + {dispositif.title} + </span> + </button> + {/each} + {/if} </div> {/if} </nav> diff --git a/src/lib/components/search/NavBarSearch.svelte b/src/lib/components/search/NavBarSearch.svelte index 32370dc0ec2a353319f38c5a85bacc596df05da5..c3fa0ea6897a3653b510dcaa1d393cfe578708fb 100644 --- a/src/lib/components/search/NavBarSearch.svelte +++ b/src/lib/components/search/NavBarSearch.svelte @@ -1,6 +1,8 @@ <script lang="ts"> - export let isSearchActive: boolean - export let searchQuery: string + export let active: boolean + export let query: string = "" + + $: active = query.length > 0 </script> <section class="flex items-center h-12 pt-1.5 pb-2 md:p-0 md:h-full"> @@ -14,20 +16,20 @@ /> <input autocomplete="off" + bind:value={query} class="w-full px-1 py-1.5 md:px-3 md:py-2 border-none bg-transparent text-sm text-gray-900 placeholder-gray-400 !ring-transparent focus:outline-none 2xl:text-base" + on:blur + on:focus placeholder="impôt sur le revenu, CSG, ..." type="search" - bind:value={searchQuery} /> - {#if isSearchActive} - <iconify-icon - class="md:mx-1 cursor-pointer self-center p-1 text-black" - icon="ri-close-line" - width="20" - height="20" - on:click={() => (searchQuery = "")} - on:keyup - /> + {#if active} + <button + class="self-center p-1.5 hover:bg-black hover:bg-opacity-10 active:bg-black active:bg-opacity-20 rounded-full text-sm transition-all duration-200 ease-out-back" + on:click={() => (query = "")} + > + <iconify-icon class="block text-xl" icon="ri-close-line" /> + </button> {/if} </div> </section> diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index b22f07b011353d297f99fc11d71b0d13451658fa..1a87ee0572f18327be9d1c458957a9873317c299 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -190,8 +190,8 @@ /* * Search * */ - const isSearchActive: Writable<boolean> = writable(false) - setContext("isSearchActive", isSearchActive) + const searchActive: Writable<boolean> = writable(false) + setContext("searchActive", searchActive) const searchParameterName: Writable<string | undefined> = writable(undefined) setContext("searchParameterName", searchParameterName) @@ -1420,7 +1420,7 @@ <div class="flex flex-col flex-nowrap md:h-screen" - class:h-screen={$isSearchActive} + class:h-screen={$searchActive} > <NavBar /> diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index cfe1e140ba35ce03e30a2088f3ca6ae7c0ac17c7..df0e4c5824a8c273e843bd982610f3ea4c01faac 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -164,7 +164,6 @@ > let isBudgetConnexionModalOpen = false let isBudgetSharingModalOpen = false - const isSearchActive = getContext("isSearchActive") as Writable<boolean> let isTestCaseSelectModalOpen = false let isUserModificationsOpen = false setContext("newSelfTargetAProps", newSelfTargetAProps) @@ -175,6 +174,7 @@ const requestedCalculations = getContext( "requestedCalculations", ) as Writable<RequestedCalculations> + const searchActive = getContext("searchActive") as Writable<boolean> const searchParameterName = getContext("searchParameterName") as Writable< string | undefined > @@ -928,9 +928,8 @@ <div bind:this={clipboardElement} /> <main - class="bg-graph-paper flex h-full flex-1 overflow-x-clip after:absolute after:inset-0 after:z-10 after:bg-[rgba(0,0,0,.3)] after:transition-all md:overflow-hidden" - class:after:content-none={!$isSearchActive} - class:overflow-hidden={$isSearchActive} + class="bg-graph-paper flex h-full flex-1 overflow-x-clip md:overflow-hidden" + class:overflow-hidden={$searchActive} > <div class="flex flex-[1_0_100%] flex-col overflow-x-clip transition-transform duration-500 ease-in-out-quart md:overflow-hidden" @@ -1128,9 +1127,20 @@ in:fade={{ delay: 150, duration: 150 }} > {#if !displayMode.budget} - <button - class="w-full flex flex-col gap-1 mt-6 px-6 py-3 lx-card-underline-le-vert" - > + <!-- <button--> + <!-- class="w-full flex flex-col gap-1 mt-6 px-6 py-3 lx-card-underline-le-vert"--> + <!-- >--> + <!-- <span--> + <!-- class="text-start text-lg 2xl:text-xl font-bold"--> + <!-- >--> + <!-- Utiliser la recherche ↗️--> + <!-- </span>--> + <!-- <span class="text-start">--> + <!-- La barre de recherche centrale permet de changer de--> + <!-- dispositif--> + <!-- </span>--> + <!-- </button>--> + <div class="w-full flex flex-col gap-1 mt-10"> <span class="text-start text-lg 2xl:text-xl font-bold" > @@ -1140,7 +1150,7 @@ La barre de recherche centrale permet de changer de dispositif </span> - </button> + </div> <div class="flex gap-9 m-10"> <hr class="mt-5 flex-1 border-dashed border-black" /> <span @@ -1411,7 +1421,7 @@ > <li class="w-1/2 md:w-auto flex justify-end"> <h2 - class="h-10 md:h-12 2xl:h-14 flex items-center border-b-[3px] border-black px-3 pb-1 text-xl text-black 2xl:text-2xl" + class="h-12 md:h-14 2xl:h-16 flex items-center border-b-[3px] 2xl:border-b-4 border-black px-3 pt-2 pb-1 text-black text-xl 2xl:text-2xl" > <span class="font-bold tracking-wide"> <span class="block md:hidden">Cas type</span> @@ -1430,7 +1440,7 @@ initialPlacement="bottom" > <h2 - class="h-10 md:h-12 2xl:h-14 flex items-center border-b-[3px] border-transparent px-3 pb-1 text-xl 2xl:border-b-4 2xl:text-2xl tracking-wide text-gray-300" + class="h-12 md:h-14 2xl:h-16 flex items-center border-b-[3px] border-transparent px-3 pt-2 pb-1 text-xl text-black 2xl:border-b-4 2xl:text-2xl justify-center tracking-wide" > <span class="block md:hidden">Budget</span> <span class="hidden md:block">Impact budgétaire</span> @@ -1849,7 +1859,7 @@ /> </div> {/if} - <span class="text-start text-sm"> + <span class="flex-1 text-start text-sm"> <span class="font-bold" >{title.split("|")[0]}</span >