{
"data": {
"near": {
"widget": {
"Search.IndexPage": {
"": "const SEARCH_API_KEY = props.searchApiKey ?? \"fc7644a5da5306311e8e9418c24fddc4\";\nconst APPLICATION_ID = props.appId ?? \"B6PI9UKKJT\";\nconst INDEX = props.index ?? \"replica_prod_near-social-feed\";\nconst API_URL = props.apiUrl ?? `https://${APPLICATION_ID}-dsn.algolia.net/1/indexes/${INDEX}/query?`;\nconst INITIAL_PAGE = props.initialPage ?? 0;\nconst facets = props.facets ?? [\"All\", \"People\", \"Apps\", \"Components\", \"Posts\"];\nconst tab = props.tab ?? \"All\";\nconst renderHeader = props.renderHeader;\nconst showHeader = props.showHeader ?? true;\nconst showSearchBar = props.showSearchBar ?? true;\nconst showFacets = props.showFacets ?? true;\nconst showPagination = props.showPagination ?? true;\nconst userId = props.accountId ?? context.accountId;\n\nconst componentsUrl = `/near/widget/ComponentsPage`;\nconst peopleUrl = `/near/widget/PeoplePage`;\nconst nearcatalogUrl = `/nearcatalog.near/widget/Index`;\n\nState.init({\n facet: tab,\n});\n\nconst Wrapper =\n props.wrapper ??\n styled.div`\n display: flex;\n flex-direction: column;\n gap: 48px;\n padding-bottom: 48px;\n max-width: 600px;\n margin: 0 auto;\n `;\n\nconst Header = styled.div`\n display: flex;\n flex-direction: column;\n gap: 12px;\n`;\n\nconst Search = styled.div``;\n\nconst Facets = styled.div`\n overflow: auto;\n`;\n\nconst H1 = styled.h1`\n font-weight: 600;\n font-size: 32px;\n line-height: 39px;\n color: #11181c;\n margin: 0;\n`;\n\nconst H2 = styled.h2`\n font-weight: 400;\n font-size: 20px;\n line-height: 24px;\n color: #687076;\n margin: 0;\n`;\n\nconst H3 = styled.h3`\n color: #687076;\n font-weight: 600;\n font-size: 12px;\n line-height: 15px;\n text-transform: uppercase;\n margin: 0;\n`;\n\nconst Group = styled.div`\n display: flex;\n flex-direction: column;\n gap: 12px;\n`;\n\nconst GroupHeader = styled.div`\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n`;\n\nconst Text = styled.p`\n margin: 0;\n line-height: 1.5rem;\n color: ${(p) => (p.bold ? \"#11181C\" : \"#687076\")};\n font-weight: ${(p) => (p.bold ? \"600\" : \"400\")};\n font-size: ${(p) => (p.small ? \"12px\" : \"14px\")};\n overflow: ${(p) => (p.ellipsis ? \"hidden\" : \"\")};\n text-overflow: ${(p) => (p.ellipsis ? \"ellipsis\" : \"\")};\n white-space: ${(p) => (p.ellipsis ? \"nowrap\" : \"\")};\n overflow-wrap: anywhere;\n\n b {\n font-weight: 600;\n color: #11181c;\n }\n`;\n\nconst TextLink = styled(\"Link\")`\n margin: 0;\n line-height: 1.5rem;\n font-size: ${(p) => (p.small ? \"12px\" : \"14px\")};\n overflow: ${(p) => (p.ellipsis ? \"hidden\" : \"\")};\n text-overflow: ${(p) => (p.ellipsis ? \"ellipsis\" : \"\")};\n white-space: ${(p) => (p.ellipsis ? \"nowrap\" : \"\")};\n overflow-wrap: anywhere;\n color: #006adc;\n outline: none;\n font-weight: 600;\n\n b {\n font-weight: 600;\n color: #11181c;\n }\n\n &:hover,\n &:focus {\n color: #006adc;\n text-decoration: underline;\n }\n`;\n\nconst Items =\n props.styles.Items ??\n styled.div`\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: 12px;\n `;\n\nconst Item = props.styles.Item ?? styled.div``;\n\nconst resetSearcheHits = () => {\n State.update({\n currentPage: 0,\n search: undefined,\n paginate: undefined,\n facet: undefined,\n });\n};\n\nconst writeStateTerm = (term) => {\n State.update({\n term,\n });\n\n if (term === \"\") {\n resetSearcheHits();\n }\n};\n\nconst profiles = (records) => {\n const profiles = [];\n for (const [i, record] of records ?? []) {\n profiles.push({\n accountId: record.author,\n profile_name: record.profile_name,\n searchPosition: i,\n });\n }\n return profiles;\n};\n\nconst posts = (content, postType) => {\n const posts = [];\n for (const [i, post] of content || []) {\n const accountId = post.author;\n const blockHeight = post.objectID.split(\"/\").slice(-1)[0];\n\n let snipContent = true;\n let text = post.content;\n if (post._highlightResult.content.matchLevel === \"full\") {\n // Use algolia provided snipped content:\n snipContent = false;\n text = post._snippetResult.content.value.replaceAll(\"<em>\", \"\").replaceAll(\"</em>\", \"\");\n }\n\n const postContent = {\n type: \"md\",\n text,\n };\n\n posts.push({\n accountId,\n blockHeight,\n postContent,\n postType,\n snipContent,\n searchPosition: i,\n });\n }\n return posts;\n};\n\nconst components = (records) => {\n const components = [];\n for (const [i, component] of records || []) {\n const idParts = component.objectID.split(\"/\");\n const widgetName = idParts[idParts.length - 1];\n const accountId = component.author;\n components.push({\n accountId,\n widgetName,\n searchPosition: i,\n });\n }\n return components;\n};\n\n// creates an array of components\nconst nearcatalog = (records) => {\n const components = [];\n for (const [i, component] of records || []) {\n const widgetName = \"Index\";\n const accountId = \"nearcatalog.near\";\n components.push({\n accountId,\n widgetName,\n slug: component.slug,\n image: component.image,\n name: component.name,\n tags: component.tags,\n variant: \"nearcatalog\",\n searchPosition: i,\n });\n }\n return components;\n};\n\nconst categorizeSearchHits = (rawResp) => {\n const results = {};\n for (const [i, result] of rawResp.hits?.entries()) {\n const { categories: categories_raw } = result;\n if (categories_raw.length > 1) {\n categories_raw.sort();\n }\n\n const categories = categories_raw.join(\", \");\n results[categories] = results[categories] || [];\n results[categories].push([i + 1, result]);\n }\n return {\n results,\n hitsTotal: rawResp.nbHits,\n hitsPerPage: rawResp.hitsPerPage,\n };\n};\n\nconst debounce = (callable, timeout) => {\n return (args) => {\n clearTimeout(state.timer);\n State.update({\n timer: setTimeout(() => callable(args), timeout ?? 250),\n });\n };\n};\n\nconst fetchSearchHits = (query, { pageNumber, configs, optionalFilters }) => {\n configs = configs ?? configsPerFacet(state.facet);\n let body = {\n query,\n page: pageNumber ?? 0,\n optionalFilters: optionalFilters ?? [\n \"categories:nearcatalog<score=4>\",\n \"categories:profile<score=3>\",\n \"categories:widget<score=2>\",\n \"categories:post<score=1>\",\n \"categories:comment<score=0>\",\n ],\n clickAnalytics: true,\n ...configs,\n };\n\n return asyncFetch(API_URL, {\n body: JSON.stringify(body),\n headers: {\n \"Content-Type\": \"application/json; charset=UTF-8\",\n \"X-Algolia-Api-Key\": SEARCH_API_KEY,\n \"X-Algolia-Application-Id\": APPLICATION_ID,\n },\n method: \"POST\",\n });\n};\n\nconst updateSearchHits = debounce(({ term, pageNumber, configs }) => {\n fetchSearchHits(term, { pageNumber, configs }).then((resp) => {\n const { results, hitsTotal, hitsPerPage } = categorizeSearchHits(resp.body);\n State.update({\n search: {\n profiles: profiles(results[\"profile\"]),\n components: components(results[\"app, widget, nearcatalog\"])\n .concat(components(results[\"widget\"]))\n .concat(nearcatalog(results[\"nearcatalog\"])),\n postsAndComments: posts(results[\"post\"], \"post\").concat(posts(results[\"comment, post\"], \"post-comment\")),\n },\n currentPage: pageNumber,\n paginate: {\n hitsTotal,\n hitsPerPage,\n },\n queryID: resp.body.queryID,\n });\n });\n});\n\nconst onSearchChange = ({ term }) => {\n writeStateTerm(term);\n updateSearchHits({ term, pageNumber: INITIAL_PAGE });\n};\n\nconst onPageChange = (pageNumber) => {\n const algoliaPageNumber = pageNumber - 1;\n if (algoliaPageNumber === state.currentPage) {\n console.log(`Selected the same page number as before: ${pageNumber}`);\n return;\n }\n // Need to clear out old search data otherwise we'll get multiple entries\n // from the previous pages as well. Seems to be cache issue on near.social.\n State.update({\n search: undefined,\n currentPage: algoliaPageNumber,\n });\n updateSearchHits({ term: state.term, pageNumber: algoliaPageNumber });\n};\n\nconst FACET_TO_CATEGORY = {\n People: \"profile\",\n Apps: \"app\",\n Components: \"widget\",\n Posts: \"post\",\n};\n\nconst searchFilters = (facet) => {\n const category = FACET_TO_CATEGORY[facet];\n let filters = category ? `categories:${category}` : undefined;\n if (category === \"post\") {\n filters = `(${filters} OR categories:comment)`;\n }\n if (category === \"app\") {\n filters = `(${filters} OR tags:app OR categories:nearcatalog)`;\n }\n if (filters) {\n filters = `${filters} AND `;\n }\n filters = `${filters}NOT author:hypefairy.near AND NOT _tags:hidden`;\n\n return filters;\n};\n\nconst restrictSearchable = (facet) => {\n const category = FACET_TO_CATEGORY[facet];\n let restrictSearchableAttrs = undefined;\n if (category === \"post\") {\n // Only the content should be searchable when the posts facet is selected.\n restrictSearchableAttrs = [\"content\"];\n }\n return restrictSearchableAttrs;\n};\n\nconst configsPerFacet = (facet) => {\n return {\n filters: searchFilters(facet),\n restrictSearchableAttributes: restrictSearchable(facet),\n };\n};\n\nconst onFacetClick = (facet) => {\n if (facet === state.facet) {\n console.log(\"Clicked the same facet\");\n return;\n }\n\n State.update({\n facet,\n });\n\n updateSearchHits({\n term: state.term,\n configs: configsPerFacet(facet),\n });\n};\n\nconst onSearchResultClick = ({ searchPosition, objectID, eventName }) => {\n const position = searchPosition + state.currentPage * state.paginate.hitsPerPage;\n const event = {\n type: \"clickedObjectIDsAfterSearch\",\n data: {\n eventName,\n userToken: userId.replace(\".\", \"+\"),\n queryID: state.queryID,\n objectIDs: [objectID],\n positions: [position],\n timestamp: Date.now(),\n },\n };\n\n // Deferred due to State.update causing multiple clicks to be needed\n // before the browser redirect to the page the user clicks on.\n setTimeout(() => {\n // This will trigger the Insights widget:\n State.update({ event });\n }, 50);\n};\n\nreturn (\n <Wrapper>\n {showHeader &&\n (renderHeader ? (\n renderHeader(state.search, state.paginate)\n ) : (\n <Header>\n <H1>Search</H1>\n <H2>Explore and find everything on the Blockchain Operating System</H2>\n </Header>\n ))}\n\n {showSearchBar && (\n <Search>\n <Widget\n src=\"near/widget/Search.Pill\"\n props={{\n onChange: onSearchChange,\n term: props.term,\n }}\n />\n </Search>\n )}\n\n {showFacets && state.search && (\n <Facets>\n <Widget\n src=\"near/widget/Search.FullPage.Facets\"\n props={{\n facets,\n onFacetClick,\n defaultFacet: facets[0],\n initialFacet: tab,\n }}\n />\n </Facets>\n )}\n\n {state.paginate?.hitsTotal == 0 && <H2>No matches were found for \"{state.term}\".</H2>}\n\n {state.search?.profiles.length > 0 && (\n <Group>\n <GroupHeader>\n <H3>People</H3>\n <TextLink href={peopleUrl} small>\n View All\n </TextLink>\n </GroupHeader>\n\n <Items>\n {state.search.profiles.map((profile, i) => (\n <Item key={profile.accountId}>\n <Widget\n src=\"near/widget/Search.FullPage.AccountProfileCard\"\n props={{\n accountId: profile.accountId,\n onClick: () =>\n onSearchResultClick({\n searchPosition: profile.searchPosition,\n objectID: `${profile.accountId}/profile`,\n eventName: \"Clicked Profile After Search\",\n }),\n }}\n />\n </Item>\n ))}\n </Items>\n </Group>\n )}\n\n {state.search?.components.length > 0 && (\n <Group>\n <GroupHeader>\n <H3>Components</H3>\n <TextLink href={componentsUrl} small>\n View All\n </TextLink>\n </GroupHeader>\n\n <Items>\n {state.search.components.map((component, i) => {\n const isNearCatalogItem = component.variant && component.variant === \"nearcatalog\";\n const componentSrc = isNearCatalogItem\n ? `${component.accountId}/widget/${component.widgetName}?id=${component.slug}`\n : `${component.accountId}/widget/${component.widgetName}`;\n const componentProps = isNearCatalogItem\n ? { image: component.image, name: component.name, tags: component.tags, variant: component.variant }\n : {};\n return (\n <Item key={componentSrc}>\n <Widget\n src=\"near/widget/Search.FullPage.ComponentCard\"\n props={{\n src: componentSrc,\n ...componentProps,\n onClick: () =>\n onSearchResultClick({\n searchPosition: component.searchPosition,\n objectID: `${component.accountId}/widget/${component.widgetName}`,\n eventName: \"Clicked Component After Search\",\n }),\n }}\n />\n </Item>\n );\n })}\n </Items>\n </Group>\n )}\n\n {state.search?.postsAndComments.length > 0 && (\n <Group>\n <GroupHeader>\n <H3>Posts and Comments</H3>\n </GroupHeader>\n\n <Items>\n {state.search.postsAndComments.map((post, i) => (\n <Item key={`${post.accountId}/${post.postType}/${post.blockHeight}`}>\n <Widget\n src=\"near/widget/Search.FullPage.PostCard\"\n props={{\n accountId: post.accountId,\n blockHeight: post.blockHeight,\n content: post.postContent,\n snipContent: post.snipContent,\n postType: post.postType,\n onClick: () =>\n onSearchResultClick({\n searchPosition: post.searchPosition,\n objectID: `${post.accountId}/${post.postType}/${post.blockHeight}`,\n eventName: \"Clicked Post After Search\",\n }),\n }}\n />\n </Item>\n ))}\n </Items>\n </Group>\n )}\n\n {showPagination && state.paginate && state.paginate.hitsTotal > state.paginate.hitsPerPage && (\n <Widget\n src=\"near/widget/Search.Paginate\"\n props={{\n totalCount: state.paginate.hitsTotal,\n pageSize: state.paginate.hitsPerPage,\n onPageChange,\n }}\n />\n )}\n\n {!props.disableInsights && (\n <Widget\n src=\"near/widget/Search.Insights\"\n props={{\n event: state.event,\n searchApiKey: SEARCH_API_KEY,\n appId: APPLICATION_ID,\n index: INDEX,\n }}\n />\n )}\n\n {props.debug && (\n <div>\n <p>Debug Data:</p>\n <pre>{JSON.stringify(state, undefined, 2)}</pre>\n </div>\n )}\n </Wrapper>\n);\n"
},
"Search.TypeAheadDropdown": {
"": "const SEARCH_API_KEY = props.searchApiKey ?? \"fc7644a5da5306311e8e9418c24fddc4\";\nconst APPLICATION_ID = props.appId ?? \"B6PI9UKKJT\";\nconst INDEX = props.index ?? \"replica_prod_near-social-feed\";\nconst API_URL = props.apiUrl ?? `https://${APPLICATION_ID}-dsn.algolia.net/1/indexes/${INDEX}/query?`;\nconst INITIAL_PAGE = props.initialPage ?? 0;\nconst facets = props.facets ?? [\"All\", \"People\", \"Apps\", \"Components\", \"Posts\"];\nconst tab = props.tab ?? \"All\";\nconst showHeader = props.showHeader ?? true;\nconst showSearchBar = props.showSearchBar ?? true;\nconst showPagination = props.showPagination ?? true;\nconst userId = props.accountId ?? context.accountId;\nconst searchPageUrl = \"/near/widget/Search.IndexPage\";\nconst topmostCount = props.topmostCount ?? 3;\n\nState.init({\n currentPage: 0,\n selectedTab: tab,\n facet: tab,\n isFiltersPanelVisible: false,\n numColumns: 3,\n selectedTags: [],\n searchResults: [], // Assuming search results are stored here\n allTags: [],\n activeTags: [],\n showFollowed: false,\n showNotFollowed: false,\n});\n\n// Styling Specifications\n\nconst typeAheadContainer = {\n width: \"513px\",\n zIndex: \"3\",\n backgroundColor: \"black\",\n borderRadius: \"10px\",\n display: \"flex\",\n flexDirection: \"column\",\n textAlign: \"center\",\n justifyContent: \"center\",\n alignItems: \"center\",\n paddingLeft: \"24px\",\n paddingRight: \"24px\",\n};\n\nconst Wrapper = styled.div`\n display: flex;\n flex-direction: column;\n max-width: 600px;\n margin: 0 auto;\n\n width: 100%;\n`;\n\nconst NoResults = styled.div`\n padding: 16px;\n display: inline-flex;\n justify-content: center;\n align-items: center;\n font-size: 1.5rem;\n color: #444;\n`;\n\nconst Header = styled.div`\n display: flex;\n flex-direction: column;\n gap: 12px;\n`;\n\nconst Facets = styled.div`\n overflow: auto;\n`;\n\nconst H1 = styled.h1`\n font-weight: 600;\n font-size: 32px;\n line-height: 39px;\n color: #11181c;\n margin: 0;\n`;\n\nconst FixedTabs = styled.div`\n text-align: right;\n top: 0;\n`;\n\nconst H2 = styled.h2`\n display: ${(p) => p.$display ?? \"block\"};\n justify-content: ${(p) => p.$justifyContent ?? \"flex-start\"};\n align-items: ${(p) => p.$alignItems ?? \"flex-start\"};\n position: ${(p) => p.$position ?? \"relative\"};\n top: ${(p) => p.$top ?? \"0\"};\n left: ${(p) => p.$left ?? \"0\"};\n width: ${(p) => p.$width ?? \"auto\"};\n font-weight: 400;\n font-size: ${(p) => p.$fontSize ?? \"20px\"};\n line-height: 24px;\n color: #687076;\n margin: 0;\n`;\n\nconst H3 = styled.h3`\n color: #687076;\n font-weight: 600;\n font-size: 12px;\n line-height: 15px;\n text-transform: uppercase;\n margin: 0;\n`;\n\nconst Group = styled.div`\n display: flex;\n flex-direction: column;\n gap: 12px;\n margin: 10px;\n`;\n\nconst GroupHeader = styled.div`\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n`;\n\nconst Text = styled.p`\n margin: 0;\n line-height: 1.5rem;\n color: ${(p) => (p.bold ? \"#11181C\" : \"#687076\")};\n font-weight: ${(p) => (p.bold ? \"600\" : \"400\")};\n font-size: ${(p) => (p.small ? \"12px\" : \"14px\")};\n overflow: ${(p) => (p.ellipsis ? \"hidden\" : \"\")};\n text-overflow: ${(p) => (p.ellipsis ? \"ellipsis\" : \"\")};\n white-space: ${(p) => (p.ellipsis ? \"nowrap\" : \"\")};\n overflow-wrap: anywhere;\n\n b {\n font-weight: 600;\n color: #11181c;\n }\n`;\n\nconst Items = styled.div`\n display: flex;\n flex-direction: column;\n gap: 12px;\n`;\n\nconst Tabs = styled.div`\n display: flex;\n height: 48px;\n border-bottom: 1px solid #eceef0;\n overflow: auto;\n scroll-behavior: smooth;\n\n @media (max-width: 1024px) {\n background: #f8f9fa;\n border-top: 1px solid #eceef0;\n margin-left: -12px;\n margin-right: -12px;\n\n > * {\n flex: 1;\n }\n }\n`;\n\nconst ButtonLink = styled(\"Link\")`\n background-color: transparent;\n border: none;\n font-size: 14px;\n font-weight: 600;\n color: #9799f8;\n cursor: pointer;\n padding: 0;\n text-decoration: underline;\n text-align:right &:hover {\n color: #9799f8;\n }\n`;\n\nconst FixedFooter = styled.div`\n text-align: right;\n border-top: 1px solid rgba(96, 109, 122, 0.4);\n bottom: 0;\n padding-bottom: 10px;\n left: 16px;\n right: 16px;\n text-align: right;\n width: 100%;\n justify-content: center;\n padding: 16px 16px 16px 16px;\n`;\n\nconst TabsButton = styled(\"Link\")`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n font-weight: 600;\n font-size: 12px;\n padding: 0 12px;\n position: relative;\n color: ${(p) => (p.selected ? \"#11181C\" : \"#687076\")};\n background: none;\n border: none;\n outline: none;\n text-align: center;\n text-decoration: none !important;\n\n &:hover {\n color: #11181c;\n }\n\n &::after {\n content: \"\";\n display: ${(p) => (p.selected ? \"block\" : \"none\")};\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: #59e692;\n }\n`;\n\nconst ScrollableContent = styled.div`\n overflow: auto;\n flex-grow: 1;\n width: 100%;\n height: 350px;\n`;\n\nconst Item = styled.div``;\n\nconst DisplayResultsByFacet = ({ title, count, items }) => (\n <Group>\n <GroupHeader>\n <H3>\n {title}\n <span\n style={{\n marginLeft: \"10px\",\n }}\n >\n {count}\n </span>\n </H3>\n </GroupHeader>\n <Items>{items}</Items>\n </Group>\n);\n\nconst TextMessage = ({ message, ...props }) => (\n <H2\n $display=\"flex\"\n $justifyContent=\"center\"\n $alignItems=\"center\"\n $position=\"absolute\"\n $fontSize=\"15px\"\n $width=\"100%\"\n $top=\"40%\"\n $left=\"-0%\"\n {...props}\n >\n {message}\n </H2>\n);\n\n//*********SEARCH FUNCTIONS ******** */\n\n// Reset Search Results\nconst resetSearcheHits = () => {\n State.update({\n currentPage: 0,\n paginate: undefined,\n facet: undefined,\n profiles: undefined,\n apps: undefined,\n components: undefined,\n postsAndComments: undefined,\n });\n};\n\n// updates search params as the user enters in a search value\nconst writeStateTerm = (term) => {\n State.update({\n term,\n });\n\n if (term === \"\") {\n resetSearcheHits();\n }\n};\n\n// creates an array of profiles\nconst profiles = (records) => {\n const profiles = [];\n for (const [i, record] of records ?? []) {\n profiles.push({\n accountId: record.author,\n profile_name: record.profile_name,\n searchPosition: i,\n });\n }\n return profiles;\n};\n\n// creates an array of objects that provide the details of the loaded posts\nconst posts = (content, postType) => {\n const posts = [];\n for (const [i, post] of content || []) {\n const accountId = post.author;\n const blockHeight = post.objectID.split(\"/\").slice(-1)[0];\n const postContent = {\n type: \"md\",\n text: post.content,\n };\n const headerStyling = postType === \"post\" ? \"border rounded-4 p-3 pb-1\" : \"pt-3 border-top pb-2\";\n\n posts.push({\n accountId,\n blockHeight,\n postContent,\n postType,\n headerStyling,\n searchPosition: i,\n });\n }\n return posts;\n};\n\n// creates an array of components\nconst components = (records, app) => {\n const components = [];\n for (const [i, component] of records || []) {\n const idParts = component.objectID.split(\"/\");\n const widgetName = idParts[idParts.length - 1];\n const accountId = component.author;\n components.push({\n app,\n accountId,\n widgetName,\n searchPosition: i,\n });\n }\n return components;\n};\n\n// creates an array of components\nconst nearcatalog = (records) => {\n const components = [];\n for (const [i, component] of records || []) {\n const widgetName = \"Index\";\n const accountId = \"nearcatalog.near\";\n components.push({\n accountId,\n widgetName,\n slug: component.slug,\n image: component.image,\n name: component.name,\n variant: \"nearcatalog\",\n searchPosition: i,\n });\n }\n return components;\n};\n\nconst categorizeSearchHits = (rawResp) => {\n const results = {};\n for (const [i, result] of rawResp.hits?.entries()) {\n const { categories: categories_raw } = result;\n if (categories_raw.length > 1) {\n categories_raw.sort();\n }\n\n const categories = categories_raw.join(\", \");\n results[categories] = results[categories] || [];\n results[categories].push([i + 1, result]);\n }\n return {\n results,\n hitsTotal: rawResp.nbHits,\n hitsPerPage: rawResp.hitsPerPage,\n };\n};\n\nconst debounce = (callable, timeout) => {\n return (args) => {\n clearTimeout(state.timer);\n State.update({\n timer: setTimeout(() => callable(args), timeout ?? 150),\n });\n };\n};\n\nconst fetchSearchHits = (query, { pageNumber, configs }) => {\n let body = {\n query,\n page: pageNumber ?? 0,\n clickAnalytics: true,\n ...configs,\n };\n return asyncFetch(API_URL, {\n body: JSON.stringify(body),\n headers: {\n \"Content-Type\": \"application/json; charset=UTF-8\",\n \"X-Algolia-Api-Key\": SEARCH_API_KEY,\n \"X-Algolia-Application-Id\": APPLICATION_ID,\n },\n method: \"POST\",\n });\n};\n\nconst updateSearchHits = debounce(({ term, pageNumber }) => {\n const localState = {\n hitsTotal: 0,\n lastUpdatedHitsTotal: 0,\n };\n // NOTE: This puts all search results into state directly instead of categorized\n // under `search`. This is due to how many times the state is updated and reading the\n // state with current near social isn't feasible.\n const updateStateAfterFetching = (facet) => {\n return (resp) => {\n const { results, hitsTotal, hitsPerPage } = categorizeSearchHits(resp.body);\n\n if (facet === \"People\") {\n State.update({\n profiles: {\n hitsTotal,\n hitsPerPage,\n hits: profiles(results[\"profile\"]),\n queryID: resp.body.queryID,\n },\n });\n } else if (facet === \"Apps\") {\n State.update({\n apps: {\n hitsTotal,\n hitsPerPage,\n hits: components(results[\"app, widget, nearcatalog\"])\n .concat(components(results[\"widget\"]))\n .concat(nearcatalog(results[\"nearcatalog\"])),\n queryID: resp.body.queryID,\n },\n });\n } else if (facet === \"Components\") {\n State.update({\n components: {\n hitsTotal,\n hitsPerPage,\n hits: components(results[\"widget\"]),\n queryID: resp.body.queryID,\n },\n });\n } else {\n State.update({\n postsAndComments: {\n hitsTotal,\n hitsPerPage,\n hits: posts(results[\"post\"], \"post\").concat(posts(results[\"comment, post\"], \"post-comment\")),\n queryID: resp.body.queryID,\n },\n });\n }\n\n localState.hitsTotal += hitsTotal;\n if (localState.hitsTotal >= localState.lastUpdatedHitsTotal) {\n localState.lastUpdatedHitsTotal = localState.hitsTotal;\n State.update({\n paginate: {\n hitsPerPage,\n hitsTotal: localState.hitsTotal,\n },\n });\n }\n };\n };\n\n for (const facet of facets.filter((i) => i !== \"All\")) {\n fetchSearchHits(term, {\n pageNumber,\n configs: configsPerFacet(facet),\n }).then(updateStateAfterFetching(facet));\n }\n});\n\nconst onSearchChange = ({ term }) => {\n writeStateTerm(term);\n updateSearchHits({ term, pageNumber: INITIAL_PAGE });\n};\n\nconst FACET_TO_CATEGORY = {\n People: \"profile\",\n Apps: \"app\",\n Components: \"widget\",\n Posts: \"post\",\n};\n\nconst FACET_TO_FILTER = {\n People: \"categories:profile\",\n Apps: \"(categories:app OR tags:app OR categories:nearcatalog)\",\n Components: \"categories:widget\",\n Posts: \"(categories:post OR categories:comment)\",\n};\n\nconst searchFilters = (facet) => {\n let filters = FACET_TO_FILTER[facet];\n if (filters) {\n filters = `${filters} AND `;\n }\n return `${filters}NOT author:hypefairy.near AND NOT _tags:hidden`;\n};\n\nconst restrictSearchable = (facet) => {\n const category = FACET_TO_CATEGORY[facet];\n let restrictSearchableAttrs = undefined;\n if (category === \"post\") {\n // Only the content should be searchable when the posts facet is selected.\n restrictSearchableAttrs = [\"content\"];\n }\n return restrictSearchableAttrs;\n};\n\nconst configsPerFacet = (facet) => {\n return {\n filters: searchFilters(facet),\n restrictSearchableAttributes: restrictSearchable(facet),\n };\n};\n\nconst onFacetClick = (facet) => {\n if (facet === state.selectedTab) {\n return;\n }\n\n State.update({\n selectedTab: facet,\n });\n\n displayResultsByFacet(facet);\n};\n\nconst handleCloseSearchMenu = () => {\n props.focusChange(false);\n};\n\nconst onSearchResultClick = ({ searchPosition, queryID, objectID, eventName }) => {\n const position = searchPosition + state.currentPage * state.paginate.hitsPerPage;\n const event = {\n type: \"clickedObjectIDsAfterSearch\",\n data: {\n eventName,\n queryID,\n userToken: userId.replace(\".\", \"+\"),\n objectIDs: [objectID],\n positions: [position],\n timestamp: Date.now(),\n },\n };\n\n // Deferred due to State.update causing multiple clicks to be needed\n // before the browser redirect to the page the user clicks on.\n setTimeout(() => {\n // This will trigger the Insights widget:\n State.update({ event });\n }, 100);\n};\n\nconst topmostAccounts = () => {\n let output = [];\n\n if (state.selectedTab === \"People\") {\n for (let i = 0; i < 6; i++) {\n if (i < state.profiles.hits.length) {\n output.push(state.profiles.hits[i]);\n }\n }\n } else {\n output = state.profiles.hits.slice(0, topmostCount);\n }\n\n return output.map((profile) => (\n <Item key={profile.accountId} onClick={handleCloseSearchMenu}>\n <Widget\n src=\"near/widget/Search.DropdownAccountCard\"\n props={{\n accountId: profile.accountId,\n profile_name: profile.profile_name,\n onClick: () =>\n onSearchResultClick({\n queryID: state.profiles.queryID,\n searchPosition: profile.searchPosition,\n objectID: `${profile.accountId}/profile`,\n eventName: \"Clicked Profile After Search\",\n }),\n }}\n />\n </Item>\n ));\n};\n\nconst tabCount = (tab) => {\n switch (tab) {\n case \"All\":\n // Return the count for All\n return state.paginate?.hitsTotal;\n case \"People\":\n // Return the count for People\n return state.profiles.hitsTotal ?? 0;\n case \"Apps\":\n // Return the count for Apps\n return state.apps.hitsTotal ?? 0;\n case \"Components\":\n // Return the count for Components\n return state.components.hitsTotal ?? 0;\n case \"Posts\":\n // Return the count for Posts\n return state.postsAndComments.hitsTotal ?? 0;\n default:\n // Return 0 if the tab name is not in the list\n return 0;\n }\n};\n\nconst topmostComponents = (apps) => {\n let output = [];\n if (state.selectedTab === \"Components\" || state.selectedTab === \"Apps\") {\n if (state.selectedTab === \"Components\") {\n output = state.components.hits.slice(0, 6);\n } else if (state.selectedTab === \"Apps\") {\n output = state.apps.hits.slice(0, 6);\n }\n } else {\n if (apps) {\n output = state.apps.hits.slice(0, topmostCount);\n } else {\n output = state.components.hits.slice(0, topmostCount);\n }\n }\n\n const queryID = apps ? state.apps.queryID : state.components.queryID;\n const eventName = apps ? \"App\" : \"Component\";\n return output.map((component, i) => {\n const isNearCatalogItem = component.variant && component.variant === \"nearcatalog\";\n const componentSrc = isNearCatalogItem\n ? `${component.accountId}/widget/${component.widgetName}?id=${component.slug}`\n : `${component.accountId}/widget/${component.widgetName}`;\n const componentProps = isNearCatalogItem\n ? { image: component.image, name: component.name, variant: component.variant }\n : {};\n return (\n <Item key={componentSrc} onClick={handleCloseSearchMenu}>\n <Widget\n src=\"near/widget/Search.ComponentCard\"\n props={{\n src: componentSrc,\n ...componentProps,\n onClick: () =>\n onSearchResultClick({\n queryID,\n searchPosition: component.searchPosition,\n objectID: `${component.accountId}/widget/${component.widgetName}`,\n eventName: `Clicked ${eventName} After Search`,\n }),\n }}\n />\n </Item>\n );\n });\n};\n\nconst topmostNEARCatalogComponents = () => {\n let output = state.nearcatalog.hits.slice(0, 5);\n\n const queryID = state.nearcatalog.queryID;\n const eventName = \"Component\";\n return output.map((component, i) => (\n <Item\n key={`${component.accountId}/widget/${component.widgetName}/${component.slug}`}\n onClick={handleCloseSearchMenu}\n >\n <Widget\n src=\"near/widget/Search.ComponentCard\"\n props={{\n src: `${component.accountId}/widget/${component.widgetName}?id=${component.slug}`,\n variant: \"nearcatalog\",\n name: component.name,\n image: component.image,\n onClick: () =>\n onSearchResultClick({\n queryID,\n searchPosition: component.searchPosition,\n objectID: `${component.accountId}/widget/${component.widgetName}?id=${component.slug}`,\n eventName: `Clicked ${eventName} After Search`,\n }),\n }}\n />\n </Item>\n ));\n};\n\nconst topmostPosts = () => {\n let output = [];\n\n if (state.selectedTab === \"Posts\") {\n for (let i = 0; i < 6; i++) {\n if (i < state.postsAndComments.hitsTotal) {\n output.push(state.postsAndComments.hits[i]);\n }\n }\n } else {\n output = state.postsAndComments.hits.slice(0, topmostCount);\n }\n\n return output.map((post, i) => (\n <Item key={`${post.accountId}/${post.postType}/${post.blockHeight}`} onClick={handleCloseSearchMenu}>\n <Widget\n src=\"near/widget/Search.PostCard\"\n props={{\n accountId: post.accountId,\n blockHeight: post.blockHeight,\n content: post.postContent,\n term: props.term,\n snipContent: true,\n onClick: () =>\n onSearchResultClick({\n queryID: state.postsAndComments.queryID,\n searchPosition: post.searchPosition,\n objectID: `${post.accountId}/${post.postType}/${post.blockHeight}`,\n eventName: \"Clicked Post After Search\",\n }),\n }}\n />\n </Item>\n ));\n};\n\nconst displayResultsByFacet = (selectedTab) => {\n switch (selectedTab) {\n case \"People\":\n return state.profiles.hits?.length > 0 ? (\n <DisplayResultsByFacet title=\"People\" count={state.profiles.hitsTotal} items={topmostAccounts()} />\n ) : (\n <TextMessage message={`No People matches were found for \"${state.term}\".`} />\n );\n case \"Apps\": {\n return state.apps.hits?.length > 0 ? (\n <DisplayResultsByFacet title=\"Apps\" count={state.apps.hitsTotal} items={topmostComponents(true)} />\n ) : (\n <>\n <TextMessage message={`No App matches were found for \"${state.term}\".`} />\n <TextMessage\n message={`Trying to find a app built by an user? Try search their account id.`}\n $fontSize=\"12px\"\n $top=\"45%\"\n />{\" \"}\n </>\n );\n }\n\n case \"Components\":\n return state.components.hits?.length > 0 ? (\n <DisplayResultsByFacet title=\"Components\" count={state.components.hitsTotal} items={topmostComponents(false)} />\n ) : (\n <>\n <TextMessage message={`No Component matches were found for \"${state.term}\".`} />\n <TextMessage\n message={`Trying to find a app built by an user? Try search their account id.`}\n $fontSize=\"12px\"\n $top=\"45%\"\n />{\" \"}\n </>\n );\n case \"Posts\":\n return state.postsAndComments.hits?.length > 0 ? (\n <DisplayResultsByFacet\n title=\"Posts and Comments\"\n count={state.postsAndComments.hitsTotal}\n items={topmostPosts()}\n />\n ) : (\n <TextMessage message={`No Post matches were found for \"${state.term}\".`} />\n );\n case \"All\":\n return (\n <>\n {state.profiles.hits?.length > 0 && (\n <DisplayResultsByFacet title=\"People\" count={state.profiles.hitsTotal} items={topmostAccounts()} />\n )}\n {state.apps.hits?.length > 0 && (\n <DisplayResultsByFacet title=\"Apps\" count={state.apps.hitsTotal} items={topmostComponents(true)} />\n )}\n {state.components.hits?.length > 0 && (\n <DisplayResultsByFacet\n title=\"Components\"\n count={state.components.hitsTotal}\n items={topmostComponents(false)}\n />\n )}\n {state.postsAndComments.hits?.length > 0 && (\n <DisplayResultsByFacet\n title=\"Posts and Comments\"\n count={state.postsAndComments.hitsTotal}\n items={topmostPosts()}\n />\n )}\n </>\n );\n }\n};\n\nif (props.term !== state.lastSyncedTerm) {\n State.update({\n lastSyncedTerm: props.term,\n });\n onSearchChange({ term: props.term });\n}\n\nconst encodeURIComponent = (text) => {\n const hexDigits = \"0123456789ABCDEF\";\n const result = [];\n for (var i = 0; i < text.length; i++) {\n const c = text.charCodeAt(i);\n if (\n (c >= 48 /*0*/ && c <= 57) /*9*/ ||\n (c >= 97 /*a*/ && c <= 122) /*z*/ ||\n (c >= 65 /*A*/ && c <= 90) /*Z*/ ||\n c == 45 /*-*/ ||\n c == 95 /*_*/ ||\n c == 46 /*.*/ ||\n c == 33 /*!*/ ||\n c == 126 /*~*/ ||\n c == 42 /***/ ||\n c == 92 /*\\\\*/ ||\n c == 40 /*(*/ ||\n c == 41 /*)*/\n ) {\n result.push(text[i]);\n } else {\n const firstHexDigit = hexDigits.charAt((c & 0xf0) / 16);\n const secondHexDigit = hexDigits.charAt(c & 0x0f);\n result.push(`%${firstHexDigit}${secondHexDigit}`);\n }\n }\n return result.join(\"\");\n};\n\nreturn (\n <div style={typeAheadContainer}>\n <Wrapper>\n <FixedTabs>\n <Widget\n src=\"near/widget/Search.Facets\"\n props={{\n facets,\n onFacetClick,\n defaultFacet: facets[0],\n }}\n />\n </FixedTabs>\n <ScrollableContent>\n {state.paginate?.hitsTotal == 0 && state.selectedTab == \"All\" && (\n <H2\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n position: \"absolute\",\n top: \"40%\", // Adjust this value to position the text lower\n width: \"100%\",\n fontSize: \"15px\",\n left: \"-0%\",\n }}\n >\n No matches were found for \"{state.term}\".\n </H2>\n )}\n {displayResultsByFacet(state.selectedTab)}\n </ScrollableContent>\n\n <FixedFooter>\n <ButtonLink\n href={`${searchPageUrl}?term=${encodeURIComponent(props.term)}&tab=${state.selectedTab}`}\n onClick={handleCloseSearchMenu}\n >\n {state.paginate?.hitsTotal > 0 && ` See ${tabCount(state.selectedTab)} Results`}\n </ButtonLink>\n </FixedFooter>\n\n {!props.disableInsights && (\n <Widget\n src=\"near/widget/Search.Insights\"\n props={{\n event: state.event,\n searchApiKey: SEARCH_API_KEY,\n appId: APPLICATION_ID,\n index: INDEX,\n }}\n />\n )}\n </Wrapper>\n </div>\n);\n"
},
"Search.FullPage.ComponentCard": {
"": "const [accountId, widget, widgetName] = props.src.split(\"/\");\nconst variant = props.variant ?? \"default\";\nconst metadata =\n variant === \"nearcatalog\"\n ? { image: props.image, name: props.name, tags: props.tags }\n : Social.get(`${accountId}/widget/${widgetName}/metadata/**`, \"final\");\nconst tags = metadata.tags && Array.isArray(metadata.tags) ? metadata.tags : Object.keys(metadata.tags || {});\nconst appUrl = `/${accountId}/widget/${widgetName}`;\nconst detailsUrl =\n variant === \"nearcatalog\"\n ? appUrl\n : `/near/widget/ComponentDetailsPage?src=${accountId}/widget/${widgetName}`;\nconst accountUrl = `/near/widget/ProfilePage?accountId=${accountId}`;\nconst onPointerUp =\n props.onClick ??\n ((event) => {\n if (props.debug) {\n console.log(\"click\", event);\n }\n });\n\nconst Card = styled.div`\n position: relative;\n width: 100%;\n border-radius: 12px;\n background: #fff;\n border: 1px solid #eceef0;\n box-shadow:\n 0px 1px 3px rgba(16, 24, 40, 0.1),\n 0px 1px 2px rgba(16, 24, 40, 0.06);\n overflow: hidden;\n`;\n\nconst CardBody = styled.div`\n padding: 16px;\n display: flex;\n gap: 16px;\n align-items: center;\n\n > * {\n min-width: 0;\n }\n`;\n\nconst CardContent = styled.div`\n width: 100%;\n`;\n\nconst CardFooter = styled.div`\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 16px;\n padding: 16px;\n border-top: 1px solid #eceef0;\n`;\n\nconst CardTag = styled.p`\n margin: 0;\n font-size: 9px;\n line-height: 14px;\n background: #eceef0;\n color: #687076;\n font-weight: 400;\n white-space: nowrap;\n position: absolute;\n top: 0;\n right: 0;\n border-bottom-left-radius: 3px;\n padding: 0 4px;\n\n i {\n margin-right: 3px;\n }\n`;\n\nconst TextLink = styled(\"Link\")`\n display: block;\n margin: 0;\n font-size: 14px;\n line-height: 18px;\n color: ${(p) => (p.bold ? \"#11181C !important\" : \"#687076 !important\")};\n font-weight: ${(p) => (p.bold ? \"600\" : \"400\")};\n font-size: ${(p) => (p.small ? \"12px\" : \"14px\")};\n overflow: ${(p) => (p.ellipsis ? \"hidden\" : \"visible\")};\n text-overflow: ${(p) => (p.ellipsis ? \"ellipsis\" : \"unset\")};\n white-space: nowrap;\n outline: none;\n\n &:focus,\n &:hover {\n text-decoration: underline;\n }\n`;\n\nconst Text = styled.p`\n margin: 0;\n font-size: 14px;\n line-height: 20px;\n color: ${(p) => (p.bold ? \"#11181C\" : \"#687076\")};\n font-weight: ${(p) => (p.bold ? \"600\" : \"400\")};\n font-size: ${(p) => (p.small ? \"12px\" : \"14px\")};\n overflow: ${(p) => (p.ellipsis ? \"hidden\" : \"\")};\n text-overflow: ${(p) => (p.ellipsis ? \"ellipsis\" : \"\")};\n white-space: nowrap;\n\n i {\n margin-right: 3px;\n }\n`;\n\nconst Thumbnail = styled(\"Link\")`\n display: block;\n width: 60px;\n height: 60px;\n flex-shrink: 0;\n border: 1px solid #eceef0;\n border-radius: 8px;\n overflow: hidden;\n outline: none;\n transition: border-color 200ms;\n\n &:focus,\n &:hover {\n border-color: #d0d5dd;\n }\n\n img {\n object-fit: cover;\n width: 100%;\n height: 100%;\n }\n`;\n\nconst TagsWrapper = styled.div`\n position: relative;\n margin-top: 4px;\n`;\n\nconst ButtonLink = styled(\"Link\")`\n padding: 8px;\n height: 32px;\n border: 1px solid #d7dbdf;\n border-radius: 100px;\n font-weight: 600;\n font-size: 12px;\n line-height: 15px;\n text-align: center;\n cursor: pointer;\n color: ${(p) => (p.primary ? \"#006ADC\" : \"#11181C\")} !important;\n background: #fbfcfd;\n white-space: nowrap;\n\n &:hover,\n &:focus {\n background: #ecedee;\n text-decoration: none;\n outline: none;\n }\n`;\n\nreturn (\n <Card>\n {variant !== \"nearcatalog\" && (\n <CardTag>\n <i className=\"bi bi-clock\"></i>{\" \"}\n <Widget\n src=\"mob.near/widget/TimeAgo@97556750\"\n props={{\n blockHeight: props.blockHeight,\n keyPath: `${accountId}/widget/${widgetName}`,\n }}\n />{\" \"}\n ago\n </CardTag>\n )}\n\n <CardBody>\n <Thumbnail href={detailsUrl} onPointerUp={onPointerUp}>\n <Widget\n src=\"mob.near/widget/Image\"\n props={{\n image: metadata.image,\n fallbackUrl: \"https://ipfs.near.social/ipfs/bafkreifc4burlk35hxom3klq4mysmslfirj7slueenbj7ddwg7pc6ixomu\",\n alt: metadata.name,\n }}\n />\n </Thumbnail>\n\n <CardContent>\n <TextLink href={detailsUrl} onPointerUp={onPointerUp} bold ellipsis>\n {metadata.name || widgetName}\n </TextLink>\n\n <TextLink small href={accountUrl} onPointerUp={onPointerUp} ellipsis>\n @{accountId}\n </TextLink>\n\n {tags.length > 0 && (\n <TagsWrapper>\n <Widget\n src=\"near/widget/Tags\"\n props={{\n tags,\n scroll: true,\n }}\n />\n </TagsWrapper>\n )}\n </CardContent>\n </CardBody>\n\n <CardFooter>\n <ButtonLink href={detailsUrl} onPointerUp={onPointerUp}>\n View Details\n </ButtonLink>\n <ButtonLink href={appUrl} onPointerUp={onPointerUp} primary>\n Open\n </ButtonLink>\n </CardFooter>\n </Card>\n);\n"
},
"Settings.Identity.Index": {
"": "let { idosConnected, connectIdOS, walletImages, connectedWallet, idosCreateAccountUrl, ...forwardedProps } = props;\n\nconst [showBanner, setShowBanner] = useState(true);\nconst [showSuccessTooltip, setShowSuccessTooltip] = useState(props.showTooltip);\n\nconst Wrapper = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 30px;\n`;\n\nconst Title = styled.h1`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font: var(--title-xl);\n font-weight: 600;\n font-size: ${(p) => (p.small ? \"20px\" : \"32px\")};\n line-height: 30px;\n margin: 0;\n user-select: none;\n`;\n\nconst Icon = styled.i`\n color: #697177;\n margin-left: 0.5rem;\n cursor: pointer;\n`;\n\nuseEffect(() => {\n if (connectIdOS) {\n connectIdOS();\n }\n}, [connectIdOS]);\n\nreturn (\n <Wrapper>\n <Title>Identity & data privacy</Title>\n\n {!idosConnected && (\n <Widget\n src=\"near/widget/Settings.Identity.Onboarding.Cards\"\n props={{\n idosConnected,\n connectIdOS,\n walletImages,\n connectedWallet,\n idosCreateAccountUrl,\n }}\n />\n )}\n\n {props.idosConnected && (\n <Widget src=\"near/widget/Settings.Identity.Verifications.Index\" props={{ ...forwardedProps }} />\n )}\n\n {showSuccessTooltip && (\n <Widget\n src=\"near/widget/DIG.Toast\"\n props={{\n type: \"success\",\n title: \"idOS connection successful\",\n description:\n \"idOS data view created. Your data will be displayed soon when your request has been reviewed and approved (approx 1 - 10 minutes).\",\n open: showSuccessTooltip,\n onOpenChange: () => {\n setShowSuccessTooltip(false);\n },\n duration: 10000,\n }}\n />\n )}\n </Wrapper>\n);\n"
},
"Settings.Identity.Onboarding.Cards": {
"": "let { idosConnected, connectIdOS, walletImages, connectedWallet, idosCreateAccountUrl } = props;\n\nconst idOSLearnLink = \"https://idos-1.gitbook.io/idos-docs\";\n\nconst Wrapper = styled.div`\n display: grid;\n grid-gap: 24px;\n grid-template-columns: repeat(2, 320px);\n justify-content: center;\n margin: 0 auto;\n`;\n\nconst Card = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n box-shadow:\n 0px 4px 4px 0px rgba(0, 0, 0, 0.1),\n 0px -1px 2px 0px rgba(0, 0, 0, 0.15);\n border-radius: 15px;\n background: ${(p) => p.background};\n width: 100%;\n height: 100%;\n gap: 24px;\n padding: 24px;\n`;\n\nconst Step = styled.div`\n display: flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n background: ${(p) => p.background};\n color: ${(p) => p.color};\n border-radius: 50%;\n`;\n\nconst Title = styled.h4`\n font: var(--text-s);\n color: ${(p) => p.color};\n font-weight: 700;\n`;\n\nconst ImagesWrapper = styled.div`\n display: flex;\n gap: 16px;\n flex: 1 0 auto;\n`;\n\nconst WalletImageWrapper = styled.div`\n display: flex;\n width: 60px;\n height: 60px;\n align-items: center;\n justify-content: center;\n position: relative;\n border-radius: 50%;\n background: var(--white);\n box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);\n opacity: ${(p) => (p.active ? \"1\" : \"0.5\")};\n transform: ${(p) => (p.active ? \"scale(1.3)\" : \"scale(1)\")};\n margin: auto 0;\n`;\n\nconst WalletImage = styled.img`\n width: 55px;\n height: 55px;\n padding: 4px;\n`;\n\nconst Checkmark = styled.i`\n position: absolute;\n top: -5px;\n right: -5px;\n display: block;\n background: var(--green8);\n border-radius: 50%;\n color: var(--white);\n font-size: 12px;\n padding: 4px;\n`;\n\nconst TextWrapper = styled.div`\n display: flex;\n flex-direction: column;\n gap: 16px;\n`;\n\nconst Text = styled.span`\n font: var(--text-base);\n color: ${(p) => p.color};\n`;\n\nconst TextLink = styled(\"Link\")`\n color: var(--violet8);\n text-decoration: underline;\n font-weight: 700;\n`;\n\nconst ImageWrapper = styled.div`\n padding: 0 24px;\n`;\n\nreturn (\n <Wrapper>\n <Card background=\"var(--white)\">\n <Step background=\"var(--sand12)\" color=\"var(--white)\">\n 1\n </Step>\n <Title>Log into idOS compatible wallet</Title>\n <ImagesWrapper>\n {walletImages &&\n walletImages.map((image) => (\n <WalletImageWrapper key={image.name} active={connectedWallet === image.name} title={image.name}>\n <WalletImage src={image.src} alt={image.name} />\n {connectedWallet === image.name && <Checkmark className=\"ph-bold ph-check\" />}\n </WalletImageWrapper>\n ))}\n </ImagesWrapper>\n <Widget\n src=\"near/widget/DIG.Button\"\n props={{\n variant: \"primary\",\n label: \"Sign In\",\n disabled: context.accountId,\n href: \"/near/widget/Settings.Index?requestAuth=1\",\n }}\n />\n </Card>\n\n <Card background=\"#0d0d0f\">\n <Step background=\"var(--white)\" color=\"var(--sand12)\">\n 2\n </Step>\n <Title color=\"var(--sand10)\">Log into idOS</Title>\n <ImageWrapper>\n <Widget\n src=\"mob.near/widget/Image\"\n props={{\n image: {\n ipfs_cid: \"bafkreigb7fwbwomsi2hg3to5tbapsnl43vfp6qdctnqhv5w4et7q5oqtnq\",\n },\n alt: \"log into idOS\",\n }}\n />\n </ImageWrapper>\n <TextWrapper>\n <Text color=\"var(--sand10)\">\n All your credentials and preferences on this settings page will be securely stored in a decentralized identity\n operating system (idOS). Sign in to view your data.\n </Text>\n <Text color=\"var(--sand10)\">\n Learn more about idOS\n <TextLink href={idOSLearnLink} target=\"_blank\">\n here\n </TextLink>\n </Text>\n </TextWrapper>\n <Widget\n src=\"near/widget/DIG.Button\"\n props={{\n variant: \"affirmative\",\n label: \"Sign In\",\n disabled: !context.accountId || idosConnected,\n href: idosCreateAccountUrl,\n }}\n />\n </Card>\n </Wrapper>\n);\n"
},
"Search.Insights": {
"": "const USER_TOKEN = props.userToken ?? \"anonymous\";\nconst SEARCH_API_KEY = props.searchApiKey;\nconst APPLICATION_ID = props.appId;\nconst INDEX = props.index;\nconst onChange =\n props.onChange ??\n ((resp) => {\n if (props.debug) {\n console.log(\"resp\", resp);\n }\n });\n\nconst code = `\n<script>\nvar ALGOLIA_INSIGHTS_SRC = \"https://cdn.jsdelivr.net/npm/search-insights@2.4.0/dist/search-insights.min.js\";\n!function(e,a,t,n,s,v,i,c){e.AlgoliaAnalyticsObject=s,e[s]=e[s]||function(){\n(e[s].queue=e[s].queue||[]).push(arguments)},e[s].version=(n.match(\"/@([^\\/]+)\\/?/\") || [])[1],i=a.createElement(t),c=a.getElementsByTagName(t)[0],\ni.async=1,i.src=n,c.parentNode.insertBefore(i,c)\n}(window,document,\"script\",ALGOLIA_INSIGHTS_SRC,\"aa\");\naa('init', {\n appId: '${APPLICATION_ID}',\n apiKey: '${SEARCH_API_KEY}',\n});\n\nwindow.top.postMessage(\"loaded\", \"*\");\nwindow.addEventListener(\"message\", (message) => {\n if (!message.data.event) {\n return;\n }\n\n const { type, data } = message.data.event;\n data[\"index\"] = \"${INDEX}\";\n const result = aa(type, data);\n message.source.postMessage({\n result,\n eventType: type,\n eventData: data,\n }, \"*\");\n}, false);\n</script>\n`;\n\nreturn (\n <iframe\n srcDoc={code}\n style={{ position: \"absolute\", width: 0, height: 0, border: 0 }}\n message={{ event: props.event }}\n onMessage={(resp) => onChange(resp)}\n />\n);\n"
},
"Search.ComponentCard": {
"": "const [accountId, widget, widgetName] = props.src.split(\"/\");\nconst variant = props.variant ?? \"default\";\nconst metadata =\n variant === \"nearcatalog\"\n ? { image: props.image, name: props.name }\n : Social.get(`${accountId}/widget/${widgetName}/metadata/**`, \"final\");\nconst appUrl = `/${accountId}/widget/${widgetName}`;\nconst detailsUrl =\n variant === \"nearcatalog\"\n ? appUrl\n : `/near/widget/ComponentDetailsPage?src=${accountId}/widget/${widgetName}`;\nconst accountUrl = `/near/widget/ProfilePage?accountId=${accountId}`;\nconst onPointerUp =\n props.onClick ??\n ((event) => {\n if (props.debug) {\n console.log(\"click\", event);\n }\n });\n\nconst Card = styled(\"Link\")`\n display: flex;\n flex-direction: row;\n align-items: center;\n width: 95%;\n height: 45px;\n overflow: hidden;\n gap: 16px;\n margin-left: 10px;\n`;\n\nconst Thumbnail = styled(\"Link\")`\n display: block;\n width: 40px;\n height: 40px;\n flex-shrink: 0;\n border: 1px solid #eceef0;\n border-radius: 8px;\n overflow: hidden;\n outline: none;\n transition: border-color 200ms;\n align-items: center;\n float: center;\n justify-content: center;\n &:focus,\n &:hover {\n border-color: #d0d5dd;\n }\n\n img {\n object-fit: cover;\n width: 100%;\n height: 100%;\n }\n`;\n\nconst HeaderAbove = styled.div`\n display: flex;\n align-items: center;\n flex: 1;\n`;\n\nconst Header = styled.div`\n display: inline-grid;\n width: 100%;\n align-items: center;\n gap: 12px;\n grid-template-columns: auto 1fr;\n cursor: pointer;\n margin: 0;\n color: #687076 !important;\n outline: none;\n text-decoration: none !important;\n background: none !important;\n border: none;\n text-align: left;\n padding: 0;\n\n > * {\n min-width: 0;\n }\n`;\n\nconst WidgetName = styled.div`\n display: flex;\n gap: 6px;\n align-items: center;\n`;\n\nconst Body = styled.div`\n margin: 0;\n align-items: center;\n flex: 1;\n font-size: 12px;\n overflow: ${(p) => (p.ellipsis ? \"hidden\" : \"\")};\n text-overflow: ${(p) => (p.ellipsis ? \"ellipsis\" : \"\")};\n`;\n\nconst TextLink = styled(\"Link\")`\n display: block;\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: ${(p) => (p.bold ? \"#FFFFFF !important\" : \"#606D7A !important\")};\n font-weight: ${(p) => (p.bold ? \"600\" : \"400\")};\n font-size: ${(p) => (p.small ? \"14px\" : \"14px\")};\n text-align: left;\n overflow: ${(p) => (p.ellipsis ? \"hidden\" : \"visible\")};\n text-overflow: ${(p) => (p.ellipsis ? \"ellipsis\" : \"unset\")};\n white-space: nowrap;\n outline: none;\n\n &:focus,\n &:hover {\n text-decoration: underline;\n }\n`;\n\nconst Text = styled.p`\n display: block;\n font-size: 12px;\n line-height: 20px;\n font-weight: 400;\n color: #687076;\n white-space: nowrap;\n\n i {\n font-size: 16px;\n }\n`;\n\nconst ButtonLink = styled(\"Link\")`\n display: inline-flex;\n align-items: right;\n justify-content: center;\n padding: 0;\n background: none;\n border: none;\n outline: none;\n cursor: pointer;\n\n img {\n width: 24px;\n height: 24px;\n }\n\n &:hover,\n &:focus {\n text-decoration: none;\n outline: none;\n }\n`;\n\nreturn (\n <Card>\n <HeaderAbove>\n <Header>\n <Thumbnail href={detailsUrl} onPointerUp={onPointerUp}>\n <Widget\n src=\"mob.near/widget/Image\"\n props={{\n image: metadata.image,\n fallbackUrl: \"https://ipfs.near.social/ipfs/bafkreifc4burlk35hxom3klq4mysmslfirj7slueenbj7ddwg7pc6ixomu\",\n alt: metadata.name,\n }}\n />\n </Thumbnail>\n <WidgetName>\n <TextLink href={detailsUrl} onPointerUp={onPointerUp} bold ellipsis>\n {metadata.name ?? widgetName}\n </TextLink>\n </WidgetName>\n </Header>\n </HeaderAbove>\n\n <Body ellipsis={true}>\n <TextLink href={accountUrl} onPointerUp={onPointerUp}>\n @{accountId}\n </TextLink>\n </Body>\n <ButtonLink href={appUrl} onPointerUp={onPointerUp}>\n <button\n style={{\n padding: \"10px 0px 10px 10px\",\n backgroundColor: \"rgba(255, 193, 7, 0)\",\n border: \"none\",\n borderRadius: \"5px\",\n cursor: \"pointer\",\n }}\n >\n <Link href={appUrl}>\n <Text small bold>\n <i className=\"bi bi-arrow-right\"></i>\n </Text>\n </Link>\n </button>\n </ButtonLink>\n </Card>\n);\n"
}
}
}
}
}