looking decent
This commit is contained in:
@@ -21,7 +21,6 @@ export interface Post {
|
||||
export interface CardProps {
|
||||
post: Post;
|
||||
privilegeLevel: "anonymous" | "admin" | "user";
|
||||
linkTarget: "blog" | "project";
|
||||
}
|
||||
|
||||
export default function Card(props: CardProps) {
|
||||
@@ -36,7 +35,7 @@ export default function Card(props: CardProps) {
|
||||
</div>
|
||||
</Show>
|
||||
<DeletePostButton
|
||||
type={props.linkTarget === "blog" ? "Blog" : "Project"}
|
||||
type="Blog"
|
||||
postID={props.post.id}
|
||||
/>
|
||||
</div>
|
||||
@@ -46,9 +45,7 @@ export default function Card(props: CardProps) {
|
||||
src={
|
||||
props.post.banner_photo
|
||||
? props.post.banner_photo
|
||||
: props.linkTarget === "blog"
|
||||
? "/bitcoin.jpg"
|
||||
: "/blueprint.jpg"
|
||||
: "/bitcoin.jpg"
|
||||
}
|
||||
alt={props.post.title.replaceAll("_", " ") + " banner"}
|
||||
class="h-full w-full object-cover"
|
||||
@@ -74,7 +71,6 @@ export default function Card(props: CardProps) {
|
||||
</div>
|
||||
<CardLinks
|
||||
postTitle={props.post.title}
|
||||
linkTarget={props.linkTarget}
|
||||
privilegeLevel={props.privilegeLevel}
|
||||
postID={props.post.id}
|
||||
/>
|
||||
|
||||
@@ -5,7 +5,6 @@ import LoadingSpinner from "~/components/LoadingSpinner";
|
||||
export interface CardLinksProps {
|
||||
postTitle: string;
|
||||
postID: number;
|
||||
linkTarget: string;
|
||||
privilegeLevel: string;
|
||||
}
|
||||
|
||||
@@ -19,12 +18,8 @@ export default function CardLinks(props: CardLinksProps) {
|
||||
href={`/blog/${props.postTitle}`}
|
||||
onClick={() => setReadLoading(true)}
|
||||
class={`${
|
||||
readLoading()
|
||||
? "bg-zinc-400"
|
||||
: props.linkTarget === "project"
|
||||
? "bg-blue-400 hover:bg-blue-500 dark:bg-blue-600 dark:hover:bg-blue-700"
|
||||
: "bg-orange-400 hover:bg-orange-500"
|
||||
} mb-1 ml-2 flex rounded px-4 py-2 font-light text-white shadow transition-all duration-300 ease-out active:scale-90`}
|
||||
readLoading() ? "bg-zinc-400" : "bg-lavender hover:brightness-125"
|
||||
} mb-1 ml-2 flex rounded px-4 py-2 text-base font-light shadow transition-all duration-300 ease-out active:scale-90`}
|
||||
>
|
||||
<Show when={readLoading()} fallback="Read">
|
||||
<LoadingSpinner height={24} width={24} />
|
||||
|
||||
@@ -159,8 +159,7 @@ export default function CommentBlock(props: CommentBlockProps) {
|
||||
|
||||
const isAnonymous = () => props.privilegeLevel === "anonymous";
|
||||
|
||||
const replyIconColor = () =>
|
||||
location.pathname.split("/")[1] === "blog" ? "#fb923c" : "#60a5fa";
|
||||
const replyIconColor = () => "#fb923c";
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -344,7 +343,6 @@ export default function CommentBlock(props: CommentBlockProps) {
|
||||
isReply={true}
|
||||
privilegeLevel={props.privilegeLevel}
|
||||
parent_id={props.comment.id}
|
||||
type={props.category}
|
||||
post_id={props.projectID}
|
||||
currentUserID={props.currentUserID}
|
||||
socket={props.socket}
|
||||
@@ -360,7 +358,6 @@ export default function CommentBlock(props: CommentBlockProps) {
|
||||
{(childComment) => (
|
||||
<CommentBlock
|
||||
comment={childComment}
|
||||
category={props.category}
|
||||
projectID={props.projectID}
|
||||
recursionCount={1}
|
||||
allComments={props.allComments}
|
||||
|
||||
@@ -23,9 +23,7 @@ export default function CommentInputBlock(props: CommentInputBlockProps) {
|
||||
<div class="flex w-full justify-center select-none">
|
||||
<div class="h-fit w-3/4 md:w-1/2">
|
||||
<form onSubmit={newCommentWrapper}>
|
||||
<div
|
||||
class={`textarea-group ${props.type === "blog" ? "blog" : ""}`}
|
||||
>
|
||||
<div class="textarea-group blog">
|
||||
<textarea
|
||||
ref={bodyRef}
|
||||
required
|
||||
@@ -46,9 +44,7 @@ export default function CommentInputBlock(props: CommentInputBlockProps) {
|
||||
class={`${
|
||||
props.commentSubmitLoading
|
||||
? "bg-zinc-400"
|
||||
: props.type === "project"
|
||||
? "border-blue-500 bg-blue-400 hover:bg-blue-500 dark:border-blue-700 dark:bg-blue-700 dark:hover:bg-blue-800"
|
||||
: "border-orange-500 bg-orange-400 hover:bg-orange-500"
|
||||
: "border-orange-500 bg-orange-400 hover:bg-orange-500"
|
||||
} rounded border px-4 py-2 font-light text-white shadow-md transition-all duration-300 ease-in-out active:scale-90`}
|
||||
>
|
||||
Submit
|
||||
@@ -61,7 +57,7 @@ export default function CommentInputBlock(props: CommentInputBlockProps) {
|
||||
} else {
|
||||
return (
|
||||
<div class="flex w-full justify-center">
|
||||
<div class={`textarea-group ${props.type === "blog" ? "blog" : ""}`}>
|
||||
<div class="textarea-group blog">
|
||||
<textarea
|
||||
required
|
||||
disabled
|
||||
|
||||
@@ -5,7 +5,6 @@ import type {
|
||||
UserPublicData,
|
||||
ReactionType,
|
||||
ModificationType,
|
||||
PostType,
|
||||
PrivilegeLevel,
|
||||
SortingMode
|
||||
} from "~/types/comment";
|
||||
@@ -24,7 +23,6 @@ interface CommentSectionProps {
|
||||
privilegeLevel: PrivilegeLevel;
|
||||
allComments: Comment[];
|
||||
topLevelComments: Comment[];
|
||||
type: PostType;
|
||||
postID: number;
|
||||
reactionMap: Map<number, CommentReaction[]>;
|
||||
currentUserID: string;
|
||||
@@ -66,7 +64,6 @@ export default function CommentSection(props: CommentSectionProps) {
|
||||
<CommentInputBlock
|
||||
isReply={false}
|
||||
privilegeLevel={props.privilegeLevel}
|
||||
type={props.type}
|
||||
post_id={props.postID}
|
||||
socket={undefined}
|
||||
currentUserID={props.currentUserID}
|
||||
@@ -91,7 +88,6 @@ export default function CommentSection(props: CommentSectionProps) {
|
||||
<CommentSorting
|
||||
topLevelComments={props.topLevelComments}
|
||||
privilegeLevel={props.privilegeLevel}
|
||||
type={props.type}
|
||||
postID={props.postID}
|
||||
allComments={props.allComments}
|
||||
reactionMap={props.reactionMap}
|
||||
|
||||
@@ -134,7 +134,7 @@ export default function CommentSectionWrapper(
|
||||
socket.send(
|
||||
JSON.stringify({
|
||||
action: "channelUpdate",
|
||||
postType: props.type,
|
||||
postType: "blog",
|
||||
postID: props.id,
|
||||
invoker_id: props.currentUserID
|
||||
})
|
||||
@@ -150,7 +150,7 @@ export default function CommentSectionWrapper(
|
||||
JSON.stringify({
|
||||
action: "commentCreation",
|
||||
commentBody: commentBody,
|
||||
postType: props.type,
|
||||
postType: "blog",
|
||||
postID: props.id,
|
||||
parentCommentID: parentCommentID,
|
||||
invokerID: props.currentUserID
|
||||
@@ -160,7 +160,7 @@ export default function CommentSectionWrapper(
|
||||
// Fallback to HTTP API if WebSocket unavailable
|
||||
const domain = import.meta.env.VITE_DOMAIN;
|
||||
const res = await fetch(
|
||||
`${domain}/api/database/comments/create/${props.type}/${props.id}`,
|
||||
`${domain}/api/database/comments/create/blog/${props.id}`,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
@@ -242,7 +242,7 @@ export default function CommentSectionWrapper(
|
||||
JSON.stringify({
|
||||
action: "commentUpdate",
|
||||
commentBody: body,
|
||||
postType: props.type,
|
||||
postType: "blog",
|
||||
postID: props.id,
|
||||
commentID: comment_id,
|
||||
invokerID: props.currentUserID
|
||||
@@ -297,7 +297,7 @@ export default function CommentSectionWrapper(
|
||||
deleteType: deletionType,
|
||||
commentID: commentID,
|
||||
invokerID: props.currentUserID,
|
||||
postType: props.type,
|
||||
postType: "blog",
|
||||
postID: props.id
|
||||
})
|
||||
);
|
||||
@@ -397,7 +397,7 @@ export default function CommentSectionWrapper(
|
||||
socket.send(
|
||||
JSON.stringify({
|
||||
action: "commentReaction",
|
||||
postType: props.type,
|
||||
postType: "blog",
|
||||
postID: props.id,
|
||||
commentID: commentID,
|
||||
invokerID: props.currentUserID,
|
||||
@@ -511,7 +511,6 @@ export default function CommentSectionWrapper(
|
||||
privilegeLevel={props.privilegeLevel}
|
||||
allComments={allComments()}
|
||||
topLevelComments={topLevelComments()}
|
||||
type={props.type}
|
||||
postID={props.id}
|
||||
reactionMap={currentReactionMap()}
|
||||
currentUserID={props.currentUserID}
|
||||
|
||||
@@ -57,7 +57,6 @@ export default function CommentSorting(props: CommentSortingProps) {
|
||||
>
|
||||
<CommentBlock
|
||||
comment={topLevelComment}
|
||||
category={props.type}
|
||||
projectID={props.postID}
|
||||
recursionCount={1}
|
||||
allComments={props.allComments}
|
||||
|
||||
32
src/components/blog/PostBodyClient.tsx
Normal file
32
src/components/blog/PostBodyClient.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import { createEffect, onMount } from "solid-js";
|
||||
import hljs from "highlight.js";
|
||||
import "highlight.js/styles/github-dark.css";
|
||||
|
||||
export interface PostBodyClientProps {
|
||||
body: string;
|
||||
hasCodeBlock: boolean;
|
||||
}
|
||||
|
||||
export default function PostBodyClient(props: PostBodyClientProps) {
|
||||
let contentRef: HTMLDivElement | undefined;
|
||||
|
||||
// Apply syntax highlighting when component mounts and when body changes
|
||||
createEffect(() => {
|
||||
if (props.hasCodeBlock && contentRef) {
|
||||
// Small delay to ensure DOM is ready
|
||||
setTimeout(() => {
|
||||
hljs.highlightAll();
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div class="mx-auto max-w-4xl px-4 pt-32 md:pt-40">
|
||||
<div
|
||||
ref={contentRef}
|
||||
class="prose dark:prose-invert max-w-none"
|
||||
innerHTML={props.body}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -11,7 +11,6 @@ export interface PostSortingProps {
|
||||
posts: Post[];
|
||||
tags: Tag[];
|
||||
privilegeLevel: "anonymous" | "admin" | "user";
|
||||
type: "blog" | "project";
|
||||
filters?: string;
|
||||
sort?: string;
|
||||
}
|
||||
@@ -35,12 +34,12 @@ export default function PostSorting(props: PostSortingProps) {
|
||||
|
||||
const sortedPosts = () => {
|
||||
const posts = filteredPosts();
|
||||
|
||||
|
||||
switch (props.sort) {
|
||||
case "newest":
|
||||
return [...posts].reverse();
|
||||
case "oldest":
|
||||
return [...posts];
|
||||
case "oldest":
|
||||
return [...posts].reverse();
|
||||
case "most liked":
|
||||
return [...posts].sort((a, b) => b.total_likes - a.total_likes);
|
||||
case "most read":
|
||||
@@ -56,7 +55,7 @@ export default function PostSorting(props: PostSortingProps) {
|
||||
<Show
|
||||
when={!(props.posts.length > 0 && filteredPosts().length === 0)}
|
||||
fallback={
|
||||
<div class="pt-12 text-center text-2xl italic tracking-wide">
|
||||
<div class="pt-12 text-center text-2xl tracking-wide italic">
|
||||
All posts filtered out!
|
||||
</div>
|
||||
}
|
||||
@@ -64,11 +63,7 @@ export default function PostSorting(props: PostSortingProps) {
|
||||
<For each={sortedPosts()}>
|
||||
{(post) => (
|
||||
<div class="my-4">
|
||||
<Card
|
||||
post={post}
|
||||
privilegeLevel={props.privilegeLevel}
|
||||
linkTarget={props.type}
|
||||
/>
|
||||
<Card post={post} privilegeLevel={props.privilegeLevel} />
|
||||
</div>
|
||||
)}
|
||||
</For>
|
||||
|
||||
@@ -11,9 +11,7 @@ const sorting = [
|
||||
{ val: "Most Comments" }
|
||||
];
|
||||
|
||||
export interface PostSortingSelectProps {
|
||||
type: "blog" | "project";
|
||||
}
|
||||
export interface PostSortingSelectProps {}
|
||||
|
||||
export default function PostSortingSelect(props: PostSortingSelectProps) {
|
||||
const [selected, setSelected] = createSignal(sorting[0]);
|
||||
@@ -42,11 +40,7 @@ export default function PostSortingSelect(props: PostSortingSelectProps) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsOpen(!isOpen())}
|
||||
class={`${
|
||||
props.type === "project"
|
||||
? "focus-visible:border-blue focus-visible:ring-offset-blue"
|
||||
: "focus-visible:border-peach focus-visible:ring-offset-peach"
|
||||
} bg-surface0 focus-visible:ring-opacity-75 relative w-full cursor-default rounded-lg py-2 pr-10 pl-3 text-left shadow-md focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 sm:text-sm`}
|
||||
class="focus-visible:border-peach focus-visible:ring-offset-peach bg-surface0 focus-visible:ring-opacity-75 relative w-full cursor-default rounded-lg py-2 pr-10 pl-3 text-left shadow-md focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 sm:text-sm"
|
||||
>
|
||||
<span class="block truncate">{selected().val}</span>
|
||||
<span class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
@@ -68,9 +62,7 @@ export default function PostSortingSelect(props: PostSortingSelectProps) {
|
||||
onClick={() => handleSelect(sort)}
|
||||
class={`relative w-full cursor-default py-2 pr-4 pl-10 text-left select-none ${
|
||||
selected().val === sort.val
|
||||
? props.type === "project"
|
||||
? "bg-blue text-base brightness-75"
|
||||
: "bg-peach text-base brightness-75"
|
||||
? "bg-peach text-base brightness-75"
|
||||
: "text-text hover:brightness-125"
|
||||
}`}
|
||||
>
|
||||
@@ -82,11 +74,7 @@ export default function PostSortingSelect(props: PostSortingSelectProps) {
|
||||
{sort.val}
|
||||
</span>
|
||||
<Show when={selected().val === sort.val}>
|
||||
<span
|
||||
class={`${
|
||||
props.type === "project" ? "text-blue" : "text-peach"
|
||||
} absolute inset-y-0 left-0 flex items-center pl-3`}
|
||||
>
|
||||
<span class="text-peach absolute inset-y-0 left-0 flex items-center pl-3">
|
||||
<Check
|
||||
strokeWidth={1}
|
||||
height={24}
|
||||
|
||||
@@ -12,7 +12,6 @@ export interface SessionDependantLikeProps {
|
||||
currentUserID: string | undefined | null;
|
||||
privilegeLevel: "admin" | "user" | "anonymous";
|
||||
likes: PostLike[];
|
||||
type: "blog" | "project";
|
||||
projectID: number;
|
||||
}
|
||||
|
||||
@@ -59,13 +58,11 @@ export default function SessionDependantLike(props: SessionDependantLikeProps) {
|
||||
|
||||
const getLikeIconColor = () => {
|
||||
if (hasLiked()) {
|
||||
return props.type === "project" ? "fill-blue-400" : "fill-orange-400";
|
||||
return "fill-orange-400";
|
||||
}
|
||||
|
||||
if (hovering()) {
|
||||
return props.type === "project"
|
||||
? "fill-blue-400 dark:fill-blue-600"
|
||||
: "fill-orange-400 dark:fill-orange-500";
|
||||
return "fill-orange-400 dark:fill-orange-500";
|
||||
}
|
||||
|
||||
return "fill-black dark:fill-white";
|
||||
@@ -96,13 +93,7 @@ export default function SessionDependantLike(props: SessionDependantLikeProps) {
|
||||
onMouseOver={() => setHovering(true)}
|
||||
onMouseLeave={() => setHovering(false)}
|
||||
>
|
||||
<div
|
||||
class={`${
|
||||
props.type === "project"
|
||||
? "hover:text-blue-400"
|
||||
: "hover:text-orange-400"
|
||||
} tooltip flex flex-col text-black dark:text-white`}
|
||||
>
|
||||
<div class="hover:text-orange-400 tooltip flex flex-col text-black dark:text-white">
|
||||
<div class="mx-auto">
|
||||
<LikeIcon
|
||||
strokeWidth={1}
|
||||
@@ -113,11 +104,7 @@ export default function SessionDependantLike(props: SessionDependantLikeProps) {
|
||||
</div>
|
||||
<div
|
||||
class={`${
|
||||
hasLiked()
|
||||
? props.type === "project"
|
||||
? "text-blue-400"
|
||||
: "text-orange-400"
|
||||
: ""
|
||||
hasLiked() ? "text-orange-400" : ""
|
||||
} mx-auto flex pl-2 transition-colors duration-200 ease-in`}
|
||||
>
|
||||
{likeCount()} {likeCount() === 1 ? "Like" : "Likes"}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { useNavigate, useLocation, useSearchParams } from "@solidjs/router";
|
||||
|
||||
export interface TagSelectorProps {
|
||||
tagMap: Record<string, number>;
|
||||
category: "blog" | "project";
|
||||
}
|
||||
|
||||
export default function TagSelector(props: TagSelectorProps) {
|
||||
@@ -72,11 +71,7 @@ export default function TagSelector(props: TagSelectorProps) {
|
||||
ref={buttonRef}
|
||||
type="button"
|
||||
onClick={toggleMenu}
|
||||
class={`${
|
||||
props.category === "project"
|
||||
? "border-blue bg-blue hover:brightness-125"
|
||||
: "border-peach bg-peach hover:brightness-125"
|
||||
} mt-2 rounded border px-4 py-2 text-base font-light shadow-md transition-all duration-300 ease-in-out active:scale-90 md:mt-0`}
|
||||
class="border-blue bg-lavender mt-2 rounded border px-4 py-2 text-base font-light shadow-md transition-all duration-300 ease-in-out hover:brightness-125 active:scale-90 md:mt-0"
|
||||
>
|
||||
Filters
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user