149 lines
3.3 KiB
TypeScript
149 lines
3.3 KiB
TypeScript
import type { OnePassword } from "opvault.js"
|
|
import styled from "@emotion/styled"
|
|
import React, { useCallback, useEffect, useState } from "react"
|
|
import { IoMdArrowRoundBack } from "react-icons/io"
|
|
import { FaUnlock } from "react-icons/fa"
|
|
import { useTranslate } from "../../i18n"
|
|
|
|
const Container = styled.div`
|
|
padding: 20px;
|
|
transform: translate(-50%, -50%);
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
width: 500px;
|
|
`
|
|
const BackButton = styled.button`
|
|
&& {
|
|
background: transparent;
|
|
}
|
|
border: none;
|
|
box-shadow: none;
|
|
font-size: 2em;
|
|
cursor: pointer;
|
|
padding: 0;
|
|
&:hover {
|
|
svg path {
|
|
fill: var(--selected-background);
|
|
transition: 0.2s;
|
|
}
|
|
}
|
|
`
|
|
const Input = styled.input`
|
|
box-shadow: inset 0 2px 2px rgb(0 0 0 / 8%);
|
|
font-size: 1.5em;
|
|
width: calc(95.5% - 60px);
|
|
&& {
|
|
border-radius: 10px;
|
|
border-width: 1px;
|
|
padding: 15px 20px;
|
|
padding-right: 60px;
|
|
}
|
|
`
|
|
const Select = styled.select`
|
|
float: right;
|
|
`
|
|
const Submit = styled.button`
|
|
font-size: 1.8em;
|
|
&& {
|
|
background: transparent;
|
|
border: none;
|
|
box-shadow: none;
|
|
}
|
|
svg path {
|
|
fill: var(--color);
|
|
}
|
|
&:hover {
|
|
transition: 0.2s;
|
|
}
|
|
text-align: center;
|
|
position: absolute;
|
|
top: 8px;
|
|
right: 5px;
|
|
`
|
|
const VaultPath = styled.div`
|
|
margin-top: 15px;
|
|
opacity: 0.7;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
`
|
|
|
|
export const Unlock: React.FC<{
|
|
instance: OnePassword
|
|
vaultPath: string
|
|
onUnlock(profile: string, password: string): void
|
|
onReturn(): void
|
|
}> = ({ onUnlock, onReturn, instance, vaultPath }) => {
|
|
const t = useTranslate()
|
|
const [profiles, setProfiles] = useState<string[]>(() => [])
|
|
const [profile, setProfile] = useState<string>()
|
|
const [password, setPassword] = useState("")
|
|
|
|
const unlock = useCallback(
|
|
(e?: React.FormEvent) => {
|
|
e?.preventDefault()
|
|
|
|
if (!profile) return
|
|
onUnlock(profile, password)
|
|
setPassword("")
|
|
},
|
|
[onUnlock, profile, password]
|
|
)
|
|
|
|
const onKeyUp = useCallback(
|
|
(e: React.KeyboardEvent) => {
|
|
if (e.key === "Enter") {
|
|
unlock()
|
|
}
|
|
},
|
|
[unlock]
|
|
)
|
|
|
|
useEffect(() => {
|
|
instance.getProfileNames().then(profiles => {
|
|
setProfiles(profiles)
|
|
setProfile(profiles[0])
|
|
})
|
|
}, [instance])
|
|
|
|
return (
|
|
<Container>
|
|
<div style={{ marginBottom: 10 }}>
|
|
<BackButton onClick={onReturn} title={t.action.go_back}>
|
|
<IoMdArrowRoundBack />
|
|
</BackButton>
|
|
<Select
|
|
title={t.noun.vault}
|
|
value={profile}
|
|
onChange={e => setProfile(e.currentTarget.value)}
|
|
>
|
|
{profiles.map(p => (
|
|
<option key={p} value={p}>
|
|
{t.noun.vault}: {p}
|
|
</option>
|
|
))}
|
|
</Select>
|
|
</div>
|
|
<div style={{ margin: "10px 0", position: "relative" }}>
|
|
<Input
|
|
type="password"
|
|
value={password}
|
|
onChange={e => setPassword(e.currentTarget.value)}
|
|
placeholder={t.label.password_placeholder}
|
|
onKeyUp={onKeyUp}
|
|
/>
|
|
<Submit
|
|
type="submit"
|
|
disabled={!profile || !password}
|
|
onClick={unlock}
|
|
title={t.action.unlock}
|
|
>
|
|
<FaUnlock />
|
|
</Submit>
|
|
</div>
|
|
<VaultPath>{vaultPath}</VaultPath>
|
|
</Container>
|
|
)
|
|
}
|