strings support
1 unmodified line234566789102 unmodified lines1 unmodified line "client_id": "https://untangled.wisp.place/oauth-client-metadata.json", "client_name": "untangled", "client_uri": "https://untangled.wisp.place", "redirect_uris": ["https://untangled.wisp.place/oauth/callback"], "scope": "atproto repo:sh.tangled.actor.profile repo:sh.tangled.repo.issue repo:sh.tangled.repo.issue.comment repo:sh.tangled.repo.issue.state repo:sh.tangled.repo.pull repo:sh.tangled.repo.pull.comment repo:sh.tangled.repo.pull.status rpc:sh.tangled.repo.merge?aud=* rpc:sh.tangled.repo.hiddenRef?aud=* repo:sh.tangled.feed.comment blob:*/*", "scope": "atproto repo:sh.tangled.actor.profile repo:sh.tangled.repo.issue repo:sh.tangled.repo.issue.comment repo:sh.tangled.repo.issue.state repo:sh.tangled.repo.pull repo:sh.tangled.repo.pull.comment repo:sh.tangled.repo.pull.status rpc:sh.tangled.repo.merge?aud=* rpc:sh.tangled.repo.hiddenRef?aud=* repo:sh.tangled.feed.comment repo:sh.tangled.string repo:sh.tangled.feed.star blob:*/*", "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "token_endpoint_auth_method": "none", "application_type": "web",2 unmodified lines3782 unmodified linesExpand all37833784378537863787378737883789379037913792379337933794379537963797379837994 unmodified lines380438053806380738063808380938103811381238132 unmodified lines3782 unmodified linesExpand all}
/* Align solid bar with the vertical replies thread line */.-ml-4.untangled-comment-highlight::before,.-ml-4 > .untangled-comment-highlight::before {.-ml-4 > .untangled-comment-highlight::before,.untangled-thread-reply.untangled-comment-highlight::before { left: calc(1rem - 2px); border-radius: 0;}
.-ml-4.untangled-comment-highlight,.-ml-4 > .untangled-comment-highlight {.-ml-4 > .untangled-comment-highlight,.untangled-thread-reply.untangled-comment-highlight { background-color: transparent !important; background-image: linear-gradient(to right, transparent calc(1rem - 2px), rgb(254 240 138 / 0.15) calc(1rem - 2px)) !important;}
4 unmodified lines .untangled-comment-highlight::before { background-color: #ca8a04; } .-ml-4.untangled-comment-highlight, .-ml-4 > .untangled-comment-highlight { .-ml-4 > .untangled-comment-highlight, .untangled-thread-reply.untangled-comment-highlight { background-color: transparent !important; background-image: linear-gradient(to right, transparent calc(1rem - 2px), rgb(161 98 7 / 0.1) calc(1rem - 2px)) !important; }}2 unmodified lines122345632 unmodified lines394041424344454647484950515253544 unmodified lines5960616263646566675 unmodified lines73747576777879808135 unmodified lines117118119120121122123124125126127128129130131132133134135136137138130 unmodified linesExpand all26927027127227327427527627727827928015 unmodified lines296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327101 unmodified linesExpand all4294304314324334344354364371 unmodified line439440441442396397398399400443444445446447448449450451452453402403404405406454455456457458459460import clsx from 'clsx';import { Bell, BookMarked, LogOut, RotateCcw, Save, Search, Settings, UserRound } from 'lucide-solid';import { Bell, BookMarked, LogOut, RotateCcw, Save, Search, Settings, UserRound, Plus, LineSquiggle } from 'lucide-solid';import { A, useLocation, useNavigate } from '@solidjs/router';import { createQuery, useQueryClient } from '@tanstack/solid-query';import { For, Show, createEffect, createSignal, onCleanup, onMount, type Component, type JSX } from 'solid-js';
32 unmodified lines const [draftAppviewUrl, setDraftAppviewUrl] = createSignal(settings.appviewUrl()); const [draftRouteKnotRequestsThroughAppview, setDraftRouteKnotRequestsThroughAppview] = createSignal( settings.routeKnotRequestsThroughAppview(), ); const [draftForcePds, setDraftForcePds] = createSignal(settings.forcePds()); const [error, setError] = createSignal<string | null>(null); const [saved, setSaved] = createSignal(false);
createEffect(() => { setDraftAppviewUrl(settings.appviewUrl()); setDraftRouteKnotRequestsThroughAppview(settings.routeKnotRequestsThroughAppview()); setDraftForcePds(settings.forcePds()); });
const reloadAppviewBackedQueries = () => { clearApiCaches();4 unmodified lines event.preventDefault(); try { settings.setAppviewUrl(draftAppviewUrl()); settings.setRouteKnotRequestsThroughAppview(draftRouteKnotRequestsThroughAppview()); settings.setForcePds(draftForcePds()); setError(null); setSaved(true); reloadAppviewBackedQueries(); } catch (cause) {5 unmodified lines const onReset = () => { settings.resetAppviewSettings(); setDraftAppviewUrl(settings.defaultAppviewUrl); setDraftRouteKnotRequestsThroughAppview(false); setDraftForcePds(false); setError(null); setSaved(true); reloadAppviewBackedQueries(); };35 unmodified lines /> <span>route knot requests through appview</span> </label>
<label class="flex items-center gap-3 text-sm text-gray-700 dark:text-gray-200"> <input type="checkbox" checked={draftForcePds()} onChange={(event) => { setDraftForcePds(event.currentTarget.checked); setSaved(false); setError(null); }} class="size-4 rounded border-gray-300 dark:border-gray-600" /> <span>force requests through PDS (bypass appview)</span> </label>
<div class="flex items-center justify-between gap-3"> <button type="button" class={buttonStyles()} onClick={onReset}> <RotateCcw class="size-4" /> reset130 unmodified linesExpand all <A href={`/${handle()}?tab=repos`} class="untangled-topbar-menu-item" onClick={closeMenu}> <BookMarked class="size-4" /> repositories </A> <A href={`/${handle()}?tab=strings`} class="untangled-topbar-menu-item" onClick={closeMenu}> <LineSquiggle class="size-4" /> strings </A> </> )} </Show>
15 unmodified lines </details> );};
const NewMenu: Component = () => { const closeMenu = (e: MouseEvent) => { const details = (e.currentTarget as HTMLElement).closest('details'); if (details) details.open = false; };
return ( <details data-topbar-menu class="untangled-topbar-menu"> <summary class="untangled-topbar-menu-summary btn text-sm no-underline hover:no-underline flex items-center gap-2 group border border-gray-200 dark:border-gray-700 rounded-sm px-3 py-1.5 bg-white dark:bg-gray-800 cursor-pointer"> <Plus class="size-4" /> <span class="hidden md:inline">new</span> </summary> <div class="untangled-topbar-menu-dropdown"> <div class="untangled-topbar-menu-item-separator"> <A href="/strings/new" class="untangled-topbar-menu-item" onClick={closeMenu}> <LineSquiggle class="size-4" /> new string </A> </div> </div> </details> );};
const TopbarSearch: Component = () => { const navigate = useNavigate(); const location = useLocation(); const [query, setQuery] = createSignal('');101 unmodified linesExpand all <Show when={auth.currentDid()} fallback={<LoginMenu />} > <NewMenu /> <NotificationsMenu /> <UserProfileMenu /> </Show> </div>1 unmodified line </nav> );};
export const RootShell: Component<{ children?: JSX.Element }> = (props) => ( <div class="min-h-screen flex flex-col gap-4 bg-slate-100 dark:bg-gray-900 dark:text-white"> <header class="untangled-safe-header w-full shadow-sm dark:text-white bg-white dark:bg-gray-800"> <Topbar /> </header>export const RootShell: Component<{ children?: JSX.Element }> = (props) => { const location = useLocation(); const isRaw = () => location.pathname.endsWith('/raw');
return ( <Show when={!isRaw()} fallback={<>{props.children}</>}> <div class="min-h-screen flex flex-col gap-4 bg-slate-100 dark:bg-gray-900 dark:text-white"> <header class="untangled-safe-header w-full shadow-sm dark:text-white bg-white dark:bg-gray-800"> <Topbar /> </header>
<div class="flex-grow"> <div class="untangled-shell mx-auto flex flex-col gap-4">{props.children}</div> </div> </div>); <div class="flex-grow"> <div class="untangled-shell mx-auto flex flex-col gap-4">{props.children}</div> </div> </div> </Show> );};18 unmodified lines1920212223242526272829303132333435363715 unmodified lines18 unmodified linesimport { NotFoundPage } from './pages/not-found';import { OAuthCallbackPage } from './pages/oauth-callback';import { SearchPage } from './pages/search';import { ProfilePage } from './pages/profile';import { StringPage, RawStringPage, NewStringPage, EditStringPage } from './pages/string';
export const AppRoutes: Component = () => ( <Router root={RootShell}> <Route path="/" component={HomePage} /> <Route path="/search" component={SearchPage} /> <Route path="/oauth/callback" component={OAuthCallbackPage} /> <Route path="/strings/new" component={NewStringPage} /> <Route path="/strings/:actor/:rkey" component={StringPage} /> <Route path="/strings/:actor/:rkey/edit" component={EditStringPage} /> <Route path="/strings/:actor/:rkey/raw" component={RawStringPage} /> <Route path="/:owner/:repo" component={RepoLayout}> <Route path="/" component={RepoCodePage} /> <Route path="/issues/new" component={NewIssuePage} /> <Route path="/issues/:issueRef" component={IssuePage} />15 unmodified lines13 unmodified lines141516171819202122232425261521 unmodified linesExpand all15481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167913 unmodified lines GitFork, Star, CircleDot, GitPullRequest, LoaderCircle, MessageSquarePlus,} from 'lucide-solid';import { useAuth } from '../lib/auth';import { resolveActor } from '../lib/api/identity';import { marked } from 'marked';import { A, useNavigate } from '@solidjs/router';import { For, Show, createMemo, createSignal, onCleanup, onMount, type Component, type JSX } from 'solid-js';import type { RepoContext, TreeEntry } from '../lib/api/repos';1521 unmodified linesExpand all};
export { CodeView, DiffView, PullDiffView } from './code-view';
export interface GenericComment { uri: string; rkey: string; author: { did: string; handle: string }; value: { body: string; createdAt: string; replyTo?: any; };}
export interface GenericCommentThread { item: GenericComment; replies: GenericComment[];}
export const CommentThreadsSection: Component<{ threads: GenericCommentThread[]; authorDid?: string; title?: string;}> = (props) => { return ( <div class="mt-6 space-y-4"> <Show when={props.title}> <h3 class="text-lg font-bold border-b border-gray-200 dark:border-gray-700 pb-2 dark:text-white mb-4"> {props.title} </h3> </Show> <div class="space-y-4"> <For each={props.threads}> {(thread) => ( <div class="rounded border border-gray-200 dark:border-gray-700 w-full overflow-hidden shadow-sm bg-gray-50 dark:bg-gray-800/50"> <ThreadCommentView id={`comment-${thread.item.rkey}`} author={thread.item.author} createdAt={thread.item.value.createdAt} markdown={thread.item.value.body} isAuthor={props.authorDid ? thread.item.author.did === props.authorDid : false} class="rounded px-6 py-4 bg-white dark:bg-gray-800" /> <Show when={thread.replies.length > 0}> <div class="relative ml-10 border-l-2 border-gray-200 dark:border-gray-700"> <For each={thread.replies}> {(reply) => ( <div class="-ml-4"> <ThreadCommentView id={`comment-${reply.rkey}`} author={reply.author} createdAt={reply.value.createdAt} markdown={reply.value.body} isAuthor={props.authorDid ? reply.author.did === props.authorDid : false} isReply={true} class="py-4 pr-4" /> </div> )} </For> </div> </Show> </div> )} </For> </div> </div> );};
export const CommentComposer: Component<{ value: string; onValueChange: (val: string) => void; onSubmit: (event: SubmitEvent) => void; working?: boolean; submitLabel?: string; placeholder?: string; error?: string | null;}> = (props) => { const auth = useAuth(); const viewerQuery = createQuery(() => ({ queryKey: ['viewer', auth.currentDid()], enabled: Boolean(auth.currentDid()), queryFn: async () => resolveActor(auth.currentDid()!), }));
return ( <form onSubmit={props.onSubmit} class="group/form w-full mt-4 flex flex-col"> <div class="bg-white dark:bg-gray-800 rounded drop-shadow-sm py-4 px-4 relative w-full border border-gray-200 dark:border-gray-700"> <div class="text-sm pb-2 text-gray-500 dark:text-gray-400"> <Show when={viewerQuery.data} fallback={<div class="h-6" />}> {(viewer) => ( <A href={`/${viewer().handle || viewer().did}`} class="flex items-center gap-1 hover:underline text-gray-500 dark:text-gray-400 w-fit"> <Avatar did={viewer().did} size="size-6" /> <span>{viewer().handle || viewer().did}</span> </A> )} </Show> </div> <textarea rows={5} placeholder={props.placeholder ?? 'Add to the discussion. Markdown is supported.'} class="w-full p-2 rounded border border-gray-200 dark:border-gray-700 bg-transparent focus:outline-none focus:ring-1 focus:ring-blue-500 dark:focus:ring-blue-400 dark:text-white" required value={props.value} onInput={(event) => props.onValueChange(event.currentTarget.value)} /> <Show when={props.error}> <div id="comment-error" class="error text-sm text-red-500 mt-1">{props.error}</div> </Show> </div> <div class="flex gap-2 mt-2"> <button id="comment-button" type="submit" class="btn-create p-2 flex items-center gap-2 no-underline hover:no-underline" disabled={props.working || !props.value.trim()} > <Show when={props.working} fallback={<MessageSquarePlus class="w-4 h-4" />}> <LoaderCircle class="w-4 h-4 animate-spin" /> </Show> <span>{props.submitLabel ?? 'Comment'}</span> </button> </div> </form> );};
65 unmodified lines66676869707172737475767778798081828384858687888990919293949596979843 unmodified lines65 unmodified lines} from './api/pulls';export { searchRecords,} from './api/search';export { getString, listStringRecords, deleteString, updateString, createString, listStringComments, createStringComment, getStringStarSummary, createStringStar, deleteStringStar,} from './api/strings';
export type { HydratedRecord, PaginatedResult, RecordCreationResult,} from './api/records';export type { StringRecord, StringComment, StringStarSummary,} from './api/strings';export type {
BlobResponse, BranchEntry, BranchResponse, CommitHeadline,43 unmodified lines12345678936 unmodified lines46474849505152535455565758596061626364656667686970717273747576773 unmodified lines8182838485868788897 unmodified lines9798991001011021031041051061071081091103 unmodified lines11411511611711811912012112212312412512612712812913013113213313413513613 unmodified linesimport { createContext, createSignal, useContext, type Component, type JSX } from 'solid-js';
const APPVIEW_URL_KEY = 'untangled.settings.appviewUrl';const ROUTE_KNOT_REQUESTS_THROUGH_APPVIEW_KEY = 'untangled.settings.routeKnotRequestsThroughAppview';const FORCE_PDS_KEY = 'untangled.settings.forcePds';
export const DEFAULT_TANGLED_APPVIEW_SERVICE = import.meta.env.VITE_TANGLED_APPVIEW_SERVICE || 'https://bobbin.klbr.net';
36 unmodified lines
return localStorage.getItem(ROUTE_KNOT_REQUESTS_THROUGH_APPVIEW_KEY) === 'true';};
const readStoredForcePds = (): boolean => { if (typeof localStorage === 'undefined') { return false; }
return localStorage.getItem(FORCE_PDS_KEY) === 'true';};
let currentAppviewUrl = readStoredAppviewUrl();let currentRouteKnotRequestsThroughAppview = readStoredRouteKnotRequestsThroughAppview();let currentForcePds = readStoredForcePds();
export const getTangledAppviewService = (): string => currentAppviewUrl;export const getRouteKnotRequestsThroughAppview = (): boolean => currentRouteKnotRequestsThroughAppview;export const getForcePds = (): boolean => currentForcePds;
interface AppSettingsContextValue { appviewUrl: () => string; routeKnotRequestsThroughAppview: () => boolean; forcePds: () => boolean; defaultAppviewUrl: string; setAppviewUrl: (url: string) => void; setRouteKnotRequestsThroughAppview: (enabled: boolean) => void; setForcePds: (enabled: boolean) => void; resetAppviewUrl: () => void; resetAppviewSettings: () => void;}
3 unmodified lines const [appviewUrl, setAppviewUrlSignal] = createSignal(currentAppviewUrl); const [routeKnotRequestsThroughAppview, setRouteKnotRequestsThroughAppviewSignal] = createSignal( currentRouteKnotRequestsThroughAppview, ); const [forcePds, setForcePdsSignal] = createSignal(currentForcePds); const defaultAppviewUrl = normalizeAppviewUrl(DEFAULT_TANGLED_APPVIEW_SERVICE);
const setAppviewUrl = (url: string) => { const normalized = normalizeAppviewUrl(url);7 unmodified lines localStorage.setItem(ROUTE_KNOT_REQUESTS_THROUGH_APPVIEW_KEY, String(enabled)); setRouteKnotRequestsThroughAppviewSignal(enabled); };
const setForcePds = (enabled: boolean) => { currentForcePds = enabled; localStorage.setItem(FORCE_PDS_KEY, String(enabled)); setForcePdsSignal(enabled); };
const resetAppviewUrl = () => { currentAppviewUrl = defaultAppviewUrl; localStorage.removeItem(APPVIEW_URL_KEY); setAppviewUrlSignal(defaultAppviewUrl);3 unmodified lines resetAppviewUrl(); currentRouteKnotRequestsThroughAppview = false; localStorage.removeItem(ROUTE_KNOT_REQUESTS_THROUGH_APPVIEW_KEY); setRouteKnotRequestsThroughAppviewSignal(false); currentForcePds = false; localStorage.removeItem(FORCE_PDS_KEY); setForcePdsSignal(false); };
return ( <AppSettingsContext.Provider value={{ appviewUrl, routeKnotRequestsThroughAppview, forcePds, defaultAppviewUrl, setAppviewUrl, setRouteKnotRequestsThroughAppview, setForcePds, resetAppviewUrl, resetAppviewSettings, }} >13 unmodified lines15 unmodified lines16171819202122232414 unmodified lines3940414243444546471 unmodified line495051525354555657585960616263646566979 unmodified linesExpand all10461047104810491050105110521053105410551056105710581059247 unmodified linesExpand all130713081309131013111312131313141315131613171318201 unmodified linesExpand all152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158080 unmodified lines15 unmodified lines ArrowRight, X, Check, Pencil, LineSquiggle,} from 'lucide-solid';import { A, useParams, useSearchParams, useNavigate } from '@solidjs/router';import { createQuery, useQueryClient } from '@tanstack/solid-query';import { For, Show, Switch, Match, createMemo, createSignal, createEffect, type Component } from 'solid-js';14 unmodified lines type VouchRecord,} from '../lib/api/graph';import { resolveActor, getActorProfile, resolveAvatarUrl, putActorProfile } from '../lib/api/identity';import { listRepoRecords, getRepoByDid, type RepoContext } from '../lib/api/repos';import { listStringRecords } from '../lib/api/strings';import { useAuth } from '../lib/auth';import { listAllAppviewRecords } from '../lib/api/appview';import { formatRelativeTime, getErrorMessage } from '../lib/repo-utils';import { ShTangledFeedStar, ShTangledActorProfile } from '@atcute/tangled';1 unmodified lineconst ProfileTabs: Component<{ activeTab: string; reposCount: number; starsCount: number; stringsCount: number; reposLoading?: boolean; starsLoading?: boolean; stringsLoading?: boolean;}> = (props) => { const tabs = [ { id: 'overview', label: 'overview', icon: () => <GalleryVertical class="w-4 h-4 mr-2" /> }, { id: 'repos', label: 'repos', icon: () => <BookMarked class="w-4 h-4 mr-2" />, count: () => props.reposCount, loading: () => props.reposLoading }, { id: 'starred', label: 'starred', icon: () => <Star class="w-4 h-4 mr-2" />, count: () => props.starsCount, loading: () => props.starsLoading }, { id: 'strings', label: 'strings', icon: () => <LineSquiggle class="w-4 h-4 mr-2" />, count: () => props.stringsCount, loading: () => props.stringsLoading }, ];
return ( <nav class="w-full pl-4 overflow-x-auto overflow-y-hidden">979 unmodified linesExpand all enabled: !!actorQuery.data, queryFn: () => listRepoRecords(actorQuery.data!), }));
const stringsQuery = createQuery(() => ({ queryKey: ['profile-strings', actorQuery.data?.did], enabled: !!actorQuery.data, queryFn: () => listStringRecords(actorQuery.data!), }));
const starsQuery = createQuery(() => ({ queryKey: ['profile-stars', actorQuery.data?.did], enabled: !!actorQuery.data, queryFn: async () => {247 unmodified linesExpand all <ProfileTabs activeTab={activeTab()} reposCount={reposQuery.data?.length ?? 0} starsCount={starsQuery.data?.length ?? 0} stringsCount={stringsQuery.data?.length ?? 0} reposLoading={reposQuery.isLoading} starsLoading={starsQuery.isLoading} stringsLoading={stringsQuery.isLoading} />
<section class="bg-white dark:bg-gray-800 px-2 py-6 md:p-6 rounded w-full dark:text-white shadow-sm"> <div class="grid grid-cols-1 md:grid-cols-11 gap-4">201 unmodified linesExpand all </Show> </div> </Match>
{/* Strings Tab */} <Match when={activeTab() === 'strings'}> <div id="all-strings" class="md:col-span-8 order-2 md:order-2"> <Show when={!stringsQuery.isLoading} fallback={ <div id="strings" class="grid grid-cols-1 gap-4 mb-6"> <For each={Array.from({ length: 3 })}> {() => <RepoCardSkeleton />} </For> </div> } > <div id="strings" class="grid grid-cols-1 gap-4 mb-6"> <For each={stringsQuery.data ?? []} fallback={ <div class="text-base text-gray-500 flex items-center justify-center italic p-12 border border-gray-200 dark:border-gray-700 rounded"> <span>This user does not have any strings yet.</span> </div> } > {(item) => { const lineCount = () => item.value.contents.split('\n').length; const timeAgo = () => formatRelativeTime(item.value.createdAt); return ( <div class="border border-gray-200 dark:border-gray-700 rounded-sm"> <div class="py-4 px-6 rounded bg-white dark:bg-gray-800"> <div class="font-medium dark:text-white flex gap-2 items-center"> <A href={`/strings/${resolvedActor().handle || resolvedActor().did}/${item.rkey}`} class="hover:underline"> {item.value.filename} </A> </div> {item.value.description && ( <div class="text-gray-600 dark:text-gray-300 text-sm"> {item.value.description} </div> )} <div class="text-gray-400 pt-4 text-sm font-mono inline-flex gap-2 mt-auto"> <span>{lineCount()} line{lineCount() !== 1 ? 's' : ''}</span> <span class="select-none [&:before]:content-['·']"></span> <span>{timeAgo()}</span> </div> </div> </div> ); }} </For> </div> </Show> </div> </Match>
{/* Followers Tab */} <Match when={activeTab() === 'followers'}> <div id="all-followers" class="md:col-span-8 order-2 md:order-2"> <p class="text-base font-bold uppercase tracking-wider p-2 dark:text-white">all followers</p>80 unmodified lines8 unmodified lines91011121314151617116 unmodified linesExpand all134135136137138139140141142143144200 unmodified linesExpand all345346347348349350351352353354355356357277 unmodified linesExpand all8 unmodified lines Search, Tag, UserRound, X, LineSquiggle,} from 'lucide-solid';import { A, useNavigate, useSearchParams } from '@solidjs/router';import { createQuery } from '@tanstack/solid-query';import type { Did, ResourceUri } from '@atcute/lexicons/syntax';116 unmodified linesExpand all </Match> <Match when={props.hit.nsid === 'sh.tangled.actor.profile'}> <UserRound class="w-4 h-4 mr-1.5 shrink-0" /> </Match> <Match when={props.hit.nsid === 'sh.tangled.string'}> <LineSquiggle class="w-4 h-4 mr-1.5 shrink-0" /> </Match> <Match when={props.hit.nsid === 'sh.tangled.label.definition'}> <Tag class="w-4 h-4 mr-1.5 shrink-0" /> </Match> </Switch>200 unmodified linesExpand all <A href={`/${props.hit.author.handle}`} class="truncate min-w-0"> {props.hit.author.handle} </A> </Match> <Match when={props.hit.nsid === 'sh.tangled.string'}> <A href={`/strings/${props.hit.author.handle || props.hit.author.did}/${props.hit.rkey}`} class="truncate min-w-0"> {props.hit.author.handle || props.hit.author.did}/{title()} </A> </Match> <Match when={props.hit.nsid === 'sh.tangled.repo.issue.comment' || props.hit.nsid === 'sh.tangled.repo.pull.comment' || props.hit.nsid === 'sh.tangled.feed.comment'}> <CommentParentLink hit={props.hit} /> </Match> </Switch>277 unmodified linesExpand all2 unmodified lines34567891011132 unmodified linesExpand all14414514614714814915015115215315415582 unmodified lines2 unmodified linesimport { normalizeServiceUrl } from './client';import { getRouteKnotRequestsThroughAppview, getTangledAppviewService, getForcePds,} from '../settings';
export interface AppviewRecordView<T> { uri: ResourceUri;132 unmodified linesExpand all return (await response.json()) as T;};
export const appviewFallback = async <T>(primary: () => Promise<T>, fallback: () => Promise<T>): Promise<T> => { if (getForcePds()) { return fallback(); }
try { return await primary(); } catch (cause) { if (!(cause instanceof AppviewUnavailableError)) {82 unmodified lines19 unmodified lines20212223242519 unmodified linesexport const PULL_COLLECTION: Nsid = 'sh.tangled.repo.pull';export const PULL_COMMENT_COLLECTION: Nsid = 'sh.tangled.repo.pull.comment';export const PULL_STATUS_COLLECTION: Nsid = 'sh.tangled.repo.pull.status';export const FEED_COMMENT_COLLECTION: Nsid = 'sh.tangled.feed.comment';export const STRING_COLLECTION: Nsid = 'sh.tangled.string';