Skip to content

Commit

Permalink
Added chips for keywords.
Browse files Browse the repository at this point in the history
  • Loading branch information
SamTV12345 committed Sep 20, 2023
1 parent 3498ec3 commit 574cad8
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 27 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"react-router": "^6.14.0",
"react-router-dom": "^6.14.0",
"react-router-hash-link": "^2.4.3",
"react-waypoint": "^10.3.0",
"sanitize-html": "^2.11.0",
"timeago": "^1.6.7"
},
Expand Down
23 changes: 23 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

67 changes: 67 additions & 0 deletions src/components/Chip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { FC, ReactElement } from 'react'

type ChipProps = {
index: number,
children?: ReactElement | ReactElement[] | string
}

export const Chip: FC<ChipProps> = ({ index, children }) => {
switch (index % 7) {
case 0:
return <span
className="p-px inline-block rounded bg-gradient-to-tl from-blue-500 to-violet-500">
<span className="block bg-[--bg-color] leading-none p-1.5 rounded text-center text-xs text-white whitespace-nowrap">
{children}
</span>
</span>
case 1:
return <span
className="p-px inline-block rounded bg-gradient-to-tl from-slate-600 to-slate-300">
<span className="block bg-[--bg-color] leading-none p-1.5 rounded text-center text-xs text-white whitespace-nowrap">
{children}
</span>
</span>
case 2:
return <span
className="p-px inline-block rounded bg-gradient-to-tl from-blue-700 to-cyan-500">
<span className="block bg-[--bg-color] leading-none p-1.5 rounded text-center text-xs text-white whitespace-nowrap">
{children}
</span>
</span>
case 3:
return <span
className="p-px inline-block rounded bg-gradient-to-tl from-red-600 to-orange-600">
<span className="block bg-[--bg-color] leading-none p-1.5 rounded text-center text-xs text-white whitespace-nowrap">
{children}
</span>
</span>
case 4:
return <span
className="p-px inline-block rounded bg-gradient-to-tl from-green-500 to-teal-500">
<span className="block bg-[--bg-color] leading-none p-1.5 rounded text-center text-xs text-white whitespace-nowrap">
{children}
</span>
</span>
case 5:
return <span
className="p-px inline-block rounded bg-gradient-to-tl from-gray-400 to-gray-100">
<span className="block bg-[--bg-color] leading-none p-1.5 rounded text-center text-xs text-white whitespace-nowrap">
{children}
</span>
</span>
case 6:
return <span
className="p-px inline-block rounded bg-gradient-to-tl from-zinc-800 to-zinc-700">
<span className="block bg-[--bg-color] leading-none p-1.5 rounded text-center text-xs text-white whitespace-nowrap">
{children}
</span>
</span>
default:
return <span
className="p-px inline-block rounded bg-gradient-to-tl from-green-500 to-teal-500">
<span className="block bg-[--bg-color] leading-none p-1.5 rounded text-center text-xs text-emerald-400 whitespace-nowrap">
{children}
</span>
</span>
}
}
43 changes: 33 additions & 10 deletions src/components/Plugin.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import {PluginMetaData,Plugin} from "../store/Plugin.ts";
import {PluginMetaData, Plugin, PluginResponse} from "../store/Plugin.ts";
import {FC} from "react";
import TimeAgo from 'javascript-time-ago'
import en from 'javascript-time-ago/locale/en'
import sanitizeHtml from 'sanitize-html'
import * as marked from 'marked'
import {PluginAuthorComp} from "./PluginAuthorComp.tsx";
import {Chip} from "./Chip.tsx";
import {Waypoint} from "react-waypoint";
import {useUIStore} from "../store/store.ts";
type PluginProps = {
metadata: PluginMetaData,
plugins: Plugin
plugins: Plugin,
index: number
}
TimeAgo.addDefaultLocale(en)
const timeago = new TimeAgo('en-US')
Expand All @@ -22,28 +27,46 @@ const renderMarkdown = (text: string) => {
return {__html: sanitizedHtml}
}

