diff --git a/package.json b/package.json index f5b443c..7b4bd59 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@tailwindcss/vite": "^4.0.9", "axios": "^1.11.0", "classnames": "^2.5.1", + "flowbite-react": "^0.12.7", "react": "^19.0.0", "react-dom": "^19.0.0", "react-icons": "^5.5.0", diff --git a/src/App.tsx b/src/App.tsx index 061a44d..34ca67b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -53,7 +53,10 @@ function App() { /> } + element={ + + + } /> diff --git a/src/components/ui/common-table.tsx b/src/components/ui/common-table.tsx index 646a389..b314e04 100644 --- a/src/components/ui/common-table.tsx +++ b/src/components/ui/common-table.tsx @@ -1,9 +1,11 @@ -import React from "react"; +import React, { ReactElement } from "react"; import classNames from "classnames"; +import { Hint } from "./hint"; export interface Column { name: string; renderCell?: (value: any) => React.ReactNode; + hint?: ReactElement; } interface CommonTableProps { @@ -33,7 +35,7 @@ export const CommonTable: React.FC = ({ } if (value === undefined || value === null) { - return NULL; + return
; } if (React.isValidElement(value)) { @@ -44,7 +46,7 @@ export const CommonTable: React.FC = ({ }; return ( -
+
{children && (
{children} @@ -63,7 +65,13 @@ export const CommonTable: React.FC = ({ columnHeaderClassName )} > - {column.name} + {column.hint ? ( + + {column.name} + + ) : ( + column.name + )} ))} diff --git a/src/components/ui/copy-button.tsx b/src/components/ui/copy-button.tsx new file mode 100644 index 0000000..e885d78 --- /dev/null +++ b/src/components/ui/copy-button.tsx @@ -0,0 +1,38 @@ +import { ReactElement, useState } from "react"; +import { Button } from "./button"; +import { MdCheck, MdContentCopy } from "react-icons/md"; + +interface CopyButtonProps { + children: ReactElement; + textToCopy: string; +} + +export const CopyButton: React.FC = ({ children, textToCopy }) => { + const [copied, setCopied] = useState(false); + + const handleCopy = async () => { + try { + await navigator.clipboard.writeText(textToCopy); + setCopied(true); + setTimeout(() => setCopied(false), 1000); + } catch (err) { + console.error('Failed to copy text: ', err); + } + }; + + return ( +
+
{children}
+ +
+ ); +}; diff --git a/src/components/ui/footer.tsx b/src/components/ui/footer.tsx index 29c433a..c21a4d4 100644 --- a/src/components/ui/footer.tsx +++ b/src/components/ui/footer.tsx @@ -1,13 +1,13 @@ import { useState } from "react"; -import ReactMarkdown from "react-markdown"; -import remarkGfm from "remark-gfm"; +import { Link as ReactDomLink } from "react-router-dom"; import { Button } from "./button"; +import { Link } from "./link"; +import { MdKeyboardArrowDown, MdKeyboardArrowUp } from "react-icons/md"; -const footerContent = ` -Information: https://hyperleda.github.io/ - -Old version: http://leda.univ-lyon1.fr/ -`; +const footerContent =
+
Information:
+
Old version:
+
export function Footer() { const [isCollapsed, setIsCollapsed] = useState(true); @@ -18,56 +18,39 @@ export function Footer() { return ( <> - {isCollapsed ? ( - - ) : ( -
-
-
- - {footerContent} - + + +
+
+
+
+ + HyperLeda Logo + + {footerContent}
-
-
- )} + +
+
); } diff --git a/src/components/ui/hint.tsx b/src/components/ui/hint.tsx new file mode 100644 index 0000000..93331ac --- /dev/null +++ b/src/components/ui/hint.tsx @@ -0,0 +1,22 @@ +import { Tooltip } from "flowbite-react"; +import { ReactElement } from "react"; +import { MdHelpOutline } from "react-icons/md"; + +interface HintProps { + children: ReactElement; + hintContent: ReactElement; + className?: string; +} + +export const Hint: React.FC = ({ children, hintContent, className = "" }) => { + return ( +
+
{children}
+
+ + + +
+
+ ); +}; diff --git a/src/components/ui/link.tsx b/src/components/ui/link.tsx new file mode 100644 index 0000000..671ccf2 --- /dev/null +++ b/src/components/ui/link.tsx @@ -0,0 +1,13 @@ +import React, { ReactElement } from "react"; + +interface LinkProps { + children?: ReactElement | string; + href: string; +} + +export const Link: React.FC = ({ children, href }) => { + const content = children ?? href + return + {content} + +} \ No newline at end of file diff --git a/src/index.css b/src/index.css index 8ed283d..b51a0e5 100644 --- a/src/index.css +++ b/src/index.css @@ -12,17 +12,6 @@ font-synthesis: none; text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; } body { @@ -41,10 +30,4 @@ h1 { color: #213547; background-color: #ffffff; } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} +} \ No newline at end of file diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 468048b..8932a42 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -1,17 +1,36 @@ import { useNavigate } from "react-router-dom"; import { SearchBar } from "../components/ui/searchbar"; -import ReactMarkdown from "react-markdown"; -import remarkGfm from "remark-gfm"; +import { ReactElement } from "react"; +import { Link } from "../components/ui/link"; -const homePageHint = ` -Examples: -- Search by name: [name:IC1445](/query?q=name:IC1445) -- Search by PGC number: [pgc:112642](/query?q=pgc:112642) - -The search conditions can be concatenated with AND or OR operators. For example: -- Search by name and PGC number: [name:IC1445 and pgc:112642](/query?q=name:IC1445%20AND%20pgc:112642) -- Search by name or PGC number: [name:IC4445 or pgc:87422](/query?q=name:IC1445%20OR%20pgc:112642) -`; +const homePageHint: ReactElement = ( +
+
Examples:
+
    +
  • + Search by name: name:IC1445 +
  • +
  • + Search by PGC number: pgc:112642 +
  • +
+
+ The search conditions can be concatenated with AND or OR operators. For example: +
+
    +
  • + Search by name and PGC number: + name:IC1445 and pgc:112642 + +
  • +
  • + Search by name or PGC number: + name:IC4445 or pgc:87422 + +
  • +
+
+); export const HomePage: React.FC = () => { const navigate = useNavigate(); @@ -23,10 +42,8 @@ export const HomePage: React.FC = () => { return (
-
- - {homePageHint} - +
+ {homePageHint}
); diff --git a/src/pages/TableDetails.tsx b/src/pages/TableDetails.tsx index 370ebfb..39995c3 100644 --- a/src/pages/TableDetails.tsx +++ b/src/pages/TableDetails.tsx @@ -3,43 +3,8 @@ import { GetTableResponse, HttpValidationError, Bibliography } from "../clients/ import { getTableAdminApiV1TableGet } from "../clients/admin/sdk.gen"; import { useNavigate, useParams } from "react-router-dom"; import { CommonTable, Column } from "../components/ui/common-table"; -import { Button } from "../components/ui/button"; -import { MdContentCopy, MdCheck } from "react-icons/md"; - -interface CopyButtonProps { - children: ReactElement; - textToCopy: string; -} - -const CopyButton: React.FC = ({ children, textToCopy }) => { - const [copied, setCopied] = useState(false); - - const handleCopy = async () => { - try { - await navigator.clipboard.writeText(textToCopy); - setCopied(true); - setTimeout(() => setCopied(false), 1000); - } catch (err) { - console.error('Failed to copy text: ', err); - } - }; - - return ( -
-
{children}
- -
- ); -}; +import { CopyButton } from "../components/ui/copy-button"; +import { Link } from "../components/ui/link"; function renderBibliography(bib: Bibliography): ReactElement { var authors = "" @@ -56,7 +21,7 @@ function renderBibliography(bib: Bibliography): ReactElement { const targetLink = "https://ui.adsabs.harvard.edu/abs/" + bib.bibcode + "/abstract" return -
{bib.bibcode} | {authors}: "{bib.title}"
+
{bib.bibcode} | {authors}: "{bib.title}"
} @@ -123,7 +88,14 @@ const renderTableDetails = (tableName: string, table: GetTableResponse) => { { name: "Name", renderCell: renderColumnName }, { name: "Description" }, { name: "Unit" }, - { name: "UCD", renderCell: renderUCD }, + { + name: "UCD", + renderCell: renderUCD, + hint:

+ Unified Content Descriptor. Describes astronomical quantities in a structured way. For more information + see IVOA Recommendation. +

+ }, ] var columnInfoValues: any[] = [] @@ -137,7 +109,7 @@ const renderTableDetails = (tableName: string, table: GetTableResponse) => { }) }); - return
+ return

{table.description}

{tableName}