Compare commits

..

No commits in common. "fix/revert-dev" and "master" have entirely different histories.

49 changed files with 4302 additions and 4178 deletions

View File

@ -1,5 +1,5 @@
.env* .env*
.env.production !.env.production
node_modules node_modules
build build
.vscode .vscode

6
.env
View File

@ -1,6 +0,0 @@
REACT_APP_CMS_BASE_URL=http://api.scipaper.ru
REACT_APP_CMS_APP_NAME=scipaper
REACT_APP_OPENID_PROVIDER_URL=http://auth.techpal.ru/auth/realms/master/protocol/openid-connect/auth?client_id=techpal&response_type=code
REACT_APP_INTEGRATOR_URL=http://api.scipaper.ru
REACT_APP_INTEGRATOR_API_VERSION=/v1
REACT_APP_GRAPHQL_URL=/graphql

View File

@ -1,6 +1,6 @@
REACT_APP_CMS_BASE_URL=http://api.scipaper.ru REACT_APP_CMS_BASE_URL=http://scipaper.ru
REACT_APP_CMS_APP_NAME=scipaper REACT_APP_CMS_APP_NAME=scipaper
REACT_APP_OPENID_PROVIDER_URL=http://auth.techpal.ru/auth/realms/master/protocol/openid-connect/auth?client_id=techpal&response_type=code REACT_APP_OPENID_PROVIDER_URL=http://auth.techpal.ru/auth/realms/master/protocol/openid-connect/auth?client_id=techpal&response_type=code
REACT_APP_INTEGRATOR_URL=http://api.scipaper.ru REACT_APP_INTEGRATOR_URL=http://scipaper.ru
REACT_APP_INTEGRATOR_API_VERSION=/v1 REACT_APP_INTEGRATOR_API_VERSION=/v1
REACT_APP_GRAPHQL_URL=/graphql REACT_APP_GRAPHQL_URL=/graphql

View File

@ -1,6 +1,6 @@
REACT_APP_CMS_BASE_URL=http://api.scipaper.ru REACT_APP_CMS_BASE_URL=http://scipaper.ru
REACT_APP_CMS_APP_NAME=scipaper REACT_APP_CMS_APP_NAME=scipaper
REACT_APP_OPENID_PROVIDER_URL=http://auth.techpal.ru/auth/realms/master/protocol/openid-connect/auth?client_id=techpal&response_type=code REACT_APP_OPENID_PROVIDER_URL=http://auth.techpal.ru/auth/realms/master/protocol/openid-connect/auth?client_id=techpal&response_type=code
REACT_APP_INTEGRATOR_URL=http://api.scipaper.ru REACT_APP_INTEGRATOR_URL=http://scipaper.ru
REACT_APP_INTEGRATOR_API_VERSION=/v1 REACT_APP_INTEGRATOR_API_VERSION=/v1
REACT_APP_GRAPHQL_URL=/graphql REACT_APP_GRAPHQL_URL=/graphql

View File

