Skip to content

Commit

Permalink
MDUI + help UI
Browse files Browse the repository at this point in the history
  • Loading branch information
agektmr committed Oct 14, 2024
1 parent 032b189 commit 0c0646d
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 66 deletions.
8 changes: 5 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"express-useragent": "^1.0.15",
"firebase-admin": "^12.6.0",
"lit": "^3.2.1",
"marked": "^13.0.3",
"mdui": "^2.1.2"
},
"engines": {
Expand Down
22 changes: 22 additions & 0 deletions public/components.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,28 @@ import 'mdui/components/text-field.js';
import 'mdui/components/list.js';
import 'mdui/components/list-item.js';
import 'mdui/components/button-icon.js';
import 'mdui/components/tooltip.js';
import 'mdui/components/top-app-bar.js';
import 'mdui/components/top-app-bar-title.js';
import 'mdui/components/navigation-drawer.js';
import 'mdui/components/linear-progress.js';
import { marked } from 'marked';

document.addEventListener('DOMContentLoaded', () => {
const drawer = document.querySelector('#drawer');
const drawerButton = document.querySelector('#drawer-button');
drawerButton.addEventListener('click', () => {
drawer.open = !drawer.open;
});
const content = document.querySelector('#help .help-content')?.innerText?.trim();
const headline = document.querySelector('#help .help-headline')?.innerText?.trim();
if (headline) {
document.querySelector('#help-headline').innerHTML = headline;
}
if (content) {
const serialized = content.split('\n').map((line) => line.trim()).join('\n');
const mkContent = marked.parse(serialized)
document.querySelector('#help-content').innerHTML = mkContent;
}
});

87 changes: 54 additions & 33 deletions public/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,16 @@

@import 'mdui/mdui.css';

* {
box-sizing: border-box;
--mdui-color-secondary: red;
}
// * {
// box-sizing: border-box;
// }

body {
margin: 0;
padding: 0;
font-family: Roboto,Noto Sans,sans-serif
}

.content {
margin: 0 16px 20px 16px;
}

.instructions {
color: gray;
}
Expand Down Expand Up @@ -65,42 +60,68 @@ h3 {
padding: 0 16px;
}

#help {
display: none;
}

mdui-top-app-bar {
background-color: var(--mdui-color-primary);
background-color: rgb(var(--mdui-color-primary));
mdui-top-app-bar-title, mdui-button-icon {
color: white;
}
mdui-linear-progress {
position: absolute;
top: 64px;
right: 0;
margin: 0;
}
}

