From 3ee70af7e0bcdf967d8a48fa5ff738ffac485fc7 Mon Sep 17 00:00:00 2001 From: matthew Date: Mon, 10 Oct 2022 20:02:27 +0400 Subject: [PATCH] add favicons --- .../components/WebsiteCard/WebsiteCard.tsx | 17 +++++++++++++- .../components/WebsiteCard/styles.module.css | 16 +++++++++++++ .../app/core/layouts/Layout/styles.module.css | 2 +- .../queries/getSearchResult.ts | 1 + .../services/modules/elastic/index.ts | 3 +++ .../services/modules/parser/index.ts | 23 ++++++++++++++++++- searching-front/services/parser.ts | 3 +-- 7 files changed, 60 insertions(+), 5 deletions(-) diff --git a/searching-front/app/core/components/WebsiteCard/WebsiteCard.tsx b/searching-front/app/core/components/WebsiteCard/WebsiteCard.tsx index 0552bff..9c818c1 100644 --- a/searching-front/app/core/components/WebsiteCard/WebsiteCard.tsx +++ b/searching-front/app/core/components/WebsiteCard/WebsiteCard.tsx @@ -1,18 +1,33 @@ import { cleanUrlForUi } from "app/core/helpers/common" +import { useEffect, useState } from "react" import s from "./styles.module.css" interface Props { url: string title: string description: string + faviconUrl?: string } const WebsiteCard = (props: Props) => { + const faviconUrl = props.faviconUrl; + const [faviconLoaded, setFaviconLoaded] = useState(false) + useEffect(() => { + if (faviconUrl) { + const faviconNode = document.createElement("img") + faviconNode.src = faviconUrl; + faviconNode.onload = () => { + setFaviconLoaded(true) + } + } + }, [faviconUrl]) const urlObj = new URL(props.url) urlObj.searchParams.set("from", "Searching.ton") - const url = urlObj.toString(); + const url = urlObj.toString() + return (
+ {faviconLoaded &&} {props.title} diff --git a/searching-front/app/core/components/WebsiteCard/styles.module.css b/searching-front/app/core/components/WebsiteCard/styles.module.css index 75e3790..1467026 100644 --- a/searching-front/app/core/components/WebsiteCard/styles.module.css +++ b/searching-front/app/core/components/WebsiteCard/styles.module.css @@ -4,6 +4,7 @@ border-radius: 12px; display: flex; flex-direction: column; + position: relative; } .root:not(:last-of-type) { @@ -34,3 +35,18 @@ .description { font-size: 13px; } + +.favicon { + width: 16px; + height: 16px; + border-radius: 50%; + position: absolute; + left: -24px; + top: 16px; +} + +@media only screen and (max-width: 700px) { + .favicon { + left: -16px; + } +} diff --git a/searching-front/app/core/layouts/Layout/styles.module.css b/searching-front/app/core/layouts/Layout/styles.module.css index 5d449ee..6093b93 100644 --- a/searching-front/app/core/layouts/Layout/styles.module.css +++ b/searching-front/app/core/layouts/Layout/styles.module.css @@ -8,7 +8,7 @@ margin-top: 20px; display: flex; flex-direction: column; - + padding: 0 20px; flex: 1; /* margin: auto; */ } diff --git a/searching-front/app/search-requests/queries/getSearchResult.ts b/searching-front/app/search-requests/queries/getSearchResult.ts index bc72b86..e98726e 100644 --- a/searching-front/app/search-requests/queries/getSearchResult.ts +++ b/searching-front/app/search-requests/queries/getSearchResult.ts @@ -22,6 +22,7 @@ const processResult = ({ bodyText, ...res }: Object, search: string) => { return { ...res, description: res.description || bodyToDescription(bodyText, search), + faviconUrl: res.faviconUrl, } } diff --git a/searching-front/services/modules/elastic/index.ts b/searching-front/services/modules/elastic/index.ts index a2bda1d..9d1d8df 100644 --- a/searching-front/services/modules/elastic/index.ts +++ b/searching-front/services/modules/elastic/index.ts @@ -11,6 +11,7 @@ export interface ElasticIndexParams { h1?: string bodyText: string description?: string + faviconUrl?: string } export interface ElasticSearchParams { text: string @@ -102,6 +103,7 @@ class Elastic { public index = async (params: ElasticIndexParams) => { const indexName = getIndexNameByText(params.title + params.bodyText) + console.log('index',params) await this.client.index({ index: indexName, id: params.url, @@ -111,6 +113,7 @@ class Elastic { h1: params.h1, bodyText: params.bodyText, description: params.description, + faviconUrl: params.faviconUrl, }, }) } diff --git a/searching-front/services/modules/parser/index.ts b/searching-front/services/modules/parser/index.ts index 076ebea..2df9b0c 100644 --- a/searching-front/services/modules/parser/index.ts +++ b/searching-front/services/modules/parser/index.ts @@ -23,9 +23,29 @@ const isInvalidLink = (link: string) => { return link.match(/\./) && !(link.match(/\.html/) || link.match(/\.htm/)) } +const getFaviconUrl = (dom:JSDOM, domain:string) => { + try{ + const node = dom.window.document.querySelector("[rel=icon][type*=image]") as HTMLLinkElement;; + const href = node?.href; + let url; + if(href){ + try { + url = new URL(href); + } catch(e){ + url = new URL(domain+href); + url.pathname = url.pathname.replace('//','/'); + } + return url.toString(); + } + } catch(e){ + return undefined + } + +} + class Parser { constructor() {} - parseUrl = async (url: string) => { + parseUrl = async (url: string, domain:string) => { try { const { data, headers } = await axios.get(url,{ @@ -66,6 +86,7 @@ class Parser { .querySelector("meta[name='description']") ?.getAttribute("content") || "", url, + faviconUrl: getFaviconUrl(dom, domain) }, subPages, } diff --git a/searching-front/services/parser.ts b/searching-front/services/parser.ts index 1d1b724..85a18ab 100644 --- a/searching-front/services/parser.ts +++ b/searching-front/services/parser.ts @@ -15,8 +15,7 @@ const indexWebsite = async (domain: string, path: string, subpages: SubPages = { const subpagesLength = Object.keys(subpages).length; if (!subpages[path]) { const url = domain + path; - const parseInfo = await Parser.parseUrl(url) - console.log(parseInfo) + const parseInfo = await Parser.parseUrl(url,domain); subpages[path] = true let pages = {} if (parseInfo !== SHOULD_NOT_PARSE && subpagesLength < 50) {