@ -1,43 +1,41 @@
# Install dependencies of project # Install dependencies only when needed
FROM node:fermium-alpine AS dependencies FROM node:16-alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat RUN apk add --no-cache libc6-compat
WORKDIR /home/app/ WORKDIR /app
COPY package.json ./ COPY package.json package-lock.json ./
RUN npm i RUN npm ci
# Rebuild the source code only when needed
# Build application to bunch of static files FROM node:16-alpine AS builder
FROM node:fermium-alpine AS builder ENV NODE_ENV production
WORKDIR /home/app/ WORKDIR /app
COPY --from=dependencies ./home/app/node_modules ./node_modules # Copy dependencies from deps stage
COPY --from=deps /app/node_modules ./node_modules
COPY . . COPY . .
RUN npm run build RUN npm run build
# Bundle static assets with nginx
# NGINX image FROM node:16-alpine as production
FROM nginx:1.21.6 as production
# Copy built assets from builder # Copy built assets from builder
COPY --from=builder /home/app/build /usr/share/nginx/html WORKDIR /app
# Add nginx.config COPY --from=builder /app/build .
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Copy setup nginx entrypoint file
COPY ./scripts/entrypoint.sh .
# Expose ports # Expose ports
EXPOSE 80 EXPOSE 3000
# Execute script COPY .env.production .
RUN chmod +x ./entrypoint.sh
ENV NODE_ENV production ENV NODE_ENV production
# ENV USER_NAME=node_user USER_UID=2000 GROUP_NAME=node_group GROUP_UID=2000 ENV USER_NAME=node_user USER_UID=2000 GROUP_NAME=node_group GROUP_UID=2000
# RUN deluser --remove-home node \ RUN npm i -g serve \
# && addgroup --g ${GROUP_UID} -S ${GROUP_NAME} \ && deluser --remove-home node \
# && adduser -D -S -s /sbin/nologin -u ${USER_UID} -G ${GROUP_NAME} ${USER_NAME} && addgroup --g ${GROUP_UID} -S ${GROUP_NAME} \
# USER "${USER_NAME}" && adduser -D -S -s /sbin/nologin -u ${USER_UID} -G ${GROUP_NAME} ${USER_NAME}\
&& chown -R ${USER_NAME}:${GROUP_NAME} "/app/"
ENTRYPOINT ["./entrypoint.sh"]
# Start serving USER "${USER_NAME}"
CMD ["nginx", "-g", "daemon off;"] CMD serve -s .

View File

@ -1,9 +1,6 @@
#! /bin/bash #! /bin/bash
# no verbose # no verbose
set +x set +x
# save env to file
printenv > .env.production
# config # config
envFilename='.env.production' envFilename='.env.production'
resolvingPath='/usr/share/nginx/html' resolvingPath='/usr/share/nginx/html'

8063
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
"@fortawesome/free-brands-svg-icons": "^6.2.0", "@fortawesome/free-brands-svg-icons": "^6.2.0",
"@fortawesome/free-solid-svg-icons": "^6.2.0", "@fortawesome/free-solid-svg-icons": "^6.2.0",
"@fortawesome/react-fontawesome": "^0.2.0", "@fortawesome/react-fontawesome": "^0.2.0",
"@headlessui/react": "^1.7.3", "@headlessui/react": "^1.6.6",
"@reduxjs/toolkit": "^1.8.3", "@reduxjs/toolkit": "^1.8.3",
"@types/node": "^16.11.47", "@types/node": "^16.11.47",
"@types/react": "^18.0.15", "@types/react": "^18.0.15",
@ -24,9 +24,9 @@
"i18next-http-backend": "^1.4.1", "i18next-http-backend": "^1.4.1",
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"react": "^18.1.0", "react": "^18.2.0",
"react-copy-to-clipboard": "^5.1.0", "react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18.1.0", "react-dom": "^18.2.0",
"react-hotkeys": "^2.0.0", "react-hotkeys": "^2.0.0",
"react-i18next": "^11.18.3", "react-i18next": "^11.18.3",
"react-loading-skeleton": "^3.1.0", "react-loading-skeleton": "^3.1.0",

33
src/article/controller/articleViewModel.ts Executable file → Normal file
View File

@ -1,31 +1,22 @@
import type { ArticleStore } from "../domain/articleStore"; import type { ArticleStore } from "../domain/articleStore";
import { getArticleUseCase } from "../useCases/getArticleUseCase";
import { useCallback, useEffect } from "react"; import { useCallback, useEffect } from "react";
import { GetArticleUseCase } from "article/useCases/getArticleUseCase";
import { FetchArticleUseCase } from "article/useCases/fetchArticleUseCase";
import { useParams } from "react-router-dom";
function useArticleViewModel( function useArticleViewModel(store: ArticleStore) {
store: ArticleStore, const _getArticle = useCallback(
fetchArticleUseCase: FetchArticleUseCase, (id: string) => getArticleUseCase(store.getArticle, store.setArticle, id),
getArticleUseCase: GetArticleUseCase, [store.getArticle, store.setArticle]
) { );
const { id } = useParams();
// const getArticle = useCallback(
// () => {
// getArticleUseCase.call(id ?? '').catch((_) => fetchArticleUseCase.call(id ?? ''));
// console.log(id);
// },
// [id]
// );
useEffect(() => { useEffect(() => {
getArticleUseCase.call(id ?? '').catch((_) => fetchArticleUseCase.call(id ?? '')); if (store.article != undefined) {
}, []); _getArticle(store.article.id);
}
}, [store.article?.id]);
return { return {
article: store.currentArticle, article: store.article,
shouldShowLoading: store.isLoading, shouldShowLoading: typeof store.article === "undefined" || store.isLoading,
hasError: store.hasError, hasError: store.hasError,
}; };
} }

