diff --git a/frontend/src/lib/icons/Icon.svelte b/frontend/src/lib/icons/Icon.svelte index 34972528e..435f41abc 100644 --- a/frontend/src/lib/icons/Icon.svelte +++ b/frontend/src/lib/icons/Icon.svelte @@ -1,6 +1,6 @@ <script lang="ts" context="module"> // Add more as necessary. Should be as limited as possible to maximize consistency. https://daisyui.com/components/badge/ - export type IconSize = 'text-md' | 'text-lg' | 'text-2xl'; + export type IconSize = 'text-md' | 'text-lg' | 'text-xl' | 'text-2xl' | 'text-5xl'; </script> <script lang="ts"> diff --git a/frontend/src/lib/layout/Layout.svelte b/frontend/src/lib/layout/Layout.svelte index bb3f2e109..34a61f29f 100644 --- a/frontend/src/lib/layout/Layout.svelte +++ b/frontend/src/lib/layout/Layout.svelte @@ -11,6 +11,8 @@ import DevContent from './DevContent.svelte'; import { helpLinks } from '$lib/components/help'; + export let hideToolbar = false; + let menuToggle = false; $: data = $page.data as LayoutData; $: user = data.user; @@ -34,37 +36,39 @@ <svelte:window on:keydown={closeOnEscape} /> {#if user} - <div class="drawer drawer-end"> + <div class="drawer drawer-end grow"> <input id="drawer-toggle" type="checkbox" bind:checked={menuToggle} class="drawer-toggle" /> - <div class="drawer-content max-w-[100vw]"> + <div class="drawer-content max-w-[100vw] flex flex-col"> <AppBar {user} /> - <div class="bg-neutral text-neutral-content p-2 md:px-6 flex justify-between items-center gap-2"> - <Breadcrumbs /> - <div class="flex gap-4 items-center"> - <DevContent> - <a href="/sandbox" class="btn btn-sm btn-secondary"> - <span class="max-sm:hidden"> - Sandbox - </span> - <Icon size="text-2xl" icon="i-mdi-box-variant" /> - </a> - </DevContent> - <a href={helpLinks.helpList} target="_blank" rel="external" - class="btn btn-sm btn-info btn-outline max-sm:hidden"> - {$t('appmenu.help')} - <Icon icon="i-mdi-open-in-new" size="text-lg" /> - </a> - <AdminContent> - <a href="/admin" class="btn btn-sm btn-accent"> - <span class="max-sm:hidden"> - {$t('admin_dashboard.title')} - </span> - <AdminIcon /> + {#if !hideToolbar} + <div class="bg-neutral text-neutral-content p-2 md:px-6 flex justify-between items-center gap-2"> + <Breadcrumbs /> + <div class="flex gap-4 items-center"> + <DevContent> + <a href="/sandbox" class="btn btn-sm btn-secondary"> + <span class="max-sm:hidden"> + Sandbox + </span> + <Icon size="text-2xl" icon="i-mdi-box-variant" /> + </a> + </DevContent> + <a href={helpLinks.helpList} target="_blank" rel="external" + class="btn btn-sm btn-info btn-outline max-sm:hidden"> + {$t('appmenu.help')} + <Icon icon="i-mdi-open-in-new" size="text-lg" /> </a> - </AdminContent> + <AdminContent> + <a href="/admin" class="btn btn-sm btn-accent"> + <span class="max-sm:hidden"> + {$t('admin_dashboard.title')} + </span> + <AdminIcon /> + </a> + </AdminContent> + </div> </div> - </div> + {/if} <div class="max-w-prose mx-auto email-status-container"> <EmailVerificationStatus {user} /> diff --git a/frontend/src/routes/(authenticated)/authorize/+layout@.svelte b/frontend/src/routes/(authenticated)/authorize/+layout@.svelte new file mode 100644 index 000000000..7370f3d5c --- /dev/null +++ b/frontend/src/routes/(authenticated)/authorize/+layout@.svelte @@ -0,0 +1,7 @@ +<script> + import { Layout } from '$lib/layout'; +</script> + +<Layout hideToolbar> + <slot /> +</Layout> diff --git a/frontend/src/routes/(authenticated)/authorize/+page.svelte b/frontend/src/routes/(authenticated)/authorize/+page.svelte index 5c2feda77..645e659de 100644 --- a/frontend/src/routes/(authenticated)/authorize/+page.svelte +++ b/frontend/src/routes/(authenticated)/authorize/+page.svelte @@ -1,18 +1,73 @@ <script lang="ts"> + import ProjectTypeIcon from '$lib/components/ProjectType/ProjectTypeIcon.svelte'; + import { ProjectType } from '$lib/gql/types'; + import { AuthenticatedUserIcon } from '$lib/icons'; - import type {PageData} from './$types'; + import Icon from '$lib/icons/Icon.svelte'; + import type { PageData } from './$types'; export let data: PageData; </script> -<form method="post" action="/api/login/open-id-auth"> - - <p>Do you want to permit "{data.appName}" to access your data? (scopes: {data.scope})</p> - {#each Object.entries(data.postback) as [key, value]} - <!--parameters required to resume the auth process--> - <input type="hidden" name={key} value={value}/> - {/each} - <input type="submit" class="btn whitespace-nowrap btn-primary" name="submit.accept" value="Approve"/> - <input type="submit" class="btn whitespace-nowrap btn-secondary" name="submit.deny" value="Deny"/> -</form> - +<div class="flex flex-col items-center grow"> + <div class="flex flex-col justify-center grow max-w-lg"> + <div class="flex-grow"></div> + <form method="post" action="/api/login/open-id-auth" class="flex flex-col items-center"> + <div class="mb-6 grid gap-x-3 gap-y-1 items-center" style="grid-template-columns: auto 1fr"> + <div class="row-span-2"> + <Icon icon="i-mdi-approval" color="text-success" size="text-5xl" /> + </div> + <h2 class="text-3xl"> + Authorize "{data.appName}" + </h2> + <div> + {data.appName} wants to access your account. + </div> + </div> + <div class="bg-base-200/50 py-5 px-8"> + <div class="grid gap-x-3 gap-y-5" style="grid-template-columns: auto 1fr"> + {#each data.scope?.split(' ') ?? [] as scope} + {#if scope === 'profile'} + <div class="grid grid-cols-subgrid col-span-full items-center"> + <AuthenticatedUserIcon size="text-4xl" /> + <div> + <div class="font-bold">Personal user data</div> + <div>Name, email address and/or username (read-only)</div> + </div> + </div> + {/if} + {#if scope === 'profile'} + <div class="grid grid-cols-subgrid col-span-full items-center"> + <ProjectTypeIcon type={ProjectType.FlEx} size="h-8" /> + <div> + <div class="font-bold">Projects</div> + <div>Project membership and roles (read-only)</div> + </div> + </div> + {/if} + {/each} + </div> + </div> + <div> + {#each Object.entries(data.postback) as [key, value]} + <!--parameters required to resume the auth process--> + <input type="hidden" name={key} {value} /> + {/each} + </div> + <div class="mt-4 flex items-center gap-2"> + {data.appName} is trusted by Language Depot + <Icon icon="i-mdi-shield-check" color="text-info" size="text-xl" /> + </div> + <div class="w-full flex max-sm:flex-col justify-center gap-4 mt-6"> + <input type="submit" class="btn whitespace-nowrap btn-secondary" name="submit.deny" value="Deny" /> + <input + type="submit" + class="btn whitespace-nowrap btn-success" + name="submit.accept" + value="Authorize {data.appName}" + /> + </div> + </form> + <div class="flex-grow-[2]"></div> + </div> +</div>