mdui-linear-progress {
position: relative;
top: -16px;
mdui-navigation-drawer {
mdui-list {
padding-top: 64px;
mdui-list-item h3 {
font-size: 1.25em !important;
margin: 1.2em 0 0.5em 0 !important;
line-height: 1.5 !important;
padding: 0;
}
}
}

mwc-list, mdui-list {
width: 400px;
mwc-list-item, mdui-list-item {
.list-item {
width: 368px;
display: flex;
justify-content: space-between;
* {
display: inline-block;
}
.entity-name {
line-height: var(--mdc-icon-button-size, 48px);
flex: 1 1 auto;
mwc-icon.mini, mdui-button-icon.mini {
margin: 4px;
--mdc-icon-size: 16px;
vertical-align: middle;
.content {
margin: 64px 16px 20px 16px;
mdui-text-field {
width: 260px;
}
mwc-list, mdui-list {
width: 500px;
mwc-list-item, mdui-list-item {
.list-item {
width: 368px;
display: flex;
justify-content: space-between;
* {
display: inline-block;
}
.entity-name {
line-height: var(--mdc-icon-button-size, 48px);
flex: 1 1 auto;
mwc-icon.mini, mdui-button-icon.mini {
margin: 4px;
--mdc-icon-size: 16px;
vertical-align: middle;
}
}
.buttons {
flex: 0 1 auto;
}
}
.buttons {
flex: 0 1 auto;
}
}
}
}

mwc-button, .mdc-button, mdui-button {
mdui-button {
margin: 8px 0;
a {
text-decoration: none;
Expand Down
74 changes: 70 additions & 4 deletions views/home.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,56 @@
<div id="help">
<div class="help-headline">
Home page
</div>
<div class="help-content">
In this page, you can edit your display name, create a passkey, and
manage your passkeys. Once you create a passkey, sign out and try
signing in with the passkey.

### Display name

Created passkeys are saved with your username and a display name. Edit
your display name to see how it appears in the account selection of your
passkey sign-in.

### Create a passkey

Press **Create a passkey** to create a new passkey. The passkey's name
is automatically assigned based on its
[AAGUID](https://web.dev/articles/webauthn-aaguid), but you can change
it as you want.

### Manage passkeys

Press the **Edit** button to rename a passkey, or press the **Delete**
button to remove it.

### Learn more

Learn how to build this experience at [Create a passkey for passwordless
logins](https://web.dev/articles/passkey-registration) and [Server-side
passkey
registration](https://developers.google.com/identity/passkeys/developer-guides/server-registration).
</div>
</div>
<main class="content center">
<h2>Welcome, {{displayName}}!</h2>
<section>
<h3>Your name:</h3>
<h3>Your display name:</h3>
<div id="display-name"></div>
</section>
<section>
<h3>Your registered passkeys:</h3>
<div id="list"></div>
</section>
<p id="message" class="instructions"></p>
<mdui-button id="create-passkey" class="hidden" icon="fingerprint">Create a passkey</mdui-button>
<mdui-button
id="create-passkey"
class="hidden"
icon="fingerprint"
variant="tonal">
Create a passkey
</mdui-button>
<mdui-button variant="outlined" href="/auth/signout">Sign out</mdui-button>
</main>
<script type="module">
Expand Down Expand Up @@ -120,13 +161,38 @@ <h3>Your registered passkeys:</h3>
const res = await _fetch('/auth/getKeys');
const list = $('#list');
const creds = html`${res.length > 0 ? html`
<mdui-list>${res.map(cred => html`
<mdui-list>${res.map(cred => {
const created = new Date(cred.registered);
const createdDate = created.toLocaleDateString(undefined, {
month: 'short',
day: 'numeric',
});
const createdTime = created.toLocaleTimeString(undefined, {
timeStyle: 'short',
hour12: false,
});
const createdStr = `Created: ${createdDate}, ${createdTime}`;
let lastUsedStr = '';
if (cred.last_used) {
const lastUsed = new Date(cred.last_used);
const lastUsedDate = lastUsed.toLocaleDateString(undefined, {
month: 'short',
day: 'numeric',
});
const lastUsedTime = lastUsed.toLocaleTimeString(undefined, {
timeStyle: 'short',
hour12: false,
});
lastUsedStr = cred.last_used?`, Last Used: ${lastUsedDate}, ${lastUsedTime}`:'';
}
return html`
<mdui-list-item nonclickable>
${cred.aaguid && cred.aaguid !== '00000000-0000-0000-0000-000000000000'
?html`
<mdui-icon slot="icon" nonclickable src="${aaguids[cred.aaguid].icon_light}"></mdui-icon>
`:''}
${cred.name || 'Unnamed' }
<div slot="description">${createdStr}${lastUsedStr}</div>
<div class="buttons" slot="end-icon">
<mdui-button-icon
data-cred-id="${cred.id}"
Expand All @@ -138,7 +204,7 @@ <h3>Your registered passkeys:</h3>
@click="${remove}"
icon="delete"></mdui-button-icon>
</div>
</mdui-list-item>`)}
</mdui-list-item>`})}
</mdui-list>` : html`
<mdui-list>
<mdui-list-item>No credentials found.</mdui-list-item>
Expand Down
40 changes: 30 additions & 10 deletions views/index.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,33 @@
<div id="help">
<div class="help-headline">
Sign-in
</div>
<div class="help-content">
Sign in with a username and password if you haven't created a passkey
yet. You can use a random username, no account creation is needed.

Once you are signed in, create a new passkey and sign out to come back
here.

### Sign in with a passkey

Once a passkey is created, place your cursor in the username field and
you'll notice the autofill dialog contains your passkeys. Select a
passkey and perform [user
verification](https://web.dev/articles/webauthn-user-verification) to
sign in.

Alternatively, you can use the one-button sign-in experience by pressing
**Use a one-button sign-in instead** button.

### Learn more

Learn how to build this experience at [Sign in with a passkey through
form autofill](https://web.dev/articles/passkey-form-autofill) and
[Server-side passkey
authentication](https://developers.google.com/identity/passkeys/developer-guides/server-authentication).
</div>
</div>
<main class="content center">
<h2>Enter a username</h2>
<form id="form" method="POST" action="/auth/username" class="center">
Expand All @@ -9,18 +39,8 @@ <h2>Enter a username</h2>
label="username"
autofocus></mdui-text-field>
<input type="password" class="hidden" name="password" />
<p class="instructions">Any username can be accepted.</p>
<mdui-button type="submit">Next</mdui-button>
<mdui-button href="/one-button" variant="text">Use one button sign-in instead</mdui-button>
<ol class="instructions narrow">
<li>Sign in with a random username and password.</li>
<li>Create a passkey.</li>
<li>Sign out.</li>
<li>Click or tap on the username input field to show an autofill dialog.</li>
<li>Select a passkey.</li>
<li>Authenticate.</li>
<li>You are signed in.</li>
</ol>
</form>
</main>
<script type="module">
Expand Down
Loading

0 comments on commit 0c0646d

Please sign in to comment.