4
src/article/data/articleAPIService.ts Executable file → Normal file
View File

@ -7,7 +7,7 @@ import { integratorApiClient } from "core/httpClient";
const articleEndpoint = "/papers/" const articleEndpoint = "/papers/"
async function fetchArticle(id: string): Promise<Article> { async function getArticle(id: string): Promise<Article> {
try { try {
const response = await integratorApiClient.get<FetchArticleByIdDTO>( const response = await integratorApiClient.get<FetchArticleByIdDTO>(
// `https://run.mocky.io/v3/62cd4581-d864-4d46-b1d6-02b45b5d1994/${id}` // `https://run.mocky.io/v3/62cd4581-d864-4d46-b1d6-02b45b5d1994/${id}`
@ -33,4 +33,4 @@ async function fetchArticle(id: string): Promise<Article> {
} }
} }
export { fetchArticle }; export { getArticle };

0
src/article/data/articleActionTypes.ts Executable file → Normal file
View File

26
src/article/data/articleActions.ts Executable file → Normal file
View File

@ -1,25 +1,23 @@
import type { Article } from "../domain/articleEntity"; import type { Article } from "../domain/articleEntity";
import { getArticle as getArticleAPI } from "./articleAPIService";
import * as actionTypes from "./articleActionTypes"; import * as actionTypes from "./articleActionTypes";
import { dispatchStatus } from "../../store/index"; import { dispatchStatus } from "../../store/index";
const setArticleAction = (article: Article, articlesList: Array<Article>) => (dispatch: any) => { const setArticleAction = (article: Article) => (dispatch: any) =>
if (!articlesList.includes(article)) { dispatch({ type: actionTypes.SET_ARTICLE, article });
const updatedList = articlesList.concat([article]);
dispatch({ type: actionTypes.SET_ARTICLE, article, updatedList });
}
}
const getArticleAction = (id: string, articles: Array<Article>) => (dispatch: any) => { const getArticleAction = (id: string) => (dispatch: any) => {
const filteredArray = articles.filter((e) => e.id == id); dispatch({ type: actionTypes.GET_ARTICLE });
if (filteredArray.length > 0) {
const article = filteredArray[0]; return getArticleAPI(id)
.then((article) => {
dispatchStatus(actionTypes.GET_ARTICLE, ".success", article)(dispatch); dispatchStatus(actionTypes.GET_ARTICLE, ".success", article)(dispatch);
return article; return article;
} })
.catch((reason) => {
const reason = 'Article not in the store';
dispatchStatus(actionTypes.GET_ARTICLE, ".failure", reason)(dispatch); dispatchStatus(actionTypes.GET_ARTICLE, ".failure", reason)(dispatch);
return null; return reason;
});
}; };
export { setArticleAction, getArticleAction }; export { setArticleAction, getArticleAction };

45
src/article/data/articleCommonStateStore.ts Executable file → Normal file
View File

@ -2,58 +2,37 @@ import React, { useCallback, useState } from "react";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
import { ArticleStore } from "../domain/articleStore"; import { ArticleStore } from "../domain/articleStore";
import type { Article } from "../domain/articleEntity"; import type { Article } from "../domain/articleEntity";
import { getArticle as getArticleAPI } from "./articleAPIService";
const useArticleCommonStore = (): ArticleStore => { const useArticleCommonStore = (): ArticleStore => {
const [isLoading, setLoading] = useState<boolean>(false); const [isLoading, setLoading] = useState<boolean>(false);
const [hasError, setError] = useState<boolean>(false); const [hasError, setError] = useState<boolean>(false);
const [currentArticle, setCurrentArticle] = useState<Article | null>(null); const [article, setArticleState] = useState<Article | undefined>();
const [articles, setArticlesState] = useState<Array<Article>>([]);
const dispatch = useDispatch(); const dispatch = useDispatch();
const getArticle = useCallback( const getArticle = useCallback(
(id: string) => { async (id: string) => {
setLoading(true); setLoading(true);
if (typeof currentArticle === undefined) { try {
const fromStore = findArticleFromStore(id); const article = await getArticleAPI(id);
if (typeof fromStore === undefined) { setArticleState(article);
setLoading(false);
return article;
} catch (error) {
setError(true); setError(true);
return null; return null;
} }
setLoading(false);
setCurrentArticle(fromStore);
return fromStore;
}
setLoading(false);
return currentArticle;
}, },
[dispatch] [dispatch]
); );
const findArticleFromStore = (id: string): Article | null => {
const filteredArray = articles.filter((e) => e.id == id);
if (filteredArray.length > 0) {
return filteredArray[0];
}
return null;
}
const setNewArticle = (newArticle: Article) => {
setCurrentArticle(newArticle);
if (!articles.includes(newArticle)) {
setArticlesState(articles.concat([newArticle]));
} else if (articles.length == 0) {
setArticlesState([newArticle]);
}
}
return { return {
articles: articles, article: article,
currentArticle: currentArticle,
isLoading, isLoading,
hasError, hasError,
setArticle: setNewArticle, setArticle: setArticleState,
getArticle: getArticle, getArticle,
}; };
}; };

7
src/article/data/articleReducer.ts Executable file → Normal file
View File

@ -5,8 +5,7 @@ import * as actionTypes from "./articleActionTypes";
type ArticleStoreState = Omit<ArticleStore, "getArticle" | "setArticle">; type ArticleStoreState = Omit<ArticleStore, "getArticle" | "setArticle">;
const INITIAL_STATE: ArticleStoreState = { const INITIAL_STATE: ArticleStoreState = {
articles: [], article: undefined,
currentArticle: null,
isLoading: false, isLoading: false,
hasError: false, hasError: false,
}; };
@ -17,11 +16,11 @@ const articleReducer = (
): ArticleStoreState => { ): ArticleStoreState => {
switch (action.type) { switch (action.type) {
case actionTypes.SET_ARTICLE: case actionTypes.SET_ARTICLE:
return { ...state, articles: action.updatedList, currentArticle: action.article, hasError: typeof action.article === undefined }; return { ...state, article: action.article };
case actionTypes.GET_ARTICLE: case actionTypes.GET_ARTICLE:
return { ...state, isLoading: true }; return { ...state, isLoading: true };
case actionTypes.GET_ARTICLE_SUCCESS: case actionTypes.GET_ARTICLE_SUCCESS:
return { ...state, isLoading: false, currentArticle: action.payload }; return { ...state, isLoading: false, article: action.payload };
case actionTypes.GET_ARTICLE_FAILURE: case actionTypes.GET_ARTICLE_FAILURE:
return { ...state, hasError: true, isLoading: false }; return { ...state, hasError: true, isLoading: false };
default: default:

9
src/article/data/articleStoreImplementation.ts Executable file → Normal file
View File

@ -9,23 +9,22 @@ import { RootState, useAppSelector } from "store";
const articleSelector = (state: RootState): ArticleStoreState => state.article; const articleSelector = (state: RootState): ArticleStoreState => state.article;
const useArticleStore = (): ArticleStore => { const useArticleStore = (): ArticleStore => {
const { isLoading, hasError, currentArticle, articles } = useAppSelector(articleSelector); const { isLoading, article, hasError } = useAppSelector(articleSelector);
const dispatch = useDispatch(); const dispatch = useDispatch();
const setArticle = useCallback( const setArticle = useCallback(
(article: Article) => setArticleAction(article, articles)(dispatch), (article: Article) => setArticleAction(article)(dispatch),
[dispatch] [dispatch]
); );
const getArticle = useCallback( const getArticle = useCallback(
(id: string) => getArticleAction(id, articles)(dispatch), (id: string) => getArticleAction(id)(dispatch),
[dispatch] [dispatch]
); );
return { return {
articles: articles, article: article,
currentArticle: currentArticle,
isLoading, isLoading,
hasError, hasError,
setArticle, setArticle,

0
src/article/data/dto/fetch_article_by_id_dto.ts Executable file → Normal file
View File

0
src/article/domain/articleEntity.ts Executable file → Normal file
View File

0
src/article/domain/articleModel.ts Executable file → Normal file
View File

7
src/article/domain/articleStore.ts Executable file → Normal file
View File

@ -1,14 +1,13 @@
import { Article } from './articleEntity'; import { Article } from './articleEntity';
interface ArticleStore { interface ArticleStore {
// State // State
articles: Array<Article>; article: Article | undefined;
currentArticle: Article | null;
isLoading: boolean; isLoading: boolean;
hasError: boolean; hasError: boolean;
// Actions // Actions
setArticle(article: Article): void; setArticle(article?: Article): void;
getArticle(identifier: string): Article | null; getArticle(identifier: string): Promise<Article | null>;
} }
export type { ArticleStore }; export type { ArticleStore };

View File

@ -1,29 +0,0 @@
import { Article } from "article/domain/articleEntity";
import { ArticleStore } from "article/domain/articleStore";
class FetchArticleUseCase {
/* ------------------------------ Dependencies ------------------------------ */
_fetchArticleCallback: (id: string) => Promise<Article | null>;
_store: ArticleStore;
/* -------------------------------------------------------------------------- */
constructor(
fetchArticle: (id: string) => Promise<Article | null>,
store: ArticleStore,
) {
this._fetchArticleCallback = fetchArticle;
this._store = store;
}
/* ----------------------------- Implementation ----------------------------- */
async call(id: string): Promise<Article | null> {
return this._fetchArticleCallback(id).then((article) => {
if (article != null) {
this._store.setArticle(article);
}
return article;
})
}
/* -------------------------------------------------------------------------- */
}
export { FetchArticleUseCase };

31
src/article/useCases/getArticleUseCase.ts Executable file → Normal file
View File

@ -1,25 +1,16 @@
import { Article } from "article/domain/articleEntity"; import { Article } from "article/domain/articleEntity";
import type { ArticleStore } from "../domain/articleStore"; import type { ArticleStore } from "../domain/articleStore";
class GetArticleUseCase { const getArticleUseCase = async (
/* ------------------------------ Dependencies ------------------------------ */ getArticle: ArticleStore["getArticle"],
_store: ArticleStore; setArticle: ArticleStore["setArticle"],
/* -------------------------------------------------------------------------- */ id: Article["id"]
constructor( ): Promise<Article | null> => {
store: ArticleStore, const article = await getArticle(id);
) { if (article) {
this._store = store; await setArticle(article);
} }
/* ----------------------------- Implementation ----------------------------- */ return article;
async call(id: string): Promise<Article> { };
const storedArticle = this._store.getArticle(id);
if (storedArticle != null) {
this._store.setArticle(storedArticle);
return storedArticle;
}
throw new Error('Article not found');
}
/* -------------------------------------------------------------------------- */
}
export { GetArticleUseCase }; export { getArticleUseCase };

0
src/article/useCases/params/create_article_params.ts Executable file → Normal file
View File

0
src/assets/lotties/notFoundAnimation.json Executable file → Normal file
View File

12
src/components/ArticleSearchResult.tsx Executable file → Normal file
View File

@ -27,15 +27,17 @@ export const ArticleSearchResult = ({ searchItem }: Props) => {
<Article className=" pt-6 pb-3 "> <Article className=" pt-6 pb-3 ">
<div className="flex flex-row justify-between"> <div className="flex flex-row justify-between">
<Article.Breadcumbs emphasis="low" className="flex flex-wrap flex-row"> <Article.Breadcumbs emphasis="low" className="flex flex-wrap flex-row">
{[`${searchItem.topic}`]} {[
`${searchItem.topic}`,
`${searchItem.topic}`,
`${searchItem.topic}`,
`${searchItem.topic}`,
]}
</Article.Breadcumbs> </Article.Breadcumbs>
<Article.SubscriptionsButtons /> <Article.SubscriptionsButtons />
</div> </div>
<Article.Title <Article.Title linkTo={`/article/info/${searchItem.id}`} className="text-2xl">
linkTo={`/article/info/${searchItem.id}`}
className="text-2xl"
>
{searchItem.title} {searchItem.title}
</Article.Title> </Article.Title>
<Article.Authors emphasis="low" className="flex flex-wrap flex-row"> <Article.Authors emphasis="low" className="flex flex-wrap flex-row">

26
src/components/Burger.tsx Executable file → Normal file
View File

@ -21,12 +21,10 @@ import { ReactComponent as SVGFile } from "assets/svg/file.svg";
import { ReactComponent as SVGEye } from "assets/svg/eye.svg"; import { ReactComponent as SVGEye } from "assets/svg/eye.svg";
import { ReactComponent as SVGArrowUp } from "assets/svg/arrow-up.svg"; import { ReactComponent as SVGArrowUp } from "assets/svg/arrow-up.svg";
import { ReactComponent as SVGCaretDown } from "assets/svg/caret-down.svg"; import { ReactComponent as SVGCaretDown } from "assets/svg/caret-down.svg";
import { useTranslation } from "react-i18next";
type Props = React.ComponentPropsWithoutRef<"div">; type Props = React.ComponentPropsWithoutRef<"div">;
const Burger = (props: Props) => { const Burger = (props: Props) => {
const { t, i18n } = useTranslation();
return ( return (
<div {...props}> <div {...props}>
<Menu as="div" className="relative inline-block text-left z-30"> <Menu as="div" className="relative inline-block text-left z-30">
@ -48,15 +46,13 @@ const Burger = (props: Props) => {
leaveTo="transform opacity-0 scale-95" leaveTo="transform opacity-0 scale-95"
> >
<Menu.Items <Menu.Items
className="origin-top-right absolute right-0 mt-5 w-48 rounded-md className="origin-top-right absolute right-0 mt-5 w-44 rounded-md
shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none" shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none"
> >
<div className="py-1"> <div className="py-1">
<Disclosure> <Disclosure>
<Disclosure.Button className="uppercase text-base px-2 py-1"> <Disclosure.Button className="uppercase text-base px-2 py-1">
<Link className="text-[#096DD9]"> <Link className="text-[#096DD9]">create new</Link>
{t("navbar.createNew")}
</Link>
</Disclosure.Button> </Disclosure.Button>
</Disclosure> </Disclosure>
<hr /> <hr />
@ -70,7 +66,7 @@ const Burger = (props: Props) => {
text-base text-base
" "
> >
<span>{t("navbar.library.navTitle")}</span> my library
<SVGArrowUp <SVGArrowUp
className={`${ className={`${
open ? "rotate-180 transform" : "rotate-360" open ? "rotate-180 transform" : "rotate-360"
@ -87,7 +83,7 @@ const Burger = (props: Props) => {
" "
> >
<SVGFile className="stroke-black w-4 h-4" /> <SVGFile className="stroke-black w-4 h-4" />
<span>{t("navbar.library.publications")}</span> My Publications
</Disclosure.Panel> </Disclosure.Panel>
</Link> </Link>
@ -100,7 +96,7 @@ const Burger = (props: Props) => {
" "
> >
<SVGFavoriteOutlined className="stroke-black w-4 h-4" /> <SVGFavoriteOutlined className="stroke-black w-4 h-4" />
<span>{t("navbar.library.favorites")}</span> My Favorites
</Disclosure.Panel> </Disclosure.Panel>
</Link> </Link>
@ -113,7 +109,7 @@ const Burger = (props: Props) => {
" "
> >
<SVGFolder className="stroke-black fill-black w-4 h-4" /> <SVGFolder className="stroke-black fill-black w-4 h-4" />
<span>{t("navbar.library.collections")}</span> My Collections
</Disclosure.Panel> </Disclosure.Panel>
</Link> </Link>
@ -126,7 +122,7 @@ const Burger = (props: Props) => {
" "
> >
<SVGEye className="stroke-black w-4 h-4" /> <SVGEye className="stroke-black w-4 h-4" />
<span>{t("navbar.library.recentViewed")}</span> Recent Viewed
</Disclosure.Panel> </Disclosure.Panel>
</Link> </Link>
</> </>
@ -144,7 +140,7 @@ const Burger = (props: Props) => {
text-base text-base
" "
> >
<span>{t("navbar.about.navTitle")}</span> About
<SVGArrowUp <SVGArrowUp
className={`${ className={`${
open ? "rotate-180 transform" : "rotate-360" open ? "rotate-180 transform" : "rotate-360"
@ -160,7 +156,7 @@ const Burger = (props: Props) => {
text-base text-base
" "
> >
<span>{t("navbar.about.aboutProject")}</span> About Freeland
</Disclosure.Panel> </Disclosure.Panel>
</Link> </Link>
@ -172,7 +168,7 @@ const Burger = (props: Props) => {
text-base text-base
" "
> >
<span>{t("navbar.about.contacts")}</span> Contact Us
</Disclosure.Panel> </Disclosure.Panel>
</Link> </Link>
@ -184,7 +180,7 @@ const Burger = (props: Props) => {
text-base text-base
" "
> >
<span>{t("navbar.about.help")}</span> Help
</Disclosure.Panel> </Disclosure.Panel>
</Link> </Link>
</> </>

0
src/components/Disclosure.tsx Executable file → Normal file
View File

0
src/components/Filters/AppiledFilters.tsx Executable file → Normal file
View File

0
src/components/Filters/Filter.tsx Executable file → Normal file
View File

0
src/components/Filters/IProdutct.ts Executable file → Normal file
View File

0
src/components/Filters/SearchFilterBar.tsx Executable file → Normal file
View File

0
src/components/Filters/functions/debounce.ts Executable file → Normal file
View File

0
src/components/Loader/Loader.css Executable file → Normal file
View File

0
src/components/Loader/Loader.tsx Executable file → Normal file
View File

0
src/components/LocalizationButton.tsx Executable file → Normal file
View File

5
src/components/Markdown.tsx Executable file → Normal file
View File

@ -14,8 +14,9 @@ import Heading from "./typography/Heading";
/* Code */ /* Code */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { oneLight } from "react-syntax-highlighter/dist/esm/styles/prism"; import { dark } from "react-syntax-highlighter/dist/esm/styles/prism";
import Link from "./typography/Link"; import Link from "./typography/Link";
import style from "react-syntax-highlighter/dist/esm/styles/hljs/a11y-dark";
export type Props = { export type Props = {
markdown: string; markdown: string;
@ -152,7 +153,7 @@ const Markdown = ({ markdown }: Props) => {
return !inline && match ? ( return !inline && match ? (
<SyntaxHighlighter <SyntaxHighlighter
children={String(children).replace(/\n$/, "")} children={String(children).replace(/\n$/, "")}
style={oneLight} style={dark}
language={match[1]} language={match[1]}
PreTag="div" PreTag="div"
/> />

0
src/components/SearchResultsSection.tsx Executable file → Normal file
View File

0
src/components/SearchSection.tsx Executable file → Normal file
View File

View File

@ -83,7 +83,7 @@ function Select<T>({
}: Props<T>): JSX.Element { }: Props<T>): JSX.Element {
return ( return (
<div className={classNames("top-16 w-60", className)}> <div className={classNames("top-16 w-60", className)}>
<Listbox value={value as any } {...props} onChange={onChange}> <Listbox value={value} {...props} onChange={onChange}>
<div className="relative"> <div className="relative">
<Listbox.Button <Listbox.Button
className={classNames([ className={classNames([

17
src/components/fetchAnArticle/AnArticle.tsx Executable file → Normal file
View File

@ -10,20 +10,19 @@ import { SVGSearch } from "components/icons";
import BaseLayout from "components/BaseLayout"; import BaseLayout from "components/BaseLayout";
import Typography from "components/typography/Typography"; import Typography from "components/typography/Typography";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FetchArticleUseCase } from "article/useCases/fetchArticleUseCase";
import { GetArticleUseCase } from "article/useCases/getArticleUseCase";
import { fetchArticle } from "article/data/articleAPIService";
const AnArticle = () => { const AnArticle = () => {
const store = useArticleStore(); const store = useArticleStore();
const { article, hasError, shouldShowLoading } = useArticleViewModel( const { article, hasError, shouldShowLoading } = useArticleViewModel(store);
store,
new FetchArticleUseCase(fetchArticle, store),
new GetArticleUseCase(store),
);
const { i18n, t } = useTranslation(); const { i18n, t } = useTranslation();
const { id } = useParams();
const newId = `${id}`;
useEffect(() => {
store.getArticle(newId);
}, [id]);
if (hasError) { if (hasError) {
return <NotFound />; return <NotFound />;
} }

14
src/components/fetchAnArticle/AnArticleBody.tsx Executable file → Normal file
View File

@ -13,17 +13,15 @@ import BaseLayout from "components/BaseLayout";
import Container from "components/Container"; import Container from "components/Container";
import NotFound from "./NotFound"; import NotFound from "./NotFound";
import Markdown from "components/Markdown"; import Markdown from "components/Markdown";
import { FetchArticleUseCase } from "article/useCases/fetchArticleUseCase";
import { GetArticleUseCase } from "article/useCases/getArticleUseCase";
import { fetchArticle } from "article/data/articleAPIService";
const AnArticleBody = () => { const AnArticleBody = () => {
const store = useArticleStore(); const store = useArticleStore();
const { article, hasError, shouldShowLoading } = useArticleViewModel( const { article, hasError, shouldShowLoading } = useArticleViewModel(store);
store, const { id } = useParams();
new FetchArticleUseCase(fetchArticle, store), const newId = `${id}`;
new GetArticleUseCase(store), useEffect(() => {
); store.getArticle(newId);
}, [id]);
if (hasError) <NotFound />; if (hasError) <NotFound />;
return ( return (
<BaseLayout> <BaseLayout>

0
src/components/fetchAnArticle/AskeletonArticle.tsx Executable file → Normal file
View File

0
src/components/fetchAnArticle/NotFound.tsx Executable file → Normal file
View File

View File

@ -80,7 +80,7 @@ const Header = () => {
<ContextMenu <ContextMenu
emphasis="high" emphasis="high"
button={t("navbar.library.navTitle")} button={t("navbar.library.navTitle")}
className="border-none uppercase z-40" className="border-none uppercase"
> >
<ContextMenuAction <ContextMenuAction
caption={t("navbar.library.publications")} caption={t("navbar.library.publications")}
@ -112,7 +112,7 @@ const Header = () => {
<ContextMenu <ContextMenu
emphasis="high" emphasis="high"
button={t("navbar.about.navTitle")} button={t("navbar.about.navTitle")}
className="border-none uppercase z-40" className="border-none uppercase"
> >
<ContextMenuAction <ContextMenuAction
caption={t("navbar.about.aboutProject")} caption={t("navbar.about.aboutProject")}

0
src/components/search/SearchBar.tsx Executable file → Normal file
View File

View File

@ -47,7 +47,6 @@ export default function Link({
typeof style === "function" typeof style === "function"
? style({ ? style({
isActive: true, isActive: true,
isPending: false
}) })
: style : style
} }

View File

@ -15,7 +15,7 @@ export function RouterLink({
return ( return (
<NavLink <NavLink
to={to} to={to}
className={classNames({ "pointer-events-none": disabled }, className as string)} className={classNames({ "pointer-events-none": disabled }, className)}
> >
{children} {children}
</NavLink> </NavLink>

View File

@ -25,6 +25,7 @@ if (!rootElement) throw new Error("Failed to find the root element");
const root = ReactDOM.createRoot(rootElement); const root = ReactDOM.createRoot(rootElement);
root.render( root.render(
<Provider store={store}> <Provider store={store}>
<React.StrictMode>
<BrowserRouter> <BrowserRouter>
<Routes> <Routes>
<Route path="/" element={<App />} /> <Route path="/" element={<App />} />
@ -45,6 +46,7 @@ root.render(
<Route path="/*" element={<NotFound />}></Route> <Route path="/*" element={<NotFound />}></Route>
</Routes> </Routes>
</BrowserRouter> </BrowserRouter>
</React.StrictMode>
</Provider> </Provider>
); );

0
src/pages/SearchResultsPage.tsx Executable file → Normal file
View File