Skip to content
Snippets Groups Projects
Commit 5a9967db authored by xaralis's avatar xaralis
Browse files

feat: favicons, page desc, support removing likes/dislikes

parent 8762f823
Branches
No related tags found
No related merge requests found
...@@ -2,14 +2,21 @@ ...@@ -2,14 +2,21 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <!-- Favicons -->
<link rel="apple-touch-icon" href="%REACT_APP_STYLEGUIDE_URL%images/favicons/favicon-196x196.png">
<link rel="icon" type="image/png" href="%REACT_APP_STYLEGUIDE_URL%images/favicons/favicon-196x196.png" sizes="196x196">
<meta name="application-name" content="CF2021">
<meta name="msapplication-TileColor" content="#000000">
<meta name="msapplication-TileImage" content="%REACT_APP_STYLEGUIDE_URL%images/favicons/mstile-144x144.png">
<meta name="msapplication-square70x70logo" content="%REACT_APP_STYLEGUIDE_URL%images/favicons/mstile-70x70.png">
<meta name="msapplication-square150x150logo" content="%REACT_APP_STYLEGUIDE_URL%images/favicons/mstile-150x150.png">
<meta name="msapplication-wide310x150logo" content="%REACT_APP_STYLEGUIDE_URL%images/favicons/mstile-310x150.png">
<meta name="msapplication-square310x310logo" content="%REACT_APP_STYLEGUIDE_URL%images/favicons/mstile-310x310.png">
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta property="og:url" content="https://cf2021.pirati.cz/" />
name="description" <meta property="og:type" content="website" />
content="Web site created using create-react-app" <meta property="og:title" content="CF 2021" />
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
...@@ -24,8 +31,8 @@ ...@@ -24,8 +31,8 @@
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`.
--> -->
<link rel="stylesheet" href="%REACT_APP_STYLEGUIDE_URL%/css/styles.css" /> <link rel="stylesheet" href="%REACT_APP_STYLEGUIDE_URL%css/styles.css" />
<title>React App</title> <title>CF 2021 | Pirátská strana</title>
</head> </head>
<body class="h-screen"> <body class="h-screen">
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
......
...@@ -41,7 +41,7 @@ const LoadingComponent = ( ...@@ -41,7 +41,7 @@ const LoadingComponent = (
<div className="h-screen w-screen flex justify-center items-center"> <div className="h-screen w-screen flex justify-center items-center">
<div className="text-center"> <div className="text-center">
<img <img
src={`${process.env.REACT_APP_STYLEGUIDE_URL}/images/logo-round-black.svg`} src={`${process.env.REACT_APP_STYLEGUIDE_URL}images/logo-round-black.svg`}
className="w-20 mb-2 inline-block" className="w-20 mb-2 inline-block"
alt="Pirátská strana" alt="Pirátská strana"
/> />
......
...@@ -34,6 +34,37 @@ export const like = createAsyncAction( ...@@ -34,6 +34,37 @@ export const like = createAsyncAction(
} }
); );
export const removeLike = createAsyncAction(
/**
* @param {CF2021.Post} post
*/
async (post) => {
return successResult(post);
},
{
shortCircuitHook: ({ args }) => {
if (args.ranking.myVote !== "like") {
return errorResult();
}
return false;
},
postActionHook: ({ result }) => {
if (!result.error) {
PostStore.update((state) => {
state.items[result.payload.id].ranking.likes -= 1;
state.items[result.payload.id].ranking.score -= 1;
state.items[result.payload.id].ranking.myVote = "none";
if (state.filters.sort === "byScore") {
updateWindowPosts(state);
}
});
}
},
}
);
export const dislike = createAsyncAction( export const dislike = createAsyncAction(
/** /**
* @param {CF2021.Post} post * @param {CF2021.Post} post
...@@ -65,6 +96,37 @@ export const dislike = createAsyncAction( ...@@ -65,6 +96,37 @@ export const dislike = createAsyncAction(
} }
); );
export const removeDislike = createAsyncAction(
/**
* @param {CF2021.Post} post
*/
async (post) => {
return successResult(post);
},
{
shortCircuitHook: ({ args }) => {
if (args.ranking.myVote !== "dislike") {
return errorResult();
}
return false;
},
postActionHook: ({ result }) => {
if (!result.error) {
PostStore.update((state) => {
state.items[result.payload.id].ranking.dislikes -= 1;
state.items[result.payload.id].ranking.score += 1;
state.items[result.payload.id].ranking.myVote = "none";
if (state.filters.sort === "byScore") {
updateWindowPosts(state);
}
});
}
},
}
);
/** /**
* Add new discussion post. * Add new discussion post.
*/ */
......
...@@ -6,7 +6,7 @@ const Footer = () => { ...@@ -6,7 +6,7 @@ const Footer = () => {
<div className="footer__main py-4 lg:py-16 container container--default"> <div className="footer__main py-4 lg:py-16 container container--default">
<section className="footer__brand"> <section className="footer__brand">
<img <img
src="https://www.va-fighters.com/pirati/krajska-sablona/dist/assets/img/logo.svg" src={`${process.env.REACT_APP_STYLEGUIDE_URL}images/logo-full-white.svg`}
alt="" alt=""
className="w-32 md:w-40 pb-6" className="w-32 md:w-40 pb-6"
/> />
......
...@@ -24,7 +24,7 @@ const Navbar = () => { ...@@ -24,7 +24,7 @@ const Navbar = () => {
<div className="navbar__brand my-4 flex items-center lg:pr-8 lg:my-0"> <div className="navbar__brand my-4 flex items-center lg:pr-8 lg:my-0">
<NavLink to="/"> <NavLink to="/">
<img <img
src={`${process.env.REACT_APP_STYLEGUIDE_URL}/images/logo-round-white.svg`} src={`${process.env.REACT_APP_STYLEGUIDE_URL}images/logo-round-white.svg`}
className="w-8" className="w-8"
alt="Pirátská strana" alt="Pirátská strana"
/> />
......
import React from "react"; import React from "react";
import classNames from "classnames"; import classNames from "classnames";
const Thumbs = ({ likes, dislikes, onLike, onDislike, canThumb }) => { const Thumbs = ({ likes, dislikes, onLike, onDislike, myVote }) => {
return ( return (
<div> <div>
<div className="space-x-2 text-sm flex items-center"> <div className="space-x-2 text-sm flex items-center">
<button <button
className={classNames("text-blue-300 flex items-center space-x-1", { className={classNames("text-blue-300 flex items-center space-x-1", {
"cursor-not-allowed": !canThumb, "cursor-pointer": myVote === "none" || myVote === "like",
"cursor-default": myVote === "dislike",
})} })}
disabled={!canThumb} disabled={myVote === "dislike"}
onClick={onLike} onClick={onLike}
> >
<span className="font-bold">{likes}</span> <span className="font-bold">{likes}</span>
...@@ -17,9 +18,10 @@ const Thumbs = ({ likes, dislikes, onLike, onDislike, canThumb }) => { ...@@ -17,9 +18,10 @@ const Thumbs = ({ likes, dislikes, onLike, onDislike, canThumb }) => {
</button> </button>
<button <button
className={classNames("text-red-600 flex items-center space-x-1", { className={classNames("text-red-600 flex items-center space-x-1", {
"cursor-not-allowed": !canThumb, "cursor-pointer": myVote === "none" || myVote === "dislike",
"cursor-default": myVote === "like",
})} })}
disabled={!canThumb} disabled={myVote === "like"}
onClick={onDislike} onClick={onDislike}
> >
<i className="ico--thumbs-down transform -scale-x-1"></i> <i className="ico--thumbs-down transform -scale-x-1"></i>
......
...@@ -153,7 +153,7 @@ const Post = ({ ...@@ -153,7 +153,7 @@ const Post = ({
dislikes={ranking.dislikes} dislikes={ranking.dislikes}
onLike={onLike} onLike={onLike}
onDislike={onDislike} onDislike={onDislike}
canThumb={ranking.myVote === "none"} myVote={ranking.myVote}
/> />
{displayActions && ( {displayActions && (
<DropdownMenu right> <DropdownMenu right>
......
import React from "react"; import React from "react";
import pick from "lodash/pick"; import pick from "lodash/pick";
import { dislike, like } from "actions/posts"; import { dislike, like, removeDislike, removeLike } from "actions/posts";
import PostList from "components/posts/PostList"; import PostList from "components/posts/PostList";
import { PostStore } from "stores"; import { PostStore } from "stores";
...@@ -16,6 +16,32 @@ const PostsContainer = ({ className }) => { ...@@ -16,6 +16,32 @@ const PostsContainer = ({ className }) => {
// const onLike = (post) => like.run(); // const onLike = (post) => like.run();
// const onDislike = (post) => console.log("dislike", post); // const onDislike = (post) => console.log("dislike", post);
/**
*
* @param {CF2021.Post} post
*/
const onLike = (post) => {
if (post.ranking.myVote === "none") {
return like.run(post);
}
if (post.ranking.myVote === "like") {
return removeLike.run(post);
}
};
/**
*
* @param {CF2021.Post} post
*/
const onDislike = (post) => {
if (post.ranking.myVote === "none") {
return dislike.run(post);
}
if (post.ranking.myVote === "dislike") {
return removeDislike.run(post);
}
};
const sliceStart = (window.page - 1) * window.perPage; const sliceStart = (window.page - 1) * window.perPage;
const sliceEnd = window.page * window.perPage; const sliceEnd = window.page * window.perPage;
...@@ -40,8 +66,8 @@ const PostsContainer = ({ className }) => { ...@@ -40,8 +66,8 @@ const PostsContainer = ({ className }) => {
items={window.items items={window.items
.slice(sliceStart, sliceEnd) .slice(sliceStart, sliceEnd)
.map((postId) => items[postId])} .map((postId) => items[postId])}
onLike={like.run} onLike={onLike}
onDislike={dislike.run} onDislike={onDislike}
className={className} className={className}
dimArchived={!showingArchivedOnly} dimArchived={!showingArchivedOnly}
displayActions={true} displayActions={true}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment