diff --git a/pkg/grid/src/components/AppInfo.tsx b/pkg/grid/src/components/AppInfo.tsx index 2bd227699..1d0198536 100644 --- a/pkg/grid/src/components/AppInfo.tsx +++ b/pkg/grid/src/components/AppInfo.tsx @@ -9,7 +9,7 @@ import { DocketHeader } from './DocketHeader'; import { Spinner } from './Spinner'; import { VatMeta } from './VatMeta'; import useDocketState, { ChargeWithDesk } from '../state/docket'; -import { getAppHref } from '../state/util'; +import { getAppHref, getAppName } from '../state/util'; import { addRecentApp } from '../nav/search/Home'; import { TreatyMeta } from './TreatyMeta'; @@ -113,7 +113,7 @@ export const AppInfo: FC = ({ docket, vat, className }) => { className="space-y-6" containerClass="w-full max-w-md" > -

Install “{docket.title}”

+

Install “{getAppName(docket)}”

This application will be able to view and interact with the contents of your Urbit. Only install if you trust the developer. @@ -123,7 +123,7 @@ export const AppInfo: FC = ({ docket, vat, className }) => { Cancel - Get “{docket.title}” + Get “{getAppName(docket)}” diff --git a/pkg/grid/src/components/AppLink.tsx b/pkg/grid/src/components/AppLink.tsx index 7cec674e6..7ff8547ec 100644 --- a/pkg/grid/src/components/AppLink.tsx +++ b/pkg/grid/src/components/AppLink.tsx @@ -2,7 +2,7 @@ import classNames from 'classnames'; import React, { HTMLProps, ReactNode } from 'react'; import { Link, LinkProps } from 'react-router-dom'; import { DocketWithDesk } from '../state/docket'; -import { getAppHref } from '../state/util'; +import { getAppHref, getAppName } from '../state/util'; import { DocketImage } from './DocketImage'; type Sizes = 'xs' | 'small' | 'default'; @@ -57,7 +57,7 @@ export const AppLink = ({ <>

-

{app.title}

+

{getAppName(app)}

{app.info && size === 'default' &&

{app.info}

}
diff --git a/pkg/grid/src/components/AppList.tsx b/pkg/grid/src/components/AppList.tsx index 7f09737eb..0764bab47 100644 --- a/pkg/grid/src/components/AppList.tsx +++ b/pkg/grid/src/components/AppList.tsx @@ -4,6 +4,7 @@ import { MatchItem } from '../nav/Nav'; import { useRecentsStore } from '../nav/search/Home'; import { AppLink, AppLinkProps } from './AppLink'; import { DocketWithDesk } from '../state/docket'; +import { getAppName } from '../state/util'; type AppListProps = { apps: T[]; @@ -45,7 +46,7 @@ export const AppList = ({ aria-labelledby={labelledBy} > {apps.map((app) => ( -
  • +
  • -

    {title}

    +

    {getAppName(docket)}

    {info &&

    {info}

    }
    {children} diff --git a/pkg/grid/src/components/DocketImage.tsx b/pkg/grid/src/components/DocketImage.tsx index b38b5543e..01267a7b5 100644 --- a/pkg/grid/src/components/DocketImage.tsx +++ b/pkg/grid/src/components/DocketImage.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import { Docket } from '@urbit/api/docket'; import cn from 'classnames'; import { useTileColor } from '../tiles/useTileColor'; @@ -19,13 +19,20 @@ const sizeMap: Record = { export function DocketImage({ color, image, className = '', size = 'full' }: DocketImageProps) { const { tileColor } = useTileColor(color); + const [imageError, setImageError] = useState(false); + return (
    - {image && ( - + {image && !imageError && ( + setImageError(true)} + /> )}
    ); diff --git a/pkg/grid/src/env.d.ts b/pkg/grid/src/env.d.ts index ebbd72c2b..2fda24a0d 100644 --- a/pkg/grid/src/env.d.ts +++ b/pkg/grid/src/env.d.ts @@ -1,4 +1,4 @@ -interface ImportMetaEnv extends Readonly> { +interface ImportMetaEnv extends Readonly> { readonly VITE_LAST_WIPE: string; readonly VITE_STORAGE_VERSION: string; } diff --git a/pkg/grid/src/nav/SystemPreferences.tsx b/pkg/grid/src/nav/SystemPreferences.tsx index 5cfbe55a5..78ca87f4c 100644 --- a/pkg/grid/src/nav/SystemPreferences.tsx +++ b/pkg/grid/src/nav/SystemPreferences.tsx @@ -14,6 +14,7 @@ import { LeftArrow } from '../components/icons/LeftArrow'; import { System } from '../components/icons/System'; import { Interface } from '../components/icons/Interface'; import { Notifications } from '../components/icons/Notifications'; +import { getAppName } from '../state/util'; interface SystemPreferencesSectionProps { url: string; @@ -112,7 +113,7 @@ export const SystemPreferences = (props: RouteComponentProps<{ submenu: string } active={matchSub('apps', charge.desk)} > - {charge.title} + {getAppName(charge)} ))} diff --git a/pkg/grid/src/nav/preferences/AppPrefs.tsx b/pkg/grid/src/nav/preferences/AppPrefs.tsx index 421e7bd34..51910f776 100644 --- a/pkg/grid/src/nav/preferences/AppPrefs.tsx +++ b/pkg/grid/src/nav/preferences/AppPrefs.tsx @@ -4,6 +4,7 @@ import { Setting } from '../../components/Setting'; import { ShipName } from '../../components/ShipName'; import { useCharge } from '../../state/docket'; import useKilnState, { useVat } from '../../state/kiln'; +import { getAppName } from '../../state/util'; export const AppPrefs = ({ match }: RouteComponentProps<{ desk: string }>) => { const { desk } = match.params; @@ -18,11 +19,11 @@ export const AppPrefs = ({ match }: RouteComponentProps<{ desk: string }>) => { return ( <> -

    {charge?.title} Settings

    +

    {getAppName(charge)} Settings

    {tracking ? ( -

    Automatically download and apply updates to keep {charge?.title} up to date.

    +

    Automatically download and apply updates to keep {getAppName(charge)} up to date.

    {otaSource && (

    OTA Source: diff --git a/pkg/grid/src/nav/search/TreatyInfo.tsx b/pkg/grid/src/nav/search/TreatyInfo.tsx index 9bc4c6de5..a6c78feec 100644 --- a/pkg/grid/src/nav/search/TreatyInfo.tsx +++ b/pkg/grid/src/nav/search/TreatyInfo.tsx @@ -4,6 +4,7 @@ import { AppInfo } from '../../components/AppInfo'; import { Spinner } from '../../components/Spinner'; import useDocketState, { useCharge, useTreaty } from '../../state/docket'; import { useVat } from '../../state/kiln'; +import { getAppName } from '../../state/util'; import { useLeapStore } from '../Nav'; export const TreatyInfo = () => { @@ -12,6 +13,7 @@ export const TreatyInfo = () => { const treaty = useTreaty(host, desk); const vat = useVat(desk); const charge = useCharge(desk); + const name = getAppName(treaty); useEffect(() => { if (!charge) { @@ -20,9 +22,9 @@ export const TreatyInfo = () => { }, [host, desk]); useEffect(() => { - select(<>{treaty?.title}); + select(<>{name}); useLeapStore.setState({ matches: [] }); - }, [treaty?.title]); + }, [name]); if (!treaty) { // TODO: maybe replace spinner with skeletons diff --git a/pkg/grid/src/state/util.ts b/pkg/grid/src/state/util.ts index d99e2e60e..a6375bbf0 100644 --- a/pkg/grid/src/state/util.ts +++ b/pkg/grid/src/state/util.ts @@ -1,4 +1,4 @@ -import { DocketHref } from '@urbit/api/docket'; +import { Docket, DocketHref, Treaty } from '@urbit/api/docket'; import { hsla, parseToHsla } from 'color2k'; import _ from 'lodash'; @@ -16,6 +16,14 @@ export function getAppHref(href: DocketHref) { return 'site' in href ? href.site : `/apps/${href.glob.base}/`; } +export function getAppName(app: (Docket & { desk: string }) | Treaty | undefined): string { + if (!app) { + return ''; + } + + return app.title || app.desk; +} + export function disableDefault(e: T): void { e.preventDefault(); } diff --git a/pkg/grid/src/tiles/RemoveApp.tsx b/pkg/grid/src/tiles/RemoveApp.tsx index 1271fe496..4f0783091 100644 --- a/pkg/grid/src/tiles/RemoveApp.tsx +++ b/pkg/grid/src/tiles/RemoveApp.tsx @@ -4,6 +4,7 @@ import { Button } from '../components/Button'; import { Dialog, DialogClose, DialogContent } from '../components/Dialog'; import { useRecentsStore } from '../nav/search/Home'; import useDocketState, { useCharges } from '../state/docket'; +import { getAppName } from '../state/util'; export const RemoveApp = () => { const history = useHistory(); @@ -21,7 +22,7 @@ export const RemoveApp = () => { return (

    !open && history.push('/')}> -

    Remove “{docket?.title || ''}”?

    +

    Remove “{getAppName(docket)}”?

    This will remove the software's tile from your home screen.

    @@ -30,7 +31,7 @@ export const RemoveApp = () => { Cancel - Remove “{docket?.title}” + Remove “{getAppName(docket)}”
    diff --git a/pkg/grid/src/tiles/SuspendApp.tsx b/pkg/grid/src/tiles/SuspendApp.tsx index abb9d15e5..c8c3e4732 100644 --- a/pkg/grid/src/tiles/SuspendApp.tsx +++ b/pkg/grid/src/tiles/SuspendApp.tsx @@ -4,6 +4,7 @@ import { Button } from '../components/Button'; import { Dialog, DialogClose, DialogContent } from '../components/Dialog'; import { useRecentsStore } from '../nav/search/Home'; import useDocketState, { useCharges } from '../state/docket'; +import { getAppName } from '../state/util'; export const SuspendApp = () => { const history = useHistory(); @@ -24,7 +25,7 @@ export const SuspendApp = () => { return ( !open && history.push('/')}> -

    Suspend “{charge?.title || ''}”

    +

    Suspend “{getAppName(charge)}”

    Suspending an app will turn off automatic updates. You cannot use an app when it is suspended, but you can resume it at any time. @@ -34,7 +35,7 @@ export const SuspendApp = () => { Cancel - Suspend “{charge?.title}” + Suspend “{getAppName(charge)}” diff --git a/pkg/interface/src/views/apps/permalinks/embed.tsx b/pkg/interface/src/views/apps/permalinks/embed.tsx index 3d8a96d80..97ab32df3 100644 --- a/pkg/interface/src/views/apps/permalinks/embed.tsx +++ b/pkg/interface/src/views/apps/permalinks/embed.tsx @@ -199,6 +199,8 @@ const ClampedText = styled(Text)` type AppTileProps = Treaty & BoxProps; export function AppTile({ color, image, ...props }: AppTileProps) { + const [imageError, setImageError] = useState(false); + return ( - {image && ( + {image && !imageError && ( setImageError(true)} /> )}