Include tags with snippets. Filter by tags. Display tags on single snippet view.

This commit is contained in:
unknown
2021-09-27 16:34:09 +02:00
parent 5b0fc6976a
commit 3cd2688589
12 changed files with 95 additions and 43 deletions

View File

@@ -3,7 +3,7 @@ import { useHistory } from 'react-router-dom';
import { SnippetsContext } from '../../store';
import { Snippet } from '../../typescript/interfaces';
import { dateParser } from '../../utils';
import { Button, Card } from '../UI';
import { Badge, Button, Card } from '../UI';
import copy from 'clipboard-copy';
import { SnippetPin } from './SnippetPin';
@@ -15,6 +15,7 @@ export const SnippetDetails = (props: Props): JSX.Element => {
const {
title,
language,
tags,
createdAt,
updatedAt,
description,
@@ -61,6 +62,16 @@ export const SnippetDetails = (props: Props): JSX.Element => {
</div>
<hr />
{/* TAGS */}
<div>
{tags.map(tag => (
<span className='me-2'>
<Badge text={tag} color='dark' />
</span>
))}
</div>
<hr />
{/* ACTIONS */}
<div className='d-grid g-2' style={{ rowGap: '10px' }}>
<Button

View File

@@ -5,7 +5,7 @@ import { Button, Card, EmptyState, Layout } from '../components/UI';
import { Snippet } from '../typescript/interfaces';
export const Snippets = (): JSX.Element => {
const { snippets, languageCount, getSnippets, countSnippets } =
const { snippets, tagCount, getSnippets, countTags } =
useContext(SnippetsContext);
const [filter, setFilter] = useState<string | null>(null);
@@ -13,16 +13,16 @@ export const Snippets = (): JSX.Element => {
useEffect(() => {
getSnippets();
countSnippets();
countTags();
}, []);
useEffect(() => {
setLocalSnippets([...snippets]);
}, [snippets]);
const filterHandler = (language: string) => {
setFilter(language);
const filteredSnippets = snippets.filter(s => s.language === language);
const filterHandler = (tag: string) => {
setFilter(tag);
const filteredSnippets = snippets.filter(s => s.tags.includes(tag));
setLocalSnippets(filteredSnippets);
};
@@ -44,21 +44,21 @@ export const Snippets = (): JSX.Element => {
<span>Total</span>
<span>{snippets.length}</span>
</div>
<h5 className='card-title'>Filter by language</h5>
<h5 className='card-title'>Filter by tags</h5>
<Fragment>
{languageCount.map((el, idx) => {
const isActiveFilter = filter === el.language;
{tagCount.map((tag, idx) => {
const isActiveFilter = filter === tag.name;
return (
<div
key={idx}
className={`d-flex justify-content-between cursor-pointer ${
isActiveFilter && 'text-dark fw-bold'
}`}
key={idx}
onClick={() => filterHandler(el.language)}
onClick={() => filterHandler(tag.name)}
>
<span>{el.language}</span>
<span>{el.count}</span>
<span>{tag.name}</span>
<span>{tag.count}</span>
</div>
);
})}

View File

@@ -5,14 +5,14 @@ import {
Context,
Snippet,
Response,
LanguageCount,
TagCount,
NewSnippet
} from '../typescript/interfaces';
export const SnippetsContext = createContext<Context>({
snippets: [],
currentSnippet: null,
languageCount: [],
tagCount: [],
getSnippets: () => {},
getSnippetById: (id: number) => {},
setSnippet: (id: number) => {},
@@ -20,7 +20,7 @@ export const SnippetsContext = createContext<Context>({
updateSnippet: (snippet: NewSnippet, id: number, isLocal?: boolean) => {},
deleteSnippet: (id: number) => {},
toggleSnippetPin: (id: number) => {},
countSnippets: () => {}
countTags: () => {}
});
interface Props {
@@ -30,7 +30,7 @@ interface Props {
export const SnippetsContextProvider = (props: Props): JSX.Element => {
const [snippets, setSnippets] = useState<Snippet[]>([]);
const [currentSnippet, setCurrentSnippet] = useState<Snippet | null>(null);
const [languageCount, setLanguageCount] = useState<LanguageCount[]>([]);
const [tagCount, setTagCount] = useState<TagCount[]>([]);
const history = useHistory();
@@ -132,17 +132,17 @@ export const SnippetsContextProvider = (props: Props): JSX.Element => {
}
};
const countSnippets = (): void => {
const countTags = (): void => {
axios
.get<Response<LanguageCount[]>>('/api/snippets/statistics/count')
.then(res => setLanguageCount(res.data.data))
.get<Response<TagCount[]>>('/api/snippets/statistics/count')
.then(res => setTagCount(res.data.data))
.catch(err => redirectOnError());
};
const context = {
snippets,
currentSnippet,
languageCount,
tagCount,
getSnippets,
getSnippetById,
setSnippet,
@@ -150,7 +150,7 @@ export const SnippetsContextProvider = (props: Props): JSX.Element => {
updateSnippet,
deleteSnippet,
toggleSnippetPin,
countSnippets
countTags
};
return (

View File

@@ -1,9 +1,9 @@
import { LanguageCount, NewSnippet, Snippet } from '.';
import { TagCount, NewSnippet, Snippet } from '.';
export interface Context {
snippets: Snippet[];
currentSnippet: Snippet | null;
languageCount: LanguageCount[];
tagCount: TagCount[];
getSnippets: () => void;
getSnippetById: (id: number) => void;
setSnippet: (id: number) => void;
@@ -11,5 +11,5 @@ export interface Context {
updateSnippet: (snippet: NewSnippet, id: number, isLocal?: boolean) => void;
deleteSnippet: (id: number) => void;
toggleSnippetPin: (id: number) => void;
countSnippets: () => void;
countTags: () => void;
}

View File

@@ -7,7 +7,7 @@ export interface NewSnippet {
code: string;
docs?: string;
isPinned: boolean;
tags: string;
tags: string[];
}
export interface Snippet extends Model, NewSnippet {}

View File

@@ -1,4 +1,4 @@
export interface LanguageCount {
export interface TagCount {
count: number;
language: string;
name: string;
}