From 976661c963efb31a9c458f4882876c0c3a90d362 Mon Sep 17 00:00:00 2001 From: Sabda Yagra Date: Fri, 7 Mar 2025 19:32:47 +0700 Subject: [PATCH] add shimmer in all image --- .../(public)/image/detail/[slug]/page.tsx | 27 +++++++++-- app/[locale]/(public)/image/filter/page.tsx | 16 +++++++ .../(public)/indeks/detail/[slug]/page.tsx | 33 +++++++++++-- app/[locale]/(public)/indeks/page.tsx | 23 +++++++-- .../(public)/video/detail/[slug]/page.tsx | 22 +++++++-- .../area-coverage-and-work-units.tsx | 13 ++--- components/landing-page/content-category.tsx | 21 +++++++- components/landing-page/coverage.tsx | 29 ++++++++--- components/landing-page/division.tsx | 29 ++++++++--- components/landing-page/hero.tsx | 30 ++++++++++-- components/landing-page/new-content.tsx | 27 ++++++++++- components/shimmer/page.tsx | 39 +++++++++++++++ components/view-source/view-source.module.css | 48 +++++++++++++++++++ components/view-source/view-source.tsx | 17 +++++++ utils/globals.tsx | 16 +++++++ 15 files changed, 349 insertions(+), 41 deletions(-) create mode 100644 components/shimmer/page.tsx create mode 100644 components/view-source/view-source.module.css create mode 100644 components/view-source/view-source.tsx diff --git a/app/[locale]/(public)/image/detail/[slug]/page.tsx b/app/[locale]/(public)/image/detail/[slug]/page.tsx index 04149204..4062fcf3 100644 --- a/app/[locale]/(public)/image/detail/[slug]/page.tsx +++ b/app/[locale]/(public)/image/detail/[slug]/page.tsx @@ -464,6 +464,23 @@ const DetailInfo = () => { }); }; + const shimmer = (w: number, h: number) => ` + + + + + + + + + + + + `; + + const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str)); + + return ( <>
@@ -477,7 +494,7 @@ const DetailInfo = () => {
) : (
- Main + Main
)} @@ -493,7 +510,7 @@ const DetailInfo = () => {
{detailDataImage?.files?.map((file: any, index: number) => ( setSelectedImage(index)} key={file?.id}> - image-small + image-small ))}
@@ -650,7 +667,7 @@ const DetailInfo = () => { {listSuggestion?.map((data: any) => (
- +

{Number(data.suggestionFrom?.roleId) == 2 || Number(data.suggestionFrom?.roleId) == 3 || Number(data.suggestionFrom?.roleId) == 4 ? "HUMAS POLRI" : data.suggestionFrom?.fullname} @@ -699,7 +716,7 @@ const DetailInfo = () => { ? data.children?.map((child1: any) => (

- +

{" "} @@ -754,7 +771,7 @@ const DetailInfo = () => { ? child1.children?.map((child2: any) => (

- +

{" "} diff --git a/app/[locale]/(public)/image/filter/page.tsx b/app/[locale]/(public)/image/filter/page.tsx index e6b30eac..d1684afb 100644 --- a/app/[locale]/(public)/image/filter/page.tsx +++ b/app/[locale]/(public)/image/filter/page.tsx @@ -367,6 +367,22 @@ const FilterPage = () => { clearTimeout(typingTimer); }; + const shimmer = (w: number, h: number) => ` + + + + + + + + + + + + `; + + const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str)); + return (

{/* Header */} diff --git a/app/[locale]/(public)/indeks/detail/[slug]/page.tsx b/app/[locale]/(public)/indeks/detail/[slug]/page.tsx index a9842038..e3a2a563 100644 --- a/app/[locale]/(public)/indeks/detail/[slug]/page.tsx +++ b/app/[locale]/(public)/indeks/detail/[slug]/page.tsx @@ -152,6 +152,22 @@ const IndeksDetail = () => { console.log(dataId); }; + const shimmer = (w: number, h: number) => ` + + + + + + + + + + + + `; + + const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str)); + return ( <>
@@ -162,7 +178,7 @@ const IndeksDetail = () => {
{/* Gambar Utama */}
- Main + Main
{/* Footer Informasi */}
@@ -196,7 +212,7 @@ const IndeksDetail = () => { {listComments?.map((data: any) => (
- # + #

{Number(data.commentFrom?.roleId) == 2 || Number(data.commentFrom?.roleId) == 3 || Number(data.commentFrom?.roleId) == 4 ? "HUMAS POLRI" : data.commentFrom?.fullname} @@ -234,7 +250,7 @@ const IndeksDetail = () => { ? data.children?.map((child1: any) => (

- # + #

{Number(child1.commentFrom?.roleId) == 2 || Number(child1.commentFrom?.roleId) == 3 || Number(child1.commentFrom?.roleId) == 4 ? "HUMAS POLRI" : child1.commentFrom?.fullname} @@ -274,7 +290,7 @@ const IndeksDetail = () => { ? child1.children?.map((child2: any) => (

- # + #

{Number(child2.commentFrom?.roleId) == 2 || Number(child2.commentFrom?.roleId) == 3 || Number(child2.commentFrom?.roleId) == 4 ? "HUMAS POLRI" : child2.commentFrom?.fullname} @@ -329,7 +345,14 @@ const IndeksDetail = () => { {indexData?.map((relate: any) => ( - +

{relate?.categoryName}

{relate?.title}

diff --git a/app/[locale]/(public)/indeks/page.tsx b/app/[locale]/(public)/indeks/page.tsx index e45c6537..0e0a18f7 100644 --- a/app/[locale]/(public)/indeks/page.tsx +++ b/app/[locale]/(public)/indeks/page.tsx @@ -40,6 +40,23 @@ const Indeks: React.FC = () => { setIndeksData(response?.data?.data?.content); }; + const shimmer = (w: number, h: number) => ` + + + + + + + + + + + + `; + + const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str)); + + return (
{/* Hero Left */} @@ -54,7 +71,7 @@ const Indeks: React.FC = () => { (indeks: any, index: number) => index == count && (
- image + image
{indeks?.categoryName} @@ -92,7 +109,7 @@ const Indeks: React.FC = () => { (indeksRight: any, index: number) => (index == count + 1 || index == count + 2) && (
- image + image
{indeksRight?.categoryName} @@ -149,7 +166,7 @@ const Indeks: React.FC = () => { (indeksBottom: any, index: number) => index < 3 && (
- +

{indeksBottom?.date}

diff --git a/app/[locale]/(public)/video/detail/[slug]/page.tsx b/app/[locale]/(public)/video/detail/[slug]/page.tsx index 21cd37eb..a02a0e84 100644 --- a/app/[locale]/(public)/video/detail/[slug]/page.tsx +++ b/app/[locale]/(public)/video/detail/[slug]/page.tsx @@ -417,6 +417,22 @@ const DetailVideo = () => { } }; + const shimmer = (w: number, h: number) => ` + + + + + + + + + + + + `; + + const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str)); + return ( <>
@@ -596,7 +612,7 @@ const DetailVideo = () => { {listSuggestion?.map((data: any) => (
- +

{Number(data.suggestionFrom?.roleId) == 2 || Number(data.suggestionFrom?.roleId) == 3 || Number(data.suggestionFrom?.roleId) == 4 ? "HUMAS POLRI" : data.suggestionFrom?.fullname} @@ -645,7 +661,7 @@ const DetailVideo = () => { ? data.children?.map((child1: any) => (

- +

{" "} @@ -699,7 +715,7 @@ const DetailVideo = () => { ? child1.children?.map((child2: any) => (

- +

{" "} diff --git a/components/landing-page/area-coverage-and-work-units.tsx b/components/landing-page/area-coverage-and-work-units.tsx index 748a6bae..7d1b26ae 100644 --- a/components/landing-page/area-coverage-and-work-units.tsx +++ b/components/landing-page/area-coverage-and-work-units.tsx @@ -1,9 +1,10 @@ "use client"; import React from "react"; -import { Dialog, DialogClose, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; +import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; import Image from "next/image"; import Coverage from "./coverage"; +import Division from "./division"; const AreaCoverageWorkUnits = () => { return ( @@ -19,7 +20,7 @@ const AreaCoverageWorkUnits = () => { indo

Polda Jajaran

- +

Polda Jajaran

@@ -40,10 +41,10 @@ const AreaCoverageWorkUnits = () => { {/* SATKER */} - indo -

Polda Jajaran

+ polri +

Satuan Kerja Polri

- +

Satuan Kerja Polri

@@ -52,7 +53,7 @@ const AreaCoverageWorkUnits = () => {
- +
diff --git a/components/landing-page/content-category.tsx b/components/landing-page/content-category.tsx index 4d3bd048..100d4ddb 100644 --- a/components/landing-page/content-category.tsx +++ b/components/landing-page/content-category.tsx @@ -33,6 +33,23 @@ const ContentCategory = (props: { group?: string }) => { const [seeAllValue, setSeeAllValue] = useState(false); const pathname = usePathname(); + const shimmer = (w: number, h: number) => ` + + + + + + + + + + + + `; + + const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str)); + + return (
@@ -56,7 +73,7 @@ const ContentCategory = (props: { group?: string }) => { !seeAllValue ? ( index < 4 ? ( - category + category

{category?.name}

@@ -66,7 +83,7 @@ const ContentCategory = (props: { group?: string }) => { ) ) : ( - category + category

{category?.name}

diff --git a/components/landing-page/coverage.tsx b/components/landing-page/coverage.tsx index 93a2027f..72ffc667 100644 --- a/components/landing-page/coverage.tsx +++ b/components/landing-page/coverage.tsx @@ -5,6 +5,7 @@ import { Icon } from "@iconify/react/dist/iconify.js"; import { Link } from "@/i18n/routing"; import { useTranslations } from "next-intl"; import { usePathname } from "next/navigation"; +import Image from "next/image"; const regions = [ { name: "Polda Metro Jaya", slug: "metro-jaya", logo: "/assets/polda/polda-metro.png" }, @@ -59,8 +60,24 @@ const Coverage: React.FC = () => { setFilteredList(filtered); }; + const shimmer = (w: number, h: number) => ` + + + + + + + + + + + +`; + + const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str)); + return ( -
+
{/* Header */} {/*

{pathname?.split("/")[1] == "in" ? ( @@ -91,13 +108,13 @@ const Coverage: React.FC = () => {

*/} {/* Grid Wilayah */} -
+
{filteredList?.map((region: any) => ( - -
- {region.name} + +
+ {region.name}
-

{region.name}

+

{region.name}

))}
diff --git a/components/landing-page/division.tsx b/components/landing-page/division.tsx index f4479d11..0bfdc73d 100644 --- a/components/landing-page/division.tsx +++ b/components/landing-page/division.tsx @@ -5,6 +5,7 @@ import { Icon } from "@iconify/react/dist/iconify.js"; import { Link } from "@/i18n/routing"; import { useTranslations } from "next-intl"; import { usePathname } from "next/navigation"; +import Image from "next/image"; const regions = [ { name: "SIBER", slug: "siber", logo: "/assets/satker/siber.png" }, @@ -62,8 +63,24 @@ const Division = () => { setFilteredList(filtered); }; + const shimmer = (w: number, h: number) => ` + + + + + + + + + + + +`; + + const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str)); + return ( -
+
{/* Header */} {/* */} {/*

@@ -90,13 +107,13 @@ const Division = () => {

*/} {/* Grid Wilayah */} -
+
{filteredList?.map((region: any) => ( - -
- {region.name} + +
+ {region.name}
-

{region.name}

+

{region.name}

))}
diff --git a/components/landing-page/hero.tsx b/components/landing-page/hero.tsx index b23dfcbe..6a09dfd0 100644 --- a/components/landing-page/hero.tsx +++ b/components/landing-page/hero.tsx @@ -1,4 +1,4 @@ -import { formatDateToIndonesian, textEllipsis } from "@/utils/globals"; +import { formatDateToIndonesian, shimmer, toBase64 } from "@/utils/globals"; import React, { useEffect, useState } from "react"; import "swiper/css/bundle"; import "swiper/css/navigation"; @@ -53,6 +53,22 @@ const Hero: React.FC = () => { setHeroData(response?.data?.data?.content); }; + const shimmer = (w: number, h: number) => ` + + + + + + + + + + + +`; + + const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str)); + return (
{/* Section Gambar Utama */} @@ -70,7 +86,15 @@ const Hero: React.FC = () => { {heroData?.map((list: any) => (
- gambar-utama + gambar-utama +
{list?.categoryName} @@ -141,7 +165,7 @@ const Hero: React.FC = () => { {heroData?.map((item: any) => (
  • - {item?.title} + {item?.title}
    {item?.categoryName} diff --git a/components/landing-page/new-content.tsx b/components/landing-page/new-content.tsx index e9d467ce..551c1684 100644 --- a/components/landing-page/new-content.tsx +++ b/components/landing-page/new-content.tsx @@ -54,6 +54,22 @@ const NewContent = (props: { group: string; type: string }) => { setNewContent(response?.data?.data?.content); }; + const shimmer = (w: number, h: number) => ` + + + + + + + + + + + + `; + + const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str)); + return (
    @@ -120,7 +136,14 @@ const NewContent = (props: { group: string; type: string }) => { {newContent?.map((image: any) => (
    router.push(prefixPath + `/image/detail/${image?.slug}`)} className="cursor-pointer relative group overflow-hidden shadow-md hover:shadow-lg"> - image + image

    {image?.title}

    @@ -184,7 +207,7 @@ const NewContent = (props: { group: string; type: string }) => { {newContent?.map((video: any) => (

    router.push(prefixPath + `/video/detail/${video?.slug}`)} className="cursor-pointer relative group rounded-md overflow-hidden shadow-md hover:shadow-lg"> - video + video

    {video?.title}

    diff --git a/components/shimmer/page.tsx b/components/shimmer/page.tsx new file mode 100644 index 00000000..a4e0e0d2 --- /dev/null +++ b/components/shimmer/page.tsx @@ -0,0 +1,39 @@ +import Image from "next/image"; +import ViewSource from "../view-source/view-source"; + + +const shimmer = (w: number, h: number) => ` + + + + + + + + + + + +`; + +const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str)); + +const Shimmer = () => ( +

    + +

    Image Component With Shimmer Data URL

    + Mountains +
    +); + +export default Shimmer; diff --git a/components/view-source/view-source.module.css b/components/view-source/view-source.module.css new file mode 100644 index 00000000..2ec16794 --- /dev/null +++ b/components/view-source/view-source.module.css @@ -0,0 +1,48 @@ +.svg { + position: absolute; + top: 0; + right: 0; +} +.arm { + transform-origin: 130px 106px; +} + +.svg:hover .arm { + animation: wave 560ms ease-in-out; +} + +@keyframes wave { + 0% { + transform: rotate(0deg); + } + + 20% { + transform: rotate(-25deg); + } + + 40% { + transform: rotate(10deg); + } + + 60% { + transform: rotate(-25deg); + } + + 80% { + transform: rotate(10deg); + } + + 100% { + transform: rotate(0deg); + } +} + +@media (max-width: 500px) { + .svg:hover .arm { + animation: none; + } + + .svg:hover .arm { + animation: wave 560ms ease-in-out; + } +} \ No newline at end of file diff --git a/components/view-source/view-source.tsx b/components/view-source/view-source.tsx new file mode 100644 index 00000000..14838de1 --- /dev/null +++ b/components/view-source/view-source.tsx @@ -0,0 +1,17 @@ +import styles from "./view-source.module.css"; + +type ViewSourceProps = { + pathname: string; +}; + +const ViewSource = ({ pathname }: ViewSourceProps) => ( + + + + + + + +); + +export default ViewSource; diff --git a/utils/globals.tsx b/utils/globals.tsx index 6f8deb30..11019f6d 100644 --- a/utils/globals.tsx +++ b/utils/globals.tsx @@ -137,3 +137,19 @@ export function checkMaliciousText(str: any) { return ""; } } + +export const shimmer = (w: number, h: number) => ` + + + + + + + + + + + +`; + +export const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str));