Compare commits

...

47 Commits

Author SHA1 Message Date
moeidtopcoder
e9e9611f80 Merge branch 'develop' into master 2022-10-31 17:52:31 +00:00
0c054687ba Merge pull request 'the overlay in burger resolved' (#172) from fix/burger into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/172
2022-10-31 15:03:14 +00:00
3b147e50a1 Merge pull request 'resolve animation - resolve responsive' (#171) from fix/404-page into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/171
2022-10-31 15:02:49 +00:00
“Salar
e94514ed02 the overlay in burger resolved 2022-10-31 17:13:43 +03:00
“Salar
0032e51858 resolve animation - resolve responsive 2022-10-31 13:28:55 +03:00
8d6a9ab74c Dockerfile changes 2022-10-29 16:23:34 +03:00
07c4ae8cbd Fixed # on localization button 2022-10-26 16:00:45 +03:00
a782930d3d Replace mocks to real APIs 2022-10-21 18:12:15 +03:00
4c1877caa5 Merge pull request 'feature/markdown-styling' (#169) from feature/markdown-styling into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/169
2022-10-21 15:10:44 +00:00
e9324f6c14 Merge pull request 'classnames resolved' (#170) from fix/link into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/170
2022-10-21 15:10:28 +00:00
“Salar
9fcee44e0c classnames resolved 2022-10-21 18:03:17 +03:00
“Salar
9939b1c824 resolve headers, lists, link, paragraph.. 2022-10-21 17:57:55 +03:00
00deb05850 Merge branch 'develop' into feature/markdown-styling 2022-10-21 14:44:09 +03:00
b8849945b9 Merge pull request 'resolve no break space in the english localization' (#164) from fix/english-localization into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/164
2022-10-21 11:42:39 +00:00
08f5ee272b Merge pull request 'resolve no break space in the russian localization' (#165) from fix/russian-localization into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/165
2022-10-21 11:42:25 +00:00
35aa957b35 Merge pull request 'content hardcoded resolved' (#166) from fix/filter into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/166
2022-10-21 11:42:10 +00:00
472e8c2ea5 Merge pull request 'the translation in the main section has been resolved' (#167) from fix/main-section into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/167
2022-10-21 11:41:50 +00:00
f17d5f3079 Merge pull request 'resolve article translation' (#168) from fix/category-card into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/168
2022-10-21 11:41:33 +00:00
“Salar
4f9b33e5b9 resolve article translation 2022-10-21 14:21:26 +03:00
“Salar
753223c7a9 the translation of interaction buttons has been added 2022-10-21 14:07:48 +03:00
“Salar
28cc9b1a71 the translation in the main section has been resolved 2022-10-21 13:46:47 +03:00
“Salar
47472868e1 content hardcoded resolved 2022-10-21 13:29:08 +03:00
“Salar
f965eaddbc content and filter were added 2022-10-21 13:26:23 +03:00
“Salar
2075426ff7 resolve no break space in the russian localization 2022-10-21 13:08:21 +03:00
“Salar
209507833e resolve no break space in the english localization 2022-10-21 13:00:25 +03:00
eff20ae459 Mocked correct article body 2022-10-21 12:08:29 +03:00
dcfe260f0e Merge pull request 'resolve english translation' (#161) from fix/english-localization into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/161
2022-10-20 10:02:12 +00:00
1af206c360 Merge pull request 'remove additional link' (#162) from fix/featured-articles-cards into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/162
2022-10-20 10:01:39 +00:00
“Salar
932d23befa remove additional link 2022-10-19 18:12:32 +03:00
“Salar
e52026cf86 resolve english translation 2022-10-19 17:46:33 +03:00
033a1f31ad Merge pull request 'resolve localization button in the header' (#160) from fix/header into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/160
2022-10-19 14:31:03 +00:00
9c79f449c5 Manually merge 2022-10-19 17:30:50 +03:00
24652d0908 Merge branch 'develop' into fix/header 2022-10-19 17:29:26 +03:00
944baced6c Merge pull request 'localization button feature' (#159) from feature/localization-button into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/159
2022-10-19 14:24:01 +00:00
“Salar
01a873477b resolve localization button in the header 2022-10-19 16:58:19 +03:00
“Salar
d1b17592c3 localization button feature 2022-10-19 16:52:46 +03:00
1475d2db27 Merge pull request 'feature/add-filters' (#157) from feature/add-filters into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/157
2022-10-18 16:50:53 +00:00
1ba9dc28b5 Merge branch 'develop' into feature/add-filters 2022-10-18 19:50:13 +03:00
1817946fe6 Merge pull request 'changed query to our api' (#156) from fix/search-request into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/156
2022-10-18 16:49:16 +00:00
de5b6ad60c Merge pull request 'fixed logo to actual' (#158) from fix/scipaper-logo into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/158
2022-10-18 16:48:47 +00:00
maximus
31706ca4e8 fixed logo to actual 2022-10-18 19:26:29 +03:00
filantrop
969749c0c0 Merge branch 'feature/add-filters' of http://85.143.176.51:3000/free-land/front-end into feature/add-filters 2022-10-18 17:50:31 +03:00
filantrop
5667f30a92 add translate 2022-10-18 17:34:10 +03:00
maximus
d77c1c6388 fixed article endpoint 2022-10-18 17:13:46 +03:00
maximus
bd6fbbebfd changed query to our api 2022-10-18 16:51:27 +03:00
filantrop
2ffce71e74 fix styles 2022-10-18 14:59:38 +03:00
35900bec5d Merge pull request 'fix/article-interaction-buttons' (#155) from fix/article-interaction-buttons into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/155
2022-10-18 10:43:30 +00:00
30 changed files with 850 additions and 198 deletions

View File

@ -17,22 +17,25 @@ COPY . .
RUN npm run build RUN npm run build
# Bundle static assets with nginx # Bundle static assets with nginx
FROM nginx:1.21.6 as production FROM node:16-alpine as production
# Copy built assets from builder # Copy built assets from builder
COPY --from=builder /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
# Expose ports # Expose ports
EXPOSE 80 EXPOSE 3000
COPY entrypoint.sh .
COPY .env.production . COPY .env.production .
ENV NODE_ENV production ENV NODE_ENV production
ENV USER_NAME=node_user USER_UID=2000 GROUP_NAME=node_group GROUP_UID=2000
# Execute script RUN npm i -g serve \
RUN ["chmod", "+x", "./entrypoint.sh"] && deluser --remove-home node \
ENTRYPOINT ["./entrypoint.sh"] && addgroup --g ${GROUP_UID} -S ${GROUP_NAME} \
&& adduser -D -S -s /sbin/nologin -u ${USER_UID} -G ${GROUP_NAME} ${USER_NAME}\
&& chown -R ${USER_NAME}:${GROUP_NAME} "/app/"
# Start serving
CMD ["nginx", "-g", "daemon off;"] USER "${USER_NAME}"
CMD serve -s .

194
package-lock.json generated
View File

@ -8,6 +8,10 @@
"name": "freeland", "name": "freeland",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.2.0",
"@fortawesome/free-brands-svg-icons": "^6.2.0",
"@fortawesome/free-solid-svg-icons": "^6.2.0",
"@fortawesome/react-fontawesome": "^0.2.0",
"@headlessui/react": "^1.6.6", "@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",
@ -31,6 +35,7 @@
"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",
"react-lottie": "^1.2.3",
"react-markdown": "^8.0.3", "react-markdown": "^8.0.3",
"react-redux": "^8.0.2", "react-redux": "^8.0.2",
"react-router-dom": "^6.3.0", "react-router-dom": "^6.3.0",
@ -65,6 +70,7 @@
"@testing-library/react": "^13.3.0", "@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2", "@types/jest": "^27.5.2",
"@types/react-lottie": "^1.2.6",
"@types/react-syntax-highlighter": "^15.5.5", "@types/react-syntax-highlighter": "^15.5.5",
"autoprefixer": "^10.4.8", "autoprefixer": "^10.4.8",
"babel-plugin-named-exports-order": "^0.0.2", "babel-plugin-named-exports-order": "^0.0.2",
@ -2384,6 +2390,63 @@
"js-yaml": "bin/js-yaml.js" "js-yaml": "bin/js-yaml.js"
} }
}, },
"node_modules/@fortawesome/fontawesome-common-types": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.0.tgz",
"integrity": "sha512-rBevIsj2nclStJ7AxTdfsa3ovHb1H+qApwrxcTVo+NNdeJiB9V75hsKfrkG5AwNcRUNxrPPiScGYCNmLMoh8pg==",
"hasInstallScript": true,
"engines": {
"node": ">=6"
}
},
"node_modules/@fortawesome/fontawesome-svg-core": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.0.tgz",
"integrity": "sha512-Cf2mAAeMWFMzpLC7Y9H1I4o3wEU+XovVJhTiNG8ZNgSQj53yl7OCJaS80K4YjrABWZzbAHVaoHE1dVJ27AAYXw==",
"hasInstallScript": true,
"dependencies": {
"@fortawesome/fontawesome-common-types": "6.2.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@fortawesome/free-brands-svg-icons": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.2.0.tgz",
"integrity": "sha512-fm1y4NyZ2qKYNmYhdMz9VAWRw1Et7PMHNunSw3W0SVAwKwv6o0qiJworLH3Y9SnmhHzAymXJwCX1op22FFvGiA==",
"hasInstallScript": true,
"dependencies": {
"@fortawesome/fontawesome-common-types": "6.2.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@fortawesome/free-solid-svg-icons": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.0.tgz",
"integrity": "sha512-UjCILHIQ4I8cN46EiQn0CZL/h8AwCGgR//1c4R96Q5viSRwuKVo0NdQEc4bm+69ZwC0dUvjbDqAHF1RR5FA3XA==",
"hasInstallScript": true,
"dependencies": {
"@fortawesome/fontawesome-common-types": "6.2.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@fortawesome/react-fontawesome": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz",
"integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==",
"dependencies": {
"prop-types": "^15.8.1"
},
"peerDependencies": {
"@fortawesome/fontawesome-svg-core": "~1 || ~6",
"react": ">=16.3"
}
},
"node_modules/@gar/promisify": { "node_modules/@gar/promisify": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
@ -11497,6 +11560,15 @@
"@types/react": "*" "@types/react": "*"
} }
}, },
"node_modules/@types/react-lottie": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@types/react-lottie/-/react-lottie-1.2.6.tgz",
"integrity": "sha512-fvGJHD7SeUdVESHo7f7erRnXkTWaa/6Mo5TB+R0/ieSftKoFspA4sMlF2qMH6BljXI7ehFJbBtrD5bzDxPCkGg==",
"dev": true,
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/react-syntax-highlighter": { "node_modules/@types/react-syntax-highlighter": {
"version": "15.5.5", "version": "15.5.5",
"resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.5.tgz", "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.5.tgz",
@ -13539,6 +13611,27 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/babel-runtime": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==",
"dependencies": {
"core-js": "^2.4.0",
"regenerator-runtime": "^0.11.0"
}
},
"node_modules/babel-runtime/node_modules/core-js": {
"version": "2.6.12",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
"deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
"hasInstallScript": true
},
"node_modules/babel-runtime/node_modules/regenerator-runtime": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
},
"node_modules/bail": { "node_modules/bail": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
@ -25585,6 +25678,11 @@
"loose-envify": "cli.js" "loose-envify": "cli.js"
} }
}, },
"node_modules/lottie-web": {
"version": "5.9.6",
"resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.9.6.tgz",
"integrity": "sha512-JFs7KsHwflugH5qIXBpB4905yC1Sub2MZWtl/elvO/QC6qj1ApqbUZJyjzJseJUtVpgiDaXQLjBlIJGS7UUUXA=="
},
"node_modules/loud-rejection": { "node_modules/loud-rejection": {
"version": "1.6.0", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
@ -30322,6 +30420,21 @@
"react": ">=16.8.0" "react": ">=16.8.0"
} }
}, },
"node_modules/react-lottie": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/react-lottie/-/react-lottie-1.2.3.tgz",
"integrity": "sha512-qLCERxUr8M+4mm1LU0Ruxw5Y5Fn/OmYkGfnA+JDM/dZb3oKwVAJCjwnjkj9TMHtzR2U6sMEUD3ZZ1RaHagM7kA==",
"dependencies": {
"babel-runtime": "^6.26.0",
"lottie-web": "^5.1.3"
},
"engines": {
"npm": "^3.0.0"
},
"peerDependencies": {
"react": "^0.14.7 || ^15.0.0 || ^16.0.0"
}
},
"node_modules/react-markdown": { "node_modules/react-markdown": {
"version": "8.0.3", "version": "8.0.3",
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.3.tgz", "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.3.tgz",
@ -41489,6 +41602,43 @@
} }
} }
}, },
"@fortawesome/fontawesome-common-types": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.0.tgz",
"integrity": "sha512-rBevIsj2nclStJ7AxTdfsa3ovHb1H+qApwrxcTVo+NNdeJiB9V75hsKfrkG5AwNcRUNxrPPiScGYCNmLMoh8pg=="
},
"@fortawesome/fontawesome-svg-core": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.0.tgz",
"integrity": "sha512-Cf2mAAeMWFMzpLC7Y9H1I4o3wEU+XovVJhTiNG8ZNgSQj53yl7OCJaS80K4YjrABWZzbAHVaoHE1dVJ27AAYXw==",
"requires": {
"@fortawesome/fontawesome-common-types": "6.2.0"
}
},
"@fortawesome/free-brands-svg-icons": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.2.0.tgz",
"integrity": "sha512-fm1y4NyZ2qKYNmYhdMz9VAWRw1Et7PMHNunSw3W0SVAwKwv6o0qiJworLH3Y9SnmhHzAymXJwCX1op22FFvGiA==",
"requires": {
"@fortawesome/fontawesome-common-types": "6.2.0"
}
},
"@fortawesome/free-solid-svg-icons": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.0.tgz",
"integrity": "sha512-UjCILHIQ4I8cN46EiQn0CZL/h8AwCGgR//1c4R96Q5viSRwuKVo0NdQEc4bm+69ZwC0dUvjbDqAHF1RR5FA3XA==",
"requires": {
"@fortawesome/fontawesome-common-types": "6.2.0"
}
},
"@fortawesome/react-fontawesome": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz",
"integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==",
"requires": {
"prop-types": "^15.8.1"
}
},
"@gar/promisify": { "@gar/promisify": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
@ -48499,6 +48649,15 @@
"@types/react": "*" "@types/react": "*"
} }
}, },
"@types/react-lottie": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@types/react-lottie/-/react-lottie-1.2.6.tgz",
"integrity": "sha512-fvGJHD7SeUdVESHo7f7erRnXkTWaa/6Mo5TB+R0/ieSftKoFspA4sMlF2qMH6BljXI7ehFJbBtrD5bzDxPCkGg==",
"dev": true,
"requires": {
"@types/react": "*"
}
},
"@types/react-syntax-highlighter": { "@types/react-syntax-highlighter": {
"version": "15.5.5", "version": "15.5.5",
"resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.5.tgz", "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.5.tgz",
@ -50107,6 +50266,27 @@
} }
} }
}, },
"babel-runtime": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==",
"requires": {
"core-js": "^2.4.0",
"regenerator-runtime": "^0.11.0"
},
"dependencies": {
"core-js": {
"version": "2.6.12",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
},
"regenerator-runtime": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
}
}
},
"bail": { "bail": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
@ -59232,6 +59412,11 @@
"js-tokens": "^3.0.0 || ^4.0.0" "js-tokens": "^3.0.0 || ^4.0.0"
} }
}, },
"lottie-web": {
"version": "5.9.6",
"resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.9.6.tgz",
"integrity": "sha512-JFs7KsHwflugH5qIXBpB4905yC1Sub2MZWtl/elvO/QC6qj1ApqbUZJyjzJseJUtVpgiDaXQLjBlIJGS7UUUXA=="
},
"loud-rejection": { "loud-rejection": {
"version": "1.6.0", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
@ -62505,6 +62690,15 @@
"resolved": "https://registry.npmjs.org/react-loading-skeleton/-/react-loading-skeleton-3.1.0.tgz", "resolved": "https://registry.npmjs.org/react-loading-skeleton/-/react-loading-skeleton-3.1.0.tgz",
"integrity": "sha512-j1U1CWWs68nBPOg7tkQqnlFcAMFF6oEK6MgqAo15f8A5p7mjH6xyKn2gHbkcimpwfO0VQXqxAswnSYVr8lWzjw==" "integrity": "sha512-j1U1CWWs68nBPOg7tkQqnlFcAMFF6oEK6MgqAo15f8A5p7mjH6xyKn2gHbkcimpwfO0VQXqxAswnSYVr8lWzjw=="
}, },
"react-lottie": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/react-lottie/-/react-lottie-1.2.3.tgz",
"integrity": "sha512-qLCERxUr8M+4mm1LU0Ruxw5Y5Fn/OmYkGfnA+JDM/dZb3oKwVAJCjwnjkj9TMHtzR2U6sMEUD3ZZ1RaHagM7kA==",
"requires": {
"babel-runtime": "^6.26.0",
"lottie-web": "^5.1.3"
}
},
"react-markdown": { "react-markdown": {
"version": "8.0.3", "version": "8.0.3",
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.3.tgz", "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.3.tgz",

View File

@ -3,6 +3,10 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.2.0",
"@fortawesome/free-brands-svg-icons": "^6.2.0",
"@fortawesome/free-solid-svg-icons": "^6.2.0",
"@fortawesome/react-fontawesome": "^0.2.0",
"@headlessui/react": "^1.6.6", "@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",
@ -26,6 +30,7 @@
"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",
"react-lottie": "^1.2.3",
"react-markdown": "^8.0.3", "react-markdown": "^8.0.3",
"react-redux": "^8.0.2", "react-redux": "^8.0.2",
"react-router-dom": "^6.3.0", "react-router-dom": "^6.3.0",
@ -105,6 +110,7 @@
"@testing-library/react": "^13.3.0", "@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2", "@types/jest": "^27.5.2",
"@types/react-lottie": "^1.2.6",
"@types/react-syntax-highlighter": "^15.5.5", "@types/react-syntax-highlighter": "^15.5.5",
"autoprefixer": "^10.4.8", "autoprefixer": "^10.4.8",
"babel-plugin-named-exports-order": "^0.0.2", "babel-plugin-named-exports-order": "^0.0.2",

View File

@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>Freeland</title> <title>Scipaper</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>

View File

@ -62,26 +62,35 @@
}, },
"articlePage": { "articlePage": {
"abstract": "Abstract", "abstract": "Abstract",
"keywords": "Keywords" "keywords": "Keywords",
"interactionButtons":{
"abstract": "Abstract",
"readFile": "Read File",
"download" : "Download",
"share" : "Share",
"cite" : "Cite",
"copied": "Copied"
}
}, },
"navbar": { "navbar": {
"createNew": "Create an article", "createNew": "Create New",
"about": { "about": {
"navTitle": "About the project", "navTitle": "About",
"aboutProject": "About Scipaper", "aboutProject": "About Scipaper",
"contacts": "Contacts", "contacts": "Contacts",
"help": "Help" "help": "Help"
}, },
"library": { "library": {
"navTitle": "My library", "navTitle": "My library",
"publications": "Publications", "publications": "Publications",
"favorites": "Favorites", "favorites": "Favorites",
"collections": "Collections", "collections": "Collections",
"recentViewed": "History" "recentViewed": "History"
}, },
"auth": { "auth": {
"signIn": "Sign In", "signIn": "Sign In",
"signUp": "Sign Up" "signUp": "Sign Up"
} }
}, },
"footer": { "footer": {
@ -96,15 +105,15 @@
"supportedBy": "Created" "supportedBy": "Created"
}, },
"mainPage": { "mainPage": {
"title": "Scientific Library with free access", "title": "Scientific Library with Free Access",
"search": "Search", "search": "Search",
"article_one": "Articles", "article_one": "Articles",
"article_few": "Articles", "article_few": "Articles",
"article_many": "Articles", "article_many": "Articles",
"advancedSearch": "Advanced search", "advancedSearch": "Advanced search",
"featuredArticles": { "featuredArticles": {
"title": "Popular articles", "title": "Featured articles",
"descriptionPart1": "Choose the one you are interested in", "descriptionPart1": "Select the category of science you are interested in",
"descriptionPart2": "Scientific category", "descriptionPart2": "Scientific category",
"categories": { "categories": {
"Medical": "Medical", "Medical": "Medical",
@ -115,14 +124,25 @@
"Social": "Social" "Social": "Social"
} }
}, },
"featuredAuthors": "Popular authors", "featuredAuthors": "Featured authors",
"more": "More", "more": "See More ",
"showAll": "Show all" "showAll": "Show all"
}, },
"searchResults": { "searchResults": {
"title": "Search results", "title": "Search results",
"totalResults":"Total results", "totalResults":"Total results",
"nothingFound": "Nothing found" "nothingFound": "Nothing found"
},
"filters": {
"authors":"Authors",
"publicationsType": "Publications Type",
"content":"Content",
"publisher":"Publisher",
"publicationTopic":"Publication Topic",
"appliedFitlers":"Applied Fitlers",
"clearAll":"Clear All",
"enterAuthorsName":"Enter Author Name",
"showAll":"Show All"
} }
} }

