This commit is contained in:
2025-07-30 13:10:11 +05:00
parent b01a285bd2
commit fdc2534154
9 changed files with 101 additions and 20 deletions
+4 -1
View File
@@ -14,7 +14,10 @@ export default async function BlogPage() {
await queryClient.prefetchQuery({
queryKey: ["articles"],
queryFn: () => api.get("articles").json<IArticle[]>(),
queryFn: () =>
api
.get("articles", { searchParams: { locale: "ru" } })
.json<IArticle[]>(),
});
return (
+1
View File
@@ -2,6 +2,7 @@ User-agent: *
Disallow: /login
Disallow: /form
Disallow: /policy
Disallow: /privacy-policy
Disallow: /a1
Disallow: /CircularProgressbar-path
+4 -3
View File
@@ -47,7 +47,7 @@ export function Footer() {
<RutubeIcon />
</div>
</ContactLink>
<ContactLink href="https://vk.com/graffinteractive?from=groups">
<ContactLink href="https://vk.com/graff.estate">
<div className="text-white lg:size-[1.389vw] size-[5.556vw] group-hover:text-black">
<VkIcon />
</div>
@@ -88,11 +88,12 @@ export function ContactLink({
className = "",
}: PropsWithChildren<{ href: string; className?: string }>) {
return (
<Link
<a
href={href}
target="_blank"
className={`lg:rounded-[1.111vw] rounded-2xl bg-[#37393B99] lg:p-[1.25vw] p-[18px] hover:bg-white transition-all hover:text-black flex justify-center w-full group ${className}`}
>
{children}
</Link>
</a>
);
}
@@ -28,6 +28,7 @@ export function ArticleContentFormModal({
createdAt,
drafted,
id,
locale,
}: IArticle) {
const { setModal } = useModalStore();
@@ -40,6 +41,7 @@ export function ArticleContentFormModal({
cardImage,
createdAt,
drafted,
locale,
},
});
@@ -84,6 +86,7 @@ export function ArticleContentFormModal({
drafted,
posterImage,
id,
locale,
}}
/>
)
+9 -3
View File
@@ -5,6 +5,7 @@ import { useModalStore } from "@/stores/useModalStore";
import { IArticle } from "@/types/IArticle";
import { CheckboxesGroup } from "@/ui/CheckboxesGroup";
import { TextInput } from "@/ui/TextInput";
import { LocaleSwitch } from "@/ui/LocaleSwitch";
import { FormProvider, useForm, useWatch } from "react-hook-form";
import { ImageUploader } from "../ImageUploader";
// import { ArticleContentFormModal } from "./ArticleContentFormModal";
@@ -39,6 +40,7 @@ export function ArticleFormModal<TAction extends "create" | "edit">({
blocks: [],
tags: [],
drafted: true,
locale: "ru",
},
mode: "onChange",
});
@@ -51,9 +53,9 @@ export function ArticleFormModal<TAction extends "create" | "edit">({
setModal(<ArticleContentFormModal {...article} />);
}
const { handleSubmit, getValues, control } = form;
const { handleSubmit, getValues, control, setValue } = form;
const { title, tags, cardImage, posterImage } = useWatch({ control });
const { title, tags, cardImage, posterImage, locale } = useWatch({ control });
async function handleSave(drafted: boolean) {
await mutateAsync({
@@ -101,7 +103,7 @@ export function ArticleFormModal<TAction extends "create" | "edit">({
name="cardImage"
label="Загрузите или перетащите изображение для превью (рекомендованнный размер 1080/1080 px)"
/>
<div className="gap-y-4 flex flex-col">
<div className="flex flex-col gap-y-4">
<label htmlFor="devices" className="w-fit btnl font-medium">
Выберите категории
</label>
@@ -116,6 +118,10 @@ export function ArticleFormModal<TAction extends "create" | "edit">({
name="posterImage"
label="Загрузите или перетащите изображение для превью (рекомендованнный размер 1080/1080 px)"
/>
<LocaleSwitch
value={locale || "ru"}
onChange={(newLocale) => setValue("locale", newLocale)}
/>
</FormProvider>
</form>
</div>
@@ -16,6 +16,7 @@ export function ArticleCard({
posterImage,
createdAt,
slug,
locale,
className,
}: IArticle & { className?: string }) {
const params = useSearchParams();
@@ -58,6 +59,7 @@ export function ArticleCard({
drafted,
posterImage,
createdAt,
locale,
}}
/>
</div>
+13 -13
View File
@@ -4,7 +4,8 @@ import { queryOptions, useQuery } from '@tanstack/react-query';
export const queryArticlesOptions = {
queryKey: ['articles'],
queryFn: () => api.get('articles').json<IArticle[]>(),
queryFn: () =>
api.get('articles', { searchParams: { locale: "ru" } }).json<IArticle[]>(),
};
export function useGetArticlesQuery(tags?: string | string[]) {
@@ -12,18 +13,17 @@ export function useGetArticlesQuery(tags?: string | string[]) {
queryOptions(
tags && tags.length > 0
? {
queryKey: ['articles', tags],
queryFn: () =>
api
.get(
`articles?${
Array.isArray(tags)
? tags.map((tag) => `tags=${tag}`).join('&')
: 'tags=' + tags
}`
)
.json<IArticle[]>(),
}
queryKey: ['articles', tags],
queryFn: () =>
api
.get(
`articles?${Array.isArray(tags)
? tags.map((tag) => `tags=${tag}`).join('&')
: 'tags=' + tags
}&locale=ru`
)
.json<IArticle[]>(),
}
: queryArticlesOptions
)
);
+1
View File
@@ -44,4 +44,5 @@ export interface IArticle {
drafted: boolean;
slug?: string;
blocks: Block[];
locale: 'ru' | 'en';
}
+64
View File
@@ -0,0 +1,64 @@
import { motion } from "framer-motion";
interface LocaleSwitchProps {
value: "ru" | "en";
onChange: (locale: "ru" | "en") => void;
}
export function LocaleSwitch({ value, onChange }: LocaleSwitchProps) {
const handleToggle = () => {
onChange(value === "ru" ? "en" : "ru");
};
return (
<div className="flex flex-col gap-2">
<label className="text1 font-medium text-white">Язык статьи</label>
<div
className={`
bg-[#37393B99] relative lg:rounded-[0.833vw] rounded-xl
w-[8.333vw] aspect-[12/5] cursor-pointer select-none
transition-opacity duration-200
`}
onClick={handleToggle}
>
<motion.div
className="absolute bg-gradient lg:rounded-[0.556vw] rounded-lg lg:p-[0.556vw] p-2 lg:w-[calc(50%-0.278vw)] w-[calc(50%-4px)] flex items-center justify-center left-[0.278vw] top-1/2"
animate={{
x: value === "ru" ? 0 : "100%",
y: "-50%",
}}
transition={{
type: "spring",
stiffness: 400,
damping: 35,
}}
>
<span className="text1 font-medium text-center text-white">
{value === "ru" ? "RU" : "EN"}
</span>
</motion.div>
<div className="flex absolute inset-0">
<div className="flex flex-1 justify-center items-center">
<span
className={`text1 font-medium transition-colors duration-200 ${
value === "ru" ? "text-transparent" : "text-gray-400"
}`}
>
RU
</span>
</div>
<div className="flex flex-1 justify-center items-center">
<span
className={`text1 font-medium transition-colors duration-200 ${
value === "en" ? "text-transparent" : "text-gray-400"
}`}
>
EN
</span>
</div>
</div>
</div>
</div>
);
}