Browse Source
Merge branch 'master' into issue-407-text-style-messages
pull/423/head
Dan Ditomaso
1 year ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with
68 additions and
20 deletions
-
src/components/PageComponents/Map/NodeDetail.tsx
-
src/components/PageComponents/Messages/MessageInput.tsx
-
src/components/UI/Button.tsx
-
src/components/UI/Toast.tsx
-
src/core/utils/string.ts
|
|
|
@ -1,6 +1,7 @@ |
|
|
|
import { Separator } from "@app/components/UI/Seperator"; |
|
|
|
import { H5 } from "@app/components/UI/Typography/H5.tsx"; |
|
|
|
import { Subtle } from "@app/components/UI/Typography/Subtle.tsx"; |
|
|
|
import { formatQuantity } from "@app/core/utils/string"; |
|
|
|
import { Avatar } from "@components/UI/Avatar"; |
|
|
|
import { Mono } from "@components/generic/Mono.tsx"; |
|
|
|
import { TimeAgo } from "@components/generic/Table/tmp/TimeAgo.tsx"; |
|
|
|
@ -132,7 +133,12 @@ export const NodeDetail = ({ node }: NodeDetailProps) => { |
|
|
|
className="ml-2 mr-1" |
|
|
|
aria-label="Elevation" |
|
|
|
/> |
|
|
|
<div>{node.position?.altitude} ft</div> |
|
|
|
<div> |
|
|
|
{formatQuantity(node.position?.altitude, { |
|
|
|
one: "meter", |
|
|
|
other: "meters", |
|
|
|
})} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
)} |
|
|
|
</div> |
|
|
|
|
|
|
|
@ -4,7 +4,13 @@ import { Input } from "@components/UI/Input.tsx"; |
|
|
|
import { useDevice } from "@core/stores/deviceStore.ts"; |
|
|
|
import type { Types } from "@meshtastic/js"; |
|
|
|
import { SendIcon } from "lucide-react"; |
|
|
|
import { type JSX, useCallback, useMemo, useState } from "react"; |
|
|
|
import { |
|
|
|
type JSX, |
|
|
|
startTransition, |
|
|
|
useCallback, |
|
|
|
useMemo, |
|
|
|
useState, |
|
|
|
} from "react"; |
|
|
|
|
|
|
|
export interface MessageInputProps { |
|
|
|
to: Types.Destination; |
|
|
|
@ -76,26 +82,31 @@ export const MessageInput = ({ |
|
|
|
<div className="flex gap-2"> |
|
|
|
<form |
|
|
|
className="w-full" |
|
|
|
onSubmit={(e) => { |
|
|
|
e.preventDefault(); |
|
|
|
sendText(localDraft); |
|
|
|
setLocalDraft(""); |
|
|
|
setMessageDraft(""); |
|
|
|
setMessageBytes(0); |
|
|
|
action={async (formData: FormData) => { |
|
|
|
// prevent user from sending blank/empty message
|
|
|
|
if (localDraft === "") return; |
|
|
|
const message = formData.get("messageInput") as string; |
|
|
|
startTransition(() => { |
|
|
|
sendText(message); |
|
|
|
setLocalDraft(""); |
|
|
|
setMessageDraft(""); |
|
|
|
setMessageBytes(0); |
|
|
|
}); |
|
|
|
}} |
|
|
|
> |
|
|
|
<div className="flex flex-grow gap-2"> |
|
|
|
<Input |
|
|
|
autoFocus={true} |
|
|
|
minLength={1} |
|
|
|
placeholder="Enter Message" |
|
|
|
value={localDraft} |
|
|
|
onChange={handleInputChange} |
|
|
|
/> |
|
|
|
<span className="w-full"> |
|
|
|
<Input |
|
|
|
autoFocus={true} |
|
|
|
minLength={1} |
|
|
|
name="messageInput" |
|
|
|
placeholder="Enter Message" |
|
|
|
value={localDraft} |
|
|
|
onChange={handleInputChange} |
|
|
|
/> |
|
|
|
</span> |
|
|
|
<div className="flex items-center w-24 p-2 place-content-end"> |
|
|
|
<span> |
|
|
|
{messageBytes}/{maxBytes} |
|
|
|
</span> |
|
|
|
{messageBytes}/{maxBytes} |
|
|
|
</div> |
|
|
|
|
|
|
|
<Button type="submit"> |
|
|
|
|
|
|
|
@ -15,7 +15,7 @@ const buttonVariants = cva( |
|
|
|
success: |
|
|
|
"bg-green-500 text-white hover:bg-green-600 dark:hover:bg-green-600", |
|
|
|
outline: |
|
|
|
"bg-transparent border border-slate-200 hover:bg-slate-100 dark:border-slate-700 dark:text-slate-100", |
|
|
|
"bg-transparent border border-slate-200 hover:bg-slate-100 dark:border-slate-400 dark:text-slate-100", |
|
|
|
subtle: |
|
|
|
"bg-slate-100 text-slate-900 hover:bg-slate-200 dark:bg-slate-700 dark:text-slate-100", |
|
|
|
ghost: |
|
|
|
|
|
|
|
@ -28,7 +28,7 @@ const toastVariants = cva( |
|
|
|
variants: { |
|
|
|
variant: { |
|
|
|
default: |
|
|
|
"border bg-background text-foreground dark:bg-slate-700 dark:border-slate-600 dark:text-slate-50", |
|
|
|
"border bg-backgroundPrimary text-foreground dark:bg-slate-700 dark:border-slate-600 dark:text-slate-50", |
|
|
|
destructive: |
|
|
|
"group destructive bg-red-600 text-white dark:border-red-900 dark:bg-red-900 dark:text-red-50", |
|
|
|
}, |
|
|
|
|
|
|
|
@ -0,0 +1,31 @@ |
|
|
|
interface PluralForms { |
|
|
|
one: string; |
|
|
|
other: string; |
|
|
|
[key: string]: string; |
|
|
|
} |
|
|
|
|
|
|
|
interface FormatOptions { |
|
|
|
locale?: string; |
|
|
|
pluralRules?: Intl.PluralRulesOptions; |
|
|
|
numberFormat?: Intl.NumberFormatOptions; |
|
|
|
} |
|
|
|
|
|
|
|
export function formatQuantity( |
|
|
|
value: number, |
|
|
|
forms: PluralForms, |
|
|
|
options: FormatOptions = {}, |
|
|
|
) { |
|
|
|
const { |
|
|
|
locale = "en-US", |
|
|
|
pluralRules: pluralOptions = { type: "cardinal" }, |
|
|
|
numberFormat: numberOptions = {}, |
|
|
|
} = options; |
|
|
|
|
|
|
|
const pluralRules = new Intl.PluralRules(locale, pluralOptions); |
|
|
|
const numberFormat = new Intl.NumberFormat(locale, numberOptions); |
|
|
|
|
|
|
|
const pluralCategory = pluralRules.select(value); |
|
|
|
const word = forms[pluralCategory]; |
|
|
|
|
|
|
|
return `${numberFormat.format(value)} ${word}`; |
|
|
|
} |