View File

@ -73,15 +73,15 @@
} }
}, },
"navbar": { "navbar": {
"createNew": "Создать статью", "createNew": "Создать статью",
"about": { "about": {
"navTitle": "О проекте", "navTitle": "О проекте",
"aboutProject": "О Scipaper", "aboutProject": "О Scipaper",
"contacts": "Контакты", "contacts": "Контакты",
"help": "Помощь" "help": "Помощь"
}, },
"library": { "library": {
"navTitle": "Моя библиотека", "navTitle": "Моя библиотека",
"publications": "Публикации", "publications": "Публикации",
"favorites": "Избранное", "favorites": "Избранное",
"collections": "Коллекции", "collections": "Коллекции",
@ -131,5 +131,15 @@
"title": "Результаты поиска", "title": "Результаты поиска",
"totalResults":"Всего найдено", "totalResults":"Всего найдено",
"nothingFound": "Ничего не найдено" "nothingFound": "Ничего не найдено"
},
"filters": {
"authors":"Авторы",
"publicationsType": "Публикации",
"publisher":"Издатель",
"publicationTopic":"Тема публикации",
"appliedFitlers":"Фильтры",
"clearAll":"Очистить всё",
"enterAuthorsName":"Введите имя автора",
"showAll":"Показать все"
} }
} }