export const PluginCom: FC<PluginProps> = ({plugins})=>{
return <div className="dark:text-white border-[1px] p-2 rounded">
export const PluginCom: FC<PluginProps> = ({plugins, index})=>{
const pluginResp = useUIStore(state=>state.plugins)
const setPlugins = useUIStore(state=>state.setPlugins)

const loadNextPage = ()=> {
console.log("Loading next page")
fetch('/api/plugins')
.then(response => response.json())
.then((data: PluginResponse) => setPlugins(data))
}

return <div className="dark:text-white border-[1px] p-2 rounded">
<div className="flex">
{pluginResp && pluginResp?.plugins.length-2 === index && <Waypoint debug onEnter={()=>loadNextPage()}/>}
<div className="text-3xl text-primary flex gap-3">
<span>{plugins.name}</span>
<a target={"_blank"} href={'https://www.npmjs.org/package/' + plugins.name}>{plugins.name}</a>
<small className="align-text-bottom text-gray-400 mt-[3px]">{plugins.version}</small>
</div>
<div className="flex-grow"></div>
{plugins.time&&<div className="mr-5 mt-[0.3rem]">{formatTime(plugins.time)}</div>}
<div className="w-10 flex items-center mr-2">
<div className="w-10 border-[1px] border-white">
<div style={{width: plugins.popularity_score*100+"%"}} title={(plugins.popularity_score*100).toFixed(2)+"% popular among other plugins"} className="bg-primary w-10 h-5 self-center"></div>
<div className="w-10 border-[1px] border-white" title={(plugins.popularity_score*100).toFixed(2)+"% popular among other plugins"}>
<div style={{width: plugins.popularity_score*100+"%"}} className="bg-primary w-10 h-5 self-center"></div>
</div>
</div>
</div>
<div>{plugins.description}</div>
<div className="flex gap-10">
{plugins.image&&<img alt={"Image of "+plugins.name} className="w-60" src={plugins.image}/>}
{plugins.image&&<img alt={"Image of "+plugins.name} className="w-60 object-contain" src={plugins.image}/>}
{plugins.readme&&<div className="w-full line-clamp-5" dangerouslySetInnerHTML={renderMarkdown(plugins.readme)}></div>}
</div>
<div>

<div className="mt-5 flex">
<PluginAuthorComp name={plugins.author} email={plugins.author_email}/>
<span className="flex-grow"></span>
<span className="mr-5">License: {plugins.license? plugins.license: '--'}</span>
<span className="flex gap-3">
{
plugins.keywords.length>0 && plugins.keywords.map((k,i)=><Chip key={plugins.name+i} index={i}>{k}</Chip>)
}
</span>
</div>
</div>
}
18 changes: 18 additions & 0 deletions src/components/PluginAuthorComp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {FC} from "react";

type PluginAuthorProps = {
email: string,
name: string,
}

export const PluginAuthorComp: FC<PluginAuthorProps> = ({email,name})=>{


if (email && name){
return <a href={"mailto:"+email}><span className="text-primary">Author:</span> {name}</a>
} else if (name){
return <span><span className="text-primary">Author:</span> {name}</span>
}
return <span>No Author</span>

}
40 changes: 23 additions & 17 deletions src/pages/PluginViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {useEffect} from "react";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faSearch} from "@fortawesome/free-solid-svg-icons";
import {PluginCom} from "../components/Plugin.tsx";
export const PluginViewer = ()=>{

export const PluginViewer = () => {
const setPlugin = useUIStore(state => state.setPlugins)
const plugins = useUIStore(state => state.plugins)
const pluginSearchTerm = useUIStore(state => state.pluginSearchTerm)
Expand All @@ -14,27 +15,32 @@ export const PluginViewer = ()=>{
useEffect(() => {
fetch('/api/plugins')
.then(response => response.json())
.then((data:PluginResponse) =>setPlugin(data))
.then((data: PluginResponse) => setPlugin(data))
}, []);

return <div className="ml-5 mr-5 flex items-center flex-col">
<div>
<h1 className="text-2xl font-bold dark:text-white text-left w-full">PluginViewer</h1>
<span className="text-gray-400">
This page lists all available plugins for etherpad hosted on npm. <span className="text-primary">{plugins?.metadata.total_downloads} downloads</span> of <span className="text-primary">{plugins?.metadata.total_count}</span> plugins in the last month.
<div className="w-full md:w-3/4">
<h1 className="text-4xl font-bold dark:text-white text-left w-full">PluginViewer</h1>
<span className="text-gray-400">
This page lists all available plugins for etherpad hosted on npm. <span
className="text-primary">{plugins?.metadata.total_downloads} downloads</span> of <span
className="text-primary">{plugins?.metadata.total_count}</span> plugins in the last month.
For more information about Etherpad visit https://etherpad.org.
</span>
<div className="mt-5 mb-5 relative flex self-center w-full md:w-3/4">
<input className="w-full rounded border-[1px] pt-2 pb-2 pl-8 pr-1" placeholder="Search for plugins to install" value={pluginSearchTerm} onChange={v=>setPluginSearchTerm(v.target.value)}/>
<FontAwesomeIcon icon={faSearch} className="absolute left-2 mt-[0.85rem]"/>
</div>
<div className="grid grid-cols-1 gap-3 w-full md:w-3/4 ">
{
plugins?.plugins.map((plugin)=> {
return <PluginCom plugins={plugin} metadata={plugins?.metadata}/>
})
}
</div>
<h2 className="text-3xl text-primary">Plugins ({plugins?.metadata.total_count})</h2>
<div className="mt-5 mb-5 relative flex self-center w-full">
<input className="w-full rounded border-[1px] pt-2 pb-2 pl-8 pr-1"
placeholder="Search for plugins to install" value={pluginSearchTerm}
onChange={v => setPluginSearchTerm(v.target.value)}/>
<FontAwesomeIcon icon={faSearch} className="absolute left-2 mt-[0.85rem]"/>
</div>
<div className="grid grid-cols-1 gap-3 w-full">
{
plugins?.plugins.map((plugin,i) => {
return <PluginCom plugins={plugin} metadata={plugins?.metadata} index={i} key={plugin.name}/>
})
}
</div>
</div>
</div>
}
1 change: 1 addition & 0 deletions src/store/Plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type Plugin = {
keywords: string[],
image: string,
readme: string,
license: string
}

export type PluginMetaData = {
Expand Down

0 comments on commit 574cad8

Please sign in to comment.