View File

@ -3,16 +3,17 @@ import { Article } from "../domain/articleEntity";
import { create } from "../domain/articleModel"; import { create } from "../domain/articleModel";
import { FetchArticleByIdDTO } from "./dto/fetch_article_by_id_dto"; import { FetchArticleByIdDTO } from "./dto/fetch_article_by_id_dto";
import Failure from "core/failure"; import Failure from "core/failure";
import { integratorApiClient } from "core/httpClient";
const articleEndpoint = "/papers/"
async function getArticle(id: string): Promise<Article> { async function getArticle(id: string): Promise<Article> {
try { try {
// await new Promise((res, _) => { const response = await integratorApiClient.get<FetchArticleByIdDTO>(
// setTimeout(() => res(null), 2000); // `https://run.mocky.io/v3/62cd4581-d864-4d46-b1d6-02b45b5d1994/${id}`
// });
const response = await axios.get<FetchArticleByIdDTO>(
`https://run.mocky.io/v3/62cd4581-d864-4d46-b1d6-02b45b5d1994/${id}`
// `https://jsonplaceholder.typicode.com/posts/${id}` // `https://jsonplaceholder.typicode.com/posts/${id}`
// `http://scipaper.ru/v1/papers/${id}` // `https://run.mocky.io/v3/066be3d8-0568-439a-8b20-062deed49a97`
articleEndpoint + id
); );
const dto = response.data; const dto = response.data;
return create({ return create({

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@
import classNames from "classnames"; import classNames from "classnames";
import { StyleType } from "core/_variants"; import { StyleType } from "core/_variants";
import React from "react"; import React from "react";
import {ReactComponent as DeleteIcon} from "./Filters/svg/chest.svg" import { ReactComponent as DeleteIcon } from "../assets/svg/xmark.svg";
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Component props */ /* Component props */
@ -49,11 +49,13 @@ function Badge({
> >
{children} {children}
{closeOption && ( {closeOption && (
<button <button onClick={onClick} className="h-4 w-5">
onClick={onClick} <div>
className=" text-white pr-1 pl-3 py-1" <DeleteIcon
> className="relative top-1 left-1 h-4 w-5 fill-white hover:fill-white stroke-white
<div><DeleteIcon className="h-[9px] w-[9px]" /></div> "
/>
</div>
</button> </button>
)} )}
</span> </span>

198
src/components/Burger.tsx Normal file
View File

@ -0,0 +1,198 @@
import { Menu, Transition } from "@headlessui/react";
import React, { Fragment } from "react";
import classNames from "classnames";
import { Disclosure } from "@headlessui/react";
/* -------------------------------------------------------------------------- */
/* Components */
/* -------------------------------------------------------------------------- */
import ContextMenuAction from "./drop-down-menu/ContextMenuAction";
import ContextMenu from "./drop-down-menu/ContextMenu";
import { Button } from "./Button/Button";
import Link from "./typography/Link";
/* -------------------------------------------------------------------------- */
/* Icons */
/* -------------------------------------------------------------------------- */
import { ReactComponent as SVGFavoriteOutlined } from "assets/svg/favorite-outlined.svg";
import { ReactComponent as SVGHamburger } from "assets/svg/hamburger.svg";
import { ReactComponent as SVGFolder } from "assets/svg/folder.svg";
import { ReactComponent as SVGFile } from "assets/svg/file.svg";
import { ReactComponent as SVGEye } from "assets/svg/eye.svg";
import { ReactComponent as SVGArrowUp } from "assets/svg/arrow-up.svg";
import { ReactComponent as SVGCaretDown } from "assets/svg/caret-down.svg";
type Props = React.ComponentPropsWithoutRef<"div">;
const Burger = (props: Props) => {
return (
<div {...props}>
<Menu as="div" className="relative inline-block text-left z-30">
<div>
<Menu.Button as={Button} emphasis="low">
<Button.Icon>
<SVGHamburger className="h-6 w-6" />
</Button.Icon>
</Menu.Button>
</div>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items
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"
>
<div className="py-1">
<Disclosure>
<Disclosure.Button className="uppercase text-base px-2 py-1">
<Link className="text-[#096DD9]">create new</Link>
</Disclosure.Button>
</Disclosure>
<hr />
<Disclosure>
{({ open }) => (
<>
<Disclosure.Button
className="uppercase px-2 flex justify-between w-full items-center
py-1
hover:bg-gray-100
text-base
"
>
my library
<SVGArrowUp
className={`${
open ? "rotate-180 transform" : "rotate-360"
} h-5 w-5 `}
/>
</Disclosure.Button>
<Link to="#" className="w-full">
<Disclosure.Panel
className="px-2 flex items-center font-normal gap-1 py-1 w-full ease-in-out duration-300
rounded
hover:bg-gray-200
text-base
"
>
<SVGFile className="stroke-black w-4 h-4" />
My Publications
</Disclosure.Panel>
</Link>
<Link to="#" className="w-full">
<Disclosure.Panel
className="px-2 flex items-center font-normal gap-1 py-1 w-full ease-in-out duration-300
rounded
hover:bg-gray-200
text-base
"
>
<SVGFavoriteOutlined className="stroke-black w-4 h-4" />
My Favorites
</Disclosure.Panel>
</Link>
<Link to="#" className="w-full">
<Disclosure.Panel
className="px-2 flex items-center font-normal gap-1 py-1 w-full ease-in-out duration-300
rounded
hover:bg-gray-200
text-base
"
>
<SVGFolder className="stroke-black fill-black w-4 h-4" />
My Collections
</Disclosure.Panel>
</Link>
<Link to="#" className="w-full">
<Disclosure.Panel
className="px-2 flex items-center font-normal gap-1 py-1 w-full ease-in-out duration-300
rounded
hover:bg-gray-200
text-base
"
>
<SVGEye className="stroke-black w-4 h-4" />
Recent Viewed
</Disclosure.Panel>
</Link>
</>
)}
</Disclosure>
<hr />
{/* Third list - start */}
<Disclosure>
{({ open }) => (
<>
<Disclosure.Button
className="uppercase px-2 flex justify-between w-full items-center
py-1
hover:bg-gray-100
text-base
"
>
About
<SVGArrowUp
className={`${
open ? "rotate-180 transform" : "rotate-360"
} h-5 w-5 `}
/>
</Disclosure.Button>
<Link to="#" className="w-full">
<Disclosure.Panel
className="px-2 flex items-center font-normal gap-1 py-1 w-full ease-in-out duration-300
rounded
hover:bg-gray-200
text-base
"
>
About Freeland
</Disclosure.Panel>
</Link>
<Link to="#" className="w-full">
<Disclosure.Panel
className="px-2 flex items-center font-normal gap-1 py-1 w-full ease-in-out duration-300
rounded
hover:bg-gray-200
text-base
"
>
Contact Us
</Disclosure.Panel>
</Link>
<Link to="#" className="w-full">
<Disclosure.Panel
className="px-2 flex items-center font-normal gap-1 py-1 w-full ease-in-out duration-300
rounded
hover:bg-gray-200
text-base
"
>
Help
</Disclosure.Panel>
</Link>
</>
)}
</Disclosure>
{/* Third list - end */}
</div>
</Menu.Items>
</Transition>
</Menu>
</div>
);
};
export default Burger;

View File

@ -13,7 +13,7 @@ type Props = {
} & Omit<React.ComponentPropsWithoutRef<"div">, "">; } & Omit<React.ComponentPropsWithoutRef<"div">, "">;
function CategoryCard({ count, title, iconChild, className, ...props }: Props) { function CategoryCard({ count, title, iconChild, className, ...props }: Props) {
const [t, i18next] = useTranslation() const [t, i18next] = useTranslation();
const iconChildStyle = const iconChildStyle =
"h-7 fill-gray-500 stroke-gray-500 group-focus:fill-blue-600 group-active:fill-blue-600 group-focus:stroke-blue-600 group-active:stroke-blue-600"; "h-7 fill-gray-500 stroke-gray-500 group-focus:fill-blue-600 group-active:fill-blue-600 group-focus:stroke-blue-600 group-active:stroke-blue-600";
@ -43,7 +43,8 @@ function CategoryCard({ count, title, iconChild, className, ...props }: Props) {
fontWeightVariant="normal" fontWeightVariant="normal"
className="text-xs text-gray-500 group-active:text-blue-600 group-focus:text-blue-600" className="text-xs text-gray-500 group-active:text-blue-600 group-focus:text-blue-600"
> >
{count} {t("mainPage.article", {count: count}).toString()} {count}{" "}
{t("mainPage.article_many", { count: count }).toString()}
</Typography> </Typography>
</div> </div>
</div> </div>

View File

@ -22,7 +22,7 @@ const Checkbox = ({ children, className, isChecked, ...props }: Props) => {
)} )}
htmlFor={props.id} htmlFor={props.id}
> >
<div className="w-6 h-6 relative"> <div className="w-5 h-5 relative">
<input <input
className="peer appearance-none transition-colors bg-transparent border-2 border-gray-300 w-6 h-6 className="peer appearance-none transition-colors bg-transparent border-2 border-gray-300 w-6 h-6
rounded checked:bg-blue-500 checked:border-blue-500 rounded checked:bg-blue-500 checked:border-blue-500
@ -33,8 +33,8 @@ const Checkbox = ({ children, className, isChecked, ...props }: Props) => {
checked={isChecked} checked={isChecked}
{...props} {...props}
/> />
<div className="h-2 w-2 absolute top-0 left-0"> <div className="h-2 w-2 absolute top-0.5 left-0.5">
<Checkmark className="h-6 w-6 fill-white hover:fill-white stroke-white" /> <Checkmark className="h-5 w-5 fill-white hover:fill-white stroke-white" />
</div> </div>
</div> </div>
{children} {children}

View File

@ -5,6 +5,8 @@ import React from "react";
import Badge from "components/Badge"; import Badge from "components/Badge";
import { IProduct } from "./IProdutct"; import { IProduct } from "./IProdutct";
import classNames from "classnames"; import classNames from "classnames";
import { useTranslation } from "react-i18next";
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Component props */ /* Component props */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -23,6 +25,9 @@ export default function AppiledFilters({
clearAll, clearAll,
className, className,
}: Props) { }: Props) {
const [t, i18next] = useTranslation()
return ( return (
<> <>
<div <div
@ -32,13 +37,13 @@ export default function AppiledFilters({
)} )}
> >
<div className="flex flex-row items-center justify-between space-x-3 "> <div className="flex flex-row items-center justify-between space-x-3 ">
<div className="font-medium">Фильтры</div> <div className="font-medium">{t("filters.appliedFitlers")}</div>
<div> <div>
<button <button
onClick={clearAll} onClick={clearAll}
className="font-normal text-sm text-gray-400" className="font-normal text-sm text-gray-400"
> >
Очистить всё {t("filters.clearAll")}
</button> </button>
</div> </div>
</div> </div>

View File

@ -5,6 +5,7 @@ import SearchFilterBar from "./SearchFilterBar";
import axios from "axios"; import axios from "axios";
import { useDebounce } from "./functions/debounce"; import { useDebounce } from "./functions/debounce";
import { IProduct } from "./IProdutct"; import { IProduct } from "./IProdutct";
import { useTranslation } from "react-i18next";
type Props = { type Props = {
className?: string; className?: string;
@ -26,6 +27,8 @@ export default function Fiter({ className }: Props) {
}; };
const debounced = useDebounce(query); const debounced = useDebounce(query);
const [t, i18next] = useTranslation();
async function fetchProducts() { async function fetchProducts() {
const response = await axios.get( const response = await axios.get(
`https://dummyjson.com/products/search?q=${debounced}` `https://dummyjson.com/products/search?q=${debounced}`
@ -83,24 +86,24 @@ export default function Fiter({ className }: Props) {
delFilter={DelFilter} delFilter={DelFilter}
clearAll={clearAll} clearAll={clearAll}
></AppiledFilters> ></AppiledFilters>
<Disclosure caption="Авторы"> <Disclosure caption={t("filters.authors")}>
<SearchFilterBar <SearchFilterBar
hints={hints} hints={hints}
isChecked={isChecked} isChecked={isChecked}
handleChange={handleChange} handleChange={handleChange}
onChange={onChange} onChange={onChange}
query={query} query={query}
placeHolder={"Введите имя автора"} placeHolder={t("filters.enterAuthorsName")}
/> />
</Disclosure> </Disclosure>
<Disclosure caption="Публикации"> <Disclosure caption={t("filters.publicationsType")}>
<p>контент...</p> <p>{t("filters.content")}</p>
</Disclosure> </Disclosure>
<Disclosure caption="Тип издания"> <Disclosure caption={t("filters.publisher")}>
<p>контент...</p> <p>{t("filters.content")}</p>
</Disclosure> </Disclosure>
<Disclosure caption="Тематика публикаций"> <Disclosure caption={t("filters.publicationTopic")}>
<p>контент...</p> <p>{t("filters.content")}</p>
</Disclosure> </Disclosure>
</div> </div>
</div> </div>

View File

@ -2,8 +2,10 @@ import { useState, useCallback, Fragment } from "react";
import { Combobox, Transition } from "@headlessui/react"; import { Combobox, Transition } from "@headlessui/react";
import { IProduct } from "./IProdutct"; import { IProduct } from "./IProdutct";
import Checkbox from "components/Checkbox"; import Checkbox from "components/Checkbox";
import { ReactComponent as SearchIcon } from "./svg/searchIcon.svg"; import { ReactComponent as SearchIcon } from "assets/svg/search.svg";
import classNames from "classnames"; import classNames from "classnames";
import { useTranslation } from "react-i18next";
type Props = { type Props = {
hints: IProduct[]; hints: IProduct[];
@ -26,6 +28,7 @@ export default function SearchFilterBar({
}: Props): JSX.Element { }: Props): JSX.Element {
const [checkList, setCheckList] = useState(hints); const [checkList, setCheckList] = useState(hints);
const [showFilters, SetShowFilters] = useState(false); const [showFilters, SetShowFilters] = useState(false);
const [t, i18next] = useTranslation()
const ShowAllFilters = useCallback(() => { const ShowAllFilters = useCallback(() => {
SetShowFilters((prev) => !prev); SetShowFilters((prev) => !prev);
@ -44,8 +47,8 @@ export default function SearchFilterBar({
> >
<div className="basis-6 "> <div className="basis-6 ">
<Combobox.Button> <Combobox.Button>
<div className="pl-1 pt-1"> <div className="pl-1 pt-1.5">
<SearchIcon /> <SearchIcon className="h-5 w-6 fill-gray-400 hover:fill-gray-400 stroke-gray-400" />
</div> </div>
</Combobox.Button> </Combobox.Button>
</div> </div>
@ -73,18 +76,18 @@ export default function SearchFilterBar({
{ {
"max-h-60 h-60 overflow-auto": showFilters === true, "max-h-60 h-60 overflow-auto": showFilters === true,
"max-h-40 h-40 overflow-hidden": "max-h-40 h-40 overflow-hidden":
showFilters === false, showFilters === false || hints.length <= 5,
}, },
], ],
])} ])}
> >
<li className=""> <li className="">
{hints.length >= 5 && query !== "" && ( {hints.length >= 6 && query !== "" && (
<button <button
onClick={ShowAllFilters} onClick={ShowAllFilters}
className="text-right text-blue-500 pl-2 text-sm font-medium" className="text-right text-blue-500 pl-2 text-sm font-medium"
> >
Показать всё({hints.length}) {t("filters.showAll")}({hints.length})
</button> </button>
)} )}
</li> </li>
@ -102,7 +105,7 @@ export default function SearchFilterBar({
</li> </li>
)) ))
) : ( ) : (
<p className="text-blue-300 pl-2">Nothing Found</p> <p className="text-blue-300 pl-2">Ничего не найдено</p>
)} )}
</ul> </ul>
)} )}

View File

@ -1,4 +0,0 @@
<svg width="12" height="13" viewBox="0 0 12 13" fill="white" xmlns="http://www.w3.org/2000/svg">
<path d="M10.9497 11.4498L1.05026 1.55027" stroke="white" stroke-width="2" stroke-linecap="round"/>
<path d="M10.9497 1.55029L1.05025 11.4498" stroke="white" stroke-width="2" stroke-linecap="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 304 B

View File

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.1003 14.1184L10.4628 9.48086C11.1824 8.55051 11.5717 7.41301 11.5717 6.21658C11.5717 4.78444 11.0128 3.44158 10.0021 2.42908C8.99135 1.41658 7.64492 0.859436 6.21456 0.859436C4.78421 0.859436 3.43778 1.41836 2.42706 2.42908C1.41456 3.43979 0.857422 4.78444 0.857422 6.21658C0.857422 7.64694 1.41635 8.99336 2.42706 10.0041C3.43778 11.0166 4.78242 11.5737 6.21456 11.5737C7.41099 11.5737 8.54671 11.1844 9.47707 10.4666L14.1146 15.1023C14.1282 15.1159 14.1443 15.1267 14.1621 15.1341C14.1799 15.1414 14.1989 15.1452 14.2181 15.1452C14.2374 15.1452 14.2564 15.1414 14.2742 15.1341C14.292 15.1267 14.3081 15.1159 14.3217 15.1023L15.1003 14.3255C15.1139 14.3119 15.1247 14.2958 15.132 14.278C15.1394 14.2602 15.1432 14.2412 15.1432 14.2219C15.1432 14.2027 15.1394 14.1837 15.132 14.1659C15.1247 14.1481 15.1139 14.132 15.1003 14.1184ZM9.04314 9.04515C8.28599 9.80051 7.28242 10.2166 6.21456 10.2166C5.14671 10.2166 4.14314 9.80051 3.38599 9.04515C2.63064 8.28801 2.21456 7.28444 2.21456 6.21658C2.21456 5.14872 2.63064 4.14336 3.38599 3.38801C4.14314 2.63265 5.14671 2.21658 6.21456 2.21658C7.28242 2.21658 8.28778 2.63086 9.04314 3.38801C9.79849 4.14515 10.2146 5.14872 10.2146 6.21658C10.2146 7.28444 9.79849 8.28979 9.04314 9.04515Z" fill="#8C8C8C"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,89 @@
import React, { Fragment, useState } from "react";
import { Trans, useTranslation } from "react-i18next";
import { Button } from "./Button/Button";
import { Menu, Transition } from "@headlessui/react";
import classNames from "classnames";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faLanguage } from "@fortawesome/free-solid-svg-icons";
type Props = React.ComponentPropsWithoutRef<"div">;
const LocalizationButton = (props: Props) => {
const { t, i18n } = useTranslation();
const changeLanguage = (lng: string) => {
i18n.changeLanguage(lng);
setLanguage(lng);
};
const [language, setLanguage] = useState("en");
return (
<div {...props}>
<Menu as="div" className="relative inline-block text-left">
<div>
<Menu.Button
as={Button}
emphasis="low"
className="flex items-center gap-2 border"
>
<div className=" w-4">
<FontAwesomeIcon icon={faLanguage} />
</div>
{/* {language} */}
</Menu.Button>
</div>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items
className="origin-top-right absolute right-0 mt-5 w-12 rounded-md
shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none"
>
<div className="py-1">
<Menu.Item>
{({ active }) => (
<a
onClick={() => {
changeLanguage("en");
}}
className={classNames(
active ? "bg-gray-100 text-gray-900" : "text-gray-700",
"block px-4 py-2 text-sm"
)}
>
En
</a>
)}
</Menu.Item>
<Menu.Item>
{({ active }) => (
<a
onClick={() => {
changeLanguage("ru");
}}
className={classNames(
active ? "bg-gray-100 text-gray-900" : "text-gray-700",
"block px-4 py-2 text-sm"
)}
>
Ru
</a>
)}
</Menu.Item>
</div>
</Menu.Items>
</Transition>
</Menu>
</div>
);
};
export default LocalizationButton;

39
src/components/LogoScipaper.tsx Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -168,14 +168,12 @@ const FeaturedArticlesCards = () => {
</Card.CardContent> </Card.CardContent>
<Card.CardAction href={Articale.Link}> <Card.CardAction href={Articale.Link}>
<Link to="*"> <Typography
<Typography className="text-blue-500 font-bold"
className="text-blue-500 font-bold" fontWeightVariant="bold"
fontWeightVariant="bold" >
> {t("mainPage.more")}
{t("mainPage.more")} </Typography>
</Typography>
</Link>
<SVGCaretRight className="fill-blue-500 w-4 h-4" /> <SVGCaretRight className="fill-blue-500 w-4 h-4" />
</Card.CardAction> </Card.CardAction>
</Card> </Card>

View File

@ -2,16 +2,14 @@
/* Imports */ /* Imports */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
import React from "react"; import React from "react";
import {t as nextT} from "i18next"; import { t as nextT } from "i18next";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { SearchBar } from "../../search/SearchBar"; import { SearchBar } from "../../search/SearchBar";
import { formatNumber } from "core/helpers"; import { formatNumber } from "core/helpers";
export default function MainSection() { export default function MainSection() {
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
const amountArticles = 4202020 const amountArticles = 4202020;
return ( return (
<section className="bg-main bg-center bg-cover bg-origin-border bg-no-repeat min-h-[100vh] py-32 px-2 sm:px-6 md:px-6 lg:px-0 items-center flex justify-center "> <section className="bg-main bg-center bg-cover bg-origin-border bg-no-repeat min-h-[100vh] py-32 px-2 sm:px-6 md:px-6 lg:px-0 items-center flex justify-center ">
@ -21,8 +19,14 @@ export default function MainSection() {
</div> </div>
<div className="flex flex-row items-center justify-center space-x-3 pt-2"> <div className="flex flex-row items-center justify-center space-x-3 pt-2">
<div className=" text-2xl text-gray-400">{t("mainPage.search")}</div> <div className=" text-2xl text-gray-400">{t("mainPage.search")}</div>
<div className=" text-3xl text-blue-500">{formatNumber(amountArticles)}</div> <div className=" text-3xl text-blue-500">
<div className=" text-2xl text-gray-400">{nextT("mainPage.article", {count: amountArticles}).toString()}</div> {formatNumber(amountArticles)}
</div>
<div className=" text-2xl text-gray-400">
{nextT("mainPage.article_many", {
count: amountArticles,
}).toString()}
</div>
</div> </div>
<div className="max-w-xl m-auto pt-16 "> <div className="max-w-xl m-auto pt-16 ">
<SearchBar /> <SearchBar />

View File

@ -1,5 +1,3 @@
import React from "react";
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* MarkDown */ /* MarkDown */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -18,33 +16,137 @@ import Heading from "./typography/Heading";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { dark } 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 { indexOf } from "lodash"; import style from "react-syntax-highlighter/dist/esm/styles/hljs/a11y-dark";
export type Props = { export type Props = {
markdown: string; markdown: string;
}; };
const Markdown = ({ markdown }: Props) => { const Markdown = ({ markdown }: Props) => {
let newMarkdown = markdown.replace(/\n/g, " \n");
return ( return (
<ReactMarkdown <ReactMarkdown
remarkPlugins={[remarkGfm]} remarkPlugins={[remarkGfm]}
children={newMarkdown} children={markdown}
components={{ components={{
h1: Heading, ul: ({ node, ...props }) => (
h2: Typography, <ul
a: (props) => { style={{
return ( listStyleType: "disc",
<Link }}
href={props.href} className="mx-8"
className="text-sky-600 font-bold text-base" {...props}
{...props} />
> ),
{props.children}
</Link> ol: ({ node, ...props }) => (
); <ol className="list-decimal mx-8" {...props} />
}, ),
h1: ({ node, ...props }) => (
<h1
style={{
fontWeight: "bold",
marginInlineEnd: 0,
marginInlineStart: 0,
marginBlockStart: 11,
marginBlockEnd: 11,
fontSize: 32,
}}
{...props}
/>
),
h2: ({ node, ...props }) => (
<h1
style={{
fontWeight: "bold",
marginInlineEnd: 0,
marginInlineStart: 0,
marginBlockStart: 13.28,
marginBlockEnd: 13.28,
fontSize: 24,
}}
{...props}
/>
),
h3: ({ node, ...props }) => (
<h1
style={{
fontWeight: "bold",
marginInlineEnd: 0,
marginInlineStart: 0,
marginBlockStart: 16,
marginBlockEnd: 16,
fontSize: 18.72,
}}
{...props}
/>
),
h4: ({ node, ...props }) => (
<h1
style={{
fontWeight: "bold",
marginInlineEnd: 0,
marginInlineStart: 0,
marginBlockStart: 21.28,
marginBlockEnd: 21.28,
}}
{...props}
/>
),
h5: ({ node, ...props }) => (
<h1
style={{
fontWeight: "bold",
marginInlineEnd: 0,
marginInlineStart: 0,
marginBlockStart: 26.72,
marginBlockEnd: 26.72,
fontSize: 13.28,
}}
{...props}
/>
),
h6: ({ node, ...props }) => (
<h1
style={{
fontWeight: "bold",
marginInlineEnd: 0,
marginInlineStart: 0,
marginBlockStart: 37.28,
marginBlockEnd: 37.28,
fontSize: 10.72,
}}
{...props}
/>
),
p: Typography,
a: ({ node, ...props }) => (
<Link
className=" inline-flex text-sm font-bold text-blue-500"
{...props}
/>
),
code({ node, inline, className, children, ...props }) { code({ node, inline, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || ""); const match = /language-(\w+)/.exec(className || "");

View File

@ -36,7 +36,7 @@ export const SearchResultSection = () => {
{t("searchResults.title")} {t("searchResults.title")}
</Typography> </Typography>
<Typography className="text-gray-300 text-sm"> <Typography className="text-gray-300 text-sm">
{t("searchResults.totalResults")}: {searchResults?.meta.total} {t("searchResults.totalResults")}: {searchResults?.meta.total}
</Typography> </Typography>
</div> </div>
<hr className="w-full border-gray-100" /> <hr className="w-full border-gray-100" />

View File

@ -12,6 +12,7 @@ import * as ArticlePart from "../../components/Article/Article";
import BaseLayout from "components/BaseLayout"; 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";
const AnArticleBody = () => { const AnArticleBody = () => {
const store = useArticleStore(); const store = useArticleStore();
@ -46,7 +47,12 @@ const AnArticleBody = () => {
<ArticlePart.Article.Title className="text-3xl"> <ArticlePart.Article.Title className="text-3xl">
{article?.title} {article?.title}
</ArticlePart.Article.Title> </ArticlePart.Article.Title>
<div className="py-6">{article?.content}</div>
<div className="py-6">
<Markdown
markdown={article?.content ?? ''}
/>
</div>
</div> </div>
</> </>
)} )}

View File

@ -3,7 +3,19 @@ import Container from "components/Container";
import { Button } from "components/Button/Button"; import { Button } from "components/Button/Button";
import Link from "components/typography/Link"; import Link from "components/typography/Link";
import Lottie from "react-lottie";
import animationData from "../../assets/lotties/notFoundAnimation.json";
const NotFound = () => { const NotFound = () => {
const defaultOptions = {
loop: true,
autoplay: true,
animationData: animationData,
rendererSettings: {
preserveAspectRatio: "xMidYMid slice",
},
};
return ( return (
<Container <Container
variant="straight" variant="straight"
@ -11,13 +23,8 @@ const NotFound = () => {
font-serif h-screen my-auto font-serif h-screen my-auto
" "
> >
<div <Lottie options={defaultOptions} height={200} width={200} />
className="bg-[url('https://cdn.dribbble.com/users/285475/screenshots/2083086/dribbble_1.gif')] <span className="font-bold text-5xl ">404</span>
h-[450px]
w-full text-center text-7xl "
>
404
</div>
<h3 className="font-bold text-2xl text-center">Page does not exist</h3> <h3 className="font-bold text-2xl text-center">Page does not exist</h3>
<h4 className="text-center"> <h4 className="text-center">
Maybe you got a broken link, or maybe you made a misprint in the address Maybe you got a broken link, or maybe you made a misprint in the address

View File

@ -5,7 +5,6 @@ import { useState, useTransition } from "react";
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
import ContextMenuAction from "../drop-down-menu/ContextMenuAction"; import ContextMenuAction from "../drop-down-menu/ContextMenuAction";
import ContextMenu from "../drop-down-menu/ContextMenu"; import ContextMenu from "../drop-down-menu/ContextMenu";
import Logofreeland from "../Logofreeland";
import { Button } from "../Button/Button"; import { Button } from "../Button/Button";
import Avatar from "../Avatar"; import Avatar from "../Avatar";
import Navbar from "../Navbar"; import Navbar from "../Navbar";
@ -25,6 +24,10 @@ import {
} from "components/icons"; } from "components/icons";
import i18n from "localization/i18n"; import i18n from "localization/i18n";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Link from "components/typography/Link";
import LocalizationButton from "components/LocalizationButton";
import LogoScipaper from "components/LogoScipaper";
import Burger from "components/Burger";
const Header = () => { const Header = () => {
const [authenticated, setAuthenticated] = useState(false); const [authenticated, setAuthenticated] = useState(false);
@ -49,14 +52,14 @@ const Header = () => {
{/* Logo and Menu */} {/* Logo and Menu */}
<div className="flex gap-8 xl:gap-x-16"> <div className="flex gap-8 xl:gap-x-16">
{/* Logo - start - className="w-7 sm:w-10 " /> */} {/* Logo - start - className="w-7 sm:w-10 " /> */}
<a className="Logo flex items-center gap-1 sm:gap-2 " href="/"> <Link className="Logo flex items-center gap-1 sm:gap-2 " to="/">
<Logo <Logo
className={classNames(authenticated ? "w-10" : "w-7 sm:w-10")} className={classNames(authenticated ? "w-10" : "w-7 sm:w-10")}
/> />
<Logofreeland <LogoScipaper
className={classNames(authenticated ? "w-28" : "w-20 sm:w-28")} className={classNames(authenticated ? "w-28" : "w-20 sm:w-28")}
/> />
</a> </Link>
{/* Logo - end - */} {/* Logo - end - */}
{/* Menu( Create new - My library - About ) Start */} {/* Menu( Create new - My library - About ) Start */}
@ -69,36 +72,36 @@ const Header = () => {
className="text-blue-500 px-4 font-bold uppercase" className="text-blue-500 px-4 font-bold uppercase"
to="/create-new" to="/create-new"
> >
{t('navbar.createNew')} {t("navbar.createNew")}
</RouterLink> </RouterLink>
{/* Link Create now - end - */} {/* Link Create now - end - */}
{/* Dropdown Menu My library - start - */} {/* Dropdown Menu My library - start - */}
<ContextMenu <ContextMenu
emphasis="high" emphasis="high"
button={t('navbar.library.navTitle')} button={t("navbar.library.navTitle")}
className="border-none uppercase" className="border-none uppercase"
> >
<ContextMenuAction <ContextMenuAction
caption={t('navbar.library.publications')} caption={t("navbar.library.publications")}
action={() => console.log("My publications")} action={() => console.log("My publications")}
icon={<SVGFile className="stroke-black " />} icon={<SVGFile className="stroke-black " />}
></ContextMenuAction> ></ContextMenuAction>
<ContextMenuAction <ContextMenuAction
caption={t('navbar.library.favorites')} caption={t("navbar.library.favorites")}
action={() => console.log("My Favorites")} action={() => console.log("My Favorites")}
icon={<SVGFavoriteOutlined className="stroke-black" />} icon={<SVGFavoriteOutlined className="stroke-black" />}
></ContextMenuAction> ></ContextMenuAction>
<ContextMenuAction <ContextMenuAction
caption={t('navbar.library.collections')} caption={t("navbar.library.collections")}
action={() => console.log("My Collections")} action={() => console.log("My Collections")}
icon={<SVGFolder className="stroke-black fill-black" />} icon={<SVGFolder className="stroke-black fill-black" />}
></ContextMenuAction> ></ContextMenuAction>
<ContextMenuAction <ContextMenuAction
caption={t('navbar.library.recentViewed')} caption={t("navbar.library.recentViewed")}
action={() => console.log("Recent Viewed")} action={() => console.log("Recent Viewed")}
icon={<SVGEye className="stroke-black " />} icon={<SVGEye className="stroke-black " />}
></ContextMenuAction> ></ContextMenuAction>
@ -108,21 +111,21 @@ const Header = () => {
{/* Dropdown Menu About - start - */} {/* Dropdown Menu About - start - */}
<ContextMenu <ContextMenu
emphasis="high" emphasis="high"
button={t('navbar.about.navTitle')} button={t("navbar.about.navTitle")}
className="border-none uppercase" className="border-none uppercase"
> >
<ContextMenuAction <ContextMenuAction
caption={t('navbar.about.aboutProject')} caption={t("navbar.about.aboutProject")}
action={() => console.log("About Freeland")} action={() => console.log("About Freeland")}
></ContextMenuAction> ></ContextMenuAction>
<ContextMenuAction <ContextMenuAction
caption={t('navbar.about.contacts')} caption={t("navbar.about.contacts")}
action={() => console.log("Contact Us")} action={() => console.log("Contact Us")}
></ContextMenuAction> ></ContextMenuAction>
<ContextMenuAction <ContextMenuAction
caption={t('navbar.about.help')} caption={t("navbar.about.help")}
action={() => console.log("Help")} action={() => console.log("Help")}
></ContextMenuAction> ></ContextMenuAction>
</ContextMenu> </ContextMenu>
@ -135,40 +138,43 @@ const Header = () => {
<div className="flex items-center font-bold text-sm gap-1 md:gap-2 "> <div className="flex items-center font-bold text-sm gap-1 md:gap-2 ">
{!authenticated {!authenticated
? [ ? [
<Button <>
emphasis="low" <LocalizationButton className="hidden md:flex" />
onClick={onClick} <Button
className="text-xs sm:px-4 sm:text-sm " emphasis="low"
> onClick={onClick}
{t('navbar.auth.signIn')} className="text-xs sm:px-4 sm:text-sm "
</Button>, >
<Button {t("navbar.auth.signIn")}
emphasis="medium" </Button>
className="hidden md:flex" </>,
onClick={onClick} <Button
> emphasis="medium"
{t('navbar.auth.signUp')} className="hidden md:flex"
</Button>, onClick={onClick}
] >
{t("navbar.auth.signUp")}
</Button>,
]
: [ : [
<Button emphasis="low"> <Button emphasis="low">
<Button.Icon> <Button.Icon>
{!notification ? ( {!notification ? (
<SVGBell className="h-6 w-6 fill-gray-900 stroke-gray-900" /> <SVGBell className="h-6 w-6 fill-gray-900 stroke-gray-900" />
) : ( ) : (
<SVGBellNotification className="h-6 w-6 fill-gray-900 stroke-gray-900" /> <SVGBellNotification className="h-6 w-6 fill-gray-900 stroke-gray-900" />
)} )}
</Button.Icon> </Button.Icon>
</Button>, </Button>,
<Button emphasis="low" className="hidden lg:flex"> <Button emphasis="low" className="hidden lg:flex">
<Button.Icon> <Button.Icon>
<Avatar className="bg-[rgb(255,122,69)] text-white">K</Avatar> <Avatar className="bg-[rgb(255,122,69)] text-white">K</Avatar>
</Button.Icon> </Button.Icon>
</Button>, </Button>,
]} ]}
{/* Burger component will be shown for the small screens */} {/* Burger component will be shown for the small screens */}
<Navbar className="block lg:hidden" /> <Burger className="block lg:hidden" />
</div> </div>
</header> </header>
); );

View File

@ -51,7 +51,7 @@ export default function Link({
: style : style
} }
aria-disabled={disabled} aria-disabled={disabled}
className="flex items-center" className={classNames("flex items-center", className)}
{...props} {...props}
> >
{children} {children}

View File

@ -22,7 +22,7 @@ const fallbackLng: Langs = "ru";
i18n i18n
.use(Backend) .use(Backend)
// .use(LanguageDetector) .use(LanguageDetector)
.use(initReactI18next) .use(initReactI18next)
.init({ .init({
debug: process.env.NODE_ENV === "development" ? true : false, debug: process.env.NODE_ENV === "development" ? true : false,

View File

@ -10,8 +10,8 @@ const searchEndpoint = "/papers/search";
async function search(request: string): Promise<SearchResults> { async function search(request: string): Promise<SearchResults> {
try { try {
const response = await integratorApiClient.get<SearchResultsDTO>( const response = await integratorApiClient.get<SearchResultsDTO>(
// searchEndpoint + `?query=` + request searchEndpoint + `?query=` + request
"https://run.mocky.io/v3/ea705665-2479-4039-8b81-412e011fc145" // "https://run.mocky.io/v3/ea705665-2479-4039-8b81-412e011fc145"
); );
const dto = response.data; const dto = response.data;
return create({ return create({