From 9904d54d282be7598af5fbdc32d30cdab25cf258 Mon Sep 17 00:00:00 2001 From: rotemergty5 <153999862+rotemergty5@users.noreply.github.com> Date: Sun, 17 May 2026 02:30:56 +0300 Subject: [PATCH 1/3] Create skeleton card component --- .../UI/Skeleton/SGLContentCardSkeleton.css | 169 ++++++++++++++++++ .../UI/Skeleton/SGLContentCardSkeleton.tsx | 167 +++++++++++++++++ src/components/UI/Skeleton/SGLSkeleton.tsx | 47 +++++ 3 files changed, 383 insertions(+) create mode 100644 src/components/UI/Skeleton/SGLContentCardSkeleton.css create mode 100644 src/components/UI/Skeleton/SGLContentCardSkeleton.tsx create mode 100644 src/components/UI/Skeleton/SGLSkeleton.tsx diff --git a/src/components/UI/Skeleton/SGLContentCardSkeleton.css b/src/components/UI/Skeleton/SGLContentCardSkeleton.css new file mode 100644 index 0000000..edd42da --- /dev/null +++ b/src/components/UI/Skeleton/SGLContentCardSkeleton.css @@ -0,0 +1,169 @@ +.sgl-card-container { + display: flex; + flex-direction: column; + gap: 16px; + + width: 100%; + + overflow-y: auto; + overflow-x: hidden; + + padding-right: 4px; + + box-sizing: border-box; + margin: 10px; +} + +.sgl-header { + display: flex; + align-items: center; + gap: 12px; + + width: 100%; +} + +.sgl-avatar-wrapper { + position: relative; + + width: 40px; + height: 40px; + +} + +.sgl-avatar-image { + position: absolute; + + top: 0; + left: 0; + + width: 40px; + height: 40px; + + border-radius: 50%; + object-fit: cover; + opacity: 1; +} + +.sgl-text-content { + flex: 1; +} + +.sgl-text-wrapper { + position: relative; + width: 'fit-content'; +} + +.sgl-subtitle-wrapper { + margin-top: -11px; +} + +.sgl-overlay-text { + position: absolute; + + top: 50%; + left: 12px; + + transform: translateY(-50%); + + color: white; + + pointer-events: none; + + white-space: nowrap; +} + +.sgl-title { + font-size: 14px; + font-weight: 600; +} + +.sgl-subtitle { + font-size: 12px; +} + +.sgl-image-section { + display: flex; + flex-direction: column; + gap: 8px; + + width: 100%; +} + +.sgl-image-wrapper { + position: relative; + + width: 100%; + height: 180px; + + overflow: hidden; + + border-radius: 16px; +} + +.sgl-image { + position: absolute; + + inset: 0; + + width: 100%; + height: 100%; + + object-fit: cover; + scale: 1.1; +} + +.image-description-wrapper { + position: relative; + width: 100%; + min-height: 32px; + + padding: 8px 12px; + box-sizing: border-box; + + border-radius: 8px; + overflow: hidden; +} + +.image-description-background { + position: absolute; + inset: 0; + + opacity: 0.5; + border-radius: 8px; +} + +.image-description { + position: relative; + + color: #fff; + font-size: 13px; + line-height: 1.4; + + word-break: break-word; + overflow-wrap: anywhere; +} + +.sgl-button-wrapper { + position: relative; + + width: fit-content; + + max-width: 100%; +} + +.sgl-button-text { + position: absolute; + + top: 50%; + left: 50%; + + transform: translate(-50%, -50%); + + color: white; + + font-size: 14px; + + white-space: nowrap; + + pointer-events: none; +} \ No newline at end of file diff --git a/src/components/UI/Skeleton/SGLContentCardSkeleton.tsx b/src/components/UI/Skeleton/SGLContentCardSkeleton.tsx new file mode 100644 index 0000000..0eda8d6 --- /dev/null +++ b/src/components/UI/Skeleton/SGLContentCardSkeleton.tsx @@ -0,0 +1,167 @@ +import Box from '@mui/material/Box' +import Typography from '@mui/material/Typography' +import './SGLContentCardSkeleton.css' +import { SGLSkeleton } from './SGLSkeleton' + +interface SGLContentCardSkeletonProps { + color?: string + avatarSrc?: string + + + title?: string + subtitle?: string + buttonText?: string + + imageSrc?: string + imageDescription?: string + + imageHeight?: number + + showAvatar?: boolean + showButton?: boolean + showImage?: boolean +} + +export const SGLContentCardSkeleton = ({ + color = '#8F3DFF', + avatarSrc = 'https://upload.wikimedia.org/wikipedia/commons/8/89/Portrait_Placeholder.png', + + title = 'Loading title', + subtitle = 'Loading subtitle', + buttonText = 'Loading button', + + imageSrc = 'https://images.unsplash.com/photo-1506744038136-46273834b3fb', + imageDescription = 'Image description', + + imageHeight = 180, + + showAvatar = true, + showButton = true, + showImage = true, +}: SGLContentCardSkeletonProps) => { + return ( + + {/* Header */} + + {showAvatar && ( + + + + {avatarSrc && ( + + )} + + )} + + + {/* Title */} + + + + + {title} + + + + {/* Subtitle */} + + + + + {subtitle} + + + + + + {/* Image */} + {showImage && ( + + + + + {imageSrc && ( + + )} + + + {/* Image Description */} + + + + + {imageDescription} + + + + )} + + + {/* Button */} + {showButton && ( + + + + + {buttonText} + + + )} + + ) +} \ No newline at end of file diff --git a/src/components/UI/Skeleton/SGLSkeleton.tsx b/src/components/UI/Skeleton/SGLSkeleton.tsx new file mode 100644 index 0000000..46d898b --- /dev/null +++ b/src/components/UI/Skeleton/SGLSkeleton.tsx @@ -0,0 +1,47 @@ +import Skeleton, { type SkeletonProps as MuiSkeletonProps } from '@mui/material/Skeleton' +import { type ReactNode } from 'react' +import { type SxProps, type Theme } from '@mui/material/styles' + +interface SGLSkeletonProps extends Omit { + children?: ReactNode + width?: number | string + height?: number | string + textSize?: number | string + skeletonColor?: string + radius?: number | string + opacity?: number + sx?: SxProps +} + +export const SGLSkeleton = ({ + children, + variant = 'text', + animation = 'wave', + width, + height, + textSize = '1rem', + skeletonColor = '#8F3DFF', + radius, + opacity = 1, + sx, + ...props +}: SGLSkeletonProps) => { + return ( + + {children} + + ) +} \ No newline at end of file From fd424d636ba99dd4dfab30ddb67ea885ea44c0d3 Mon Sep 17 00:00:00 2001 From: Rotem Date: Tue, 19 May 2026 18:42:51 +0300 Subject: [PATCH 2/3] Update skeleton component --- .../UI/Skeleton/SGLContentCardSkeleton.css | 169 ------------------ .../UI/Skeleton/SGLContentCardSkeleton.tsx | 167 ----------------- src/components/UI/Skeleton/SGLSkeleton.tsx | 38 ++-- 3 files changed, 10 insertions(+), 364 deletions(-) delete mode 100644 src/components/UI/Skeleton/SGLContentCardSkeleton.css delete mode 100644 src/components/UI/Skeleton/SGLContentCardSkeleton.tsx diff --git a/src/components/UI/Skeleton/SGLContentCardSkeleton.css b/src/components/UI/Skeleton/SGLContentCardSkeleton.css deleted file mode 100644 index edd42da..0000000 --- a/src/components/UI/Skeleton/SGLContentCardSkeleton.css +++ /dev/null @@ -1,169 +0,0 @@ -.sgl-card-container { - display: flex; - flex-direction: column; - gap: 16px; - - width: 100%; - - overflow-y: auto; - overflow-x: hidden; - - padding-right: 4px; - - box-sizing: border-box; - margin: 10px; -} - -.sgl-header { - display: flex; - align-items: center; - gap: 12px; - - width: 100%; -} - -.sgl-avatar-wrapper { - position: relative; - - width: 40px; - height: 40px; - -} - -.sgl-avatar-image { - position: absolute; - - top: 0; - left: 0; - - width: 40px; - height: 40px; - - border-radius: 50%; - object-fit: cover; - opacity: 1; -} - -.sgl-text-content { - flex: 1; -} - -.sgl-text-wrapper { - position: relative; - width: 'fit-content'; -} - -.sgl-subtitle-wrapper { - margin-top: -11px; -} - -.sgl-overlay-text { - position: absolute; - - top: 50%; - left: 12px; - - transform: translateY(-50%); - - color: white; - - pointer-events: none; - - white-space: nowrap; -} - -.sgl-title { - font-size: 14px; - font-weight: 600; -} - -.sgl-subtitle { - font-size: 12px; -} - -.sgl-image-section { - display: flex; - flex-direction: column; - gap: 8px; - - width: 100%; -} - -.sgl-image-wrapper { - position: relative; - - width: 100%; - height: 180px; - - overflow: hidden; - - border-radius: 16px; -} - -.sgl-image { - position: absolute; - - inset: 0; - - width: 100%; - height: 100%; - - object-fit: cover; - scale: 1.1; -} - -.image-description-wrapper { - position: relative; - width: 100%; - min-height: 32px; - - padding: 8px 12px; - box-sizing: border-box; - - border-radius: 8px; - overflow: hidden; -} - -.image-description-background { - position: absolute; - inset: 0; - - opacity: 0.5; - border-radius: 8px; -} - -.image-description { - position: relative; - - color: #fff; - font-size: 13px; - line-height: 1.4; - - word-break: break-word; - overflow-wrap: anywhere; -} - -.sgl-button-wrapper { - position: relative; - - width: fit-content; - - max-width: 100%; -} - -.sgl-button-text { - position: absolute; - - top: 50%; - left: 50%; - - transform: translate(-50%, -50%); - - color: white; - - font-size: 14px; - - white-space: nowrap; - - pointer-events: none; -} \ No newline at end of file diff --git a/src/components/UI/Skeleton/SGLContentCardSkeleton.tsx b/src/components/UI/Skeleton/SGLContentCardSkeleton.tsx deleted file mode 100644 index 0eda8d6..0000000 --- a/src/components/UI/Skeleton/SGLContentCardSkeleton.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import Box from '@mui/material/Box' -import Typography from '@mui/material/Typography' -import './SGLContentCardSkeleton.css' -import { SGLSkeleton } from './SGLSkeleton' - -interface SGLContentCardSkeletonProps { - color?: string - avatarSrc?: string - - - title?: string - subtitle?: string - buttonText?: string - - imageSrc?: string - imageDescription?: string - - imageHeight?: number - - showAvatar?: boolean - showButton?: boolean - showImage?: boolean -} - -export const SGLContentCardSkeleton = ({ - color = '#8F3DFF', - avatarSrc = 'https://upload.wikimedia.org/wikipedia/commons/8/89/Portrait_Placeholder.png', - - title = 'Loading title', - subtitle = 'Loading subtitle', - buttonText = 'Loading button', - - imageSrc = 'https://images.unsplash.com/photo-1506744038136-46273834b3fb', - imageDescription = 'Image description', - - imageHeight = 180, - - showAvatar = true, - showButton = true, - showImage = true, -}: SGLContentCardSkeletonProps) => { - return ( - - {/* Header */} - - {showAvatar && ( - - - - {avatarSrc && ( - - )} - - )} - - - {/* Title */} - - - - - {title} - - - - {/* Subtitle */} - - - - - {subtitle} - - - - - - {/* Image */} - {showImage && ( - - - - - {imageSrc && ( - - )} - - - {/* Image Description */} - - - - - {imageDescription} - - - - )} - - - {/* Button */} - {showButton && ( - - - - - {buttonText} - - - )} - - ) -} \ No newline at end of file diff --git a/src/components/UI/Skeleton/SGLSkeleton.tsx b/src/components/UI/Skeleton/SGLSkeleton.tsx index 46d898b..5b009f7 100644 --- a/src/components/UI/Skeleton/SGLSkeleton.tsx +++ b/src/components/UI/Skeleton/SGLSkeleton.tsx @@ -1,47 +1,29 @@ -import Skeleton, { type SkeletonProps as MuiSkeletonProps } from '@mui/material/Skeleton' -import { type ReactNode } from 'react' -import { type SxProps, type Theme } from '@mui/material/styles' +import Skeleton, { + type SkeletonProps as MuiSkeletonProps, +} from '@mui/material/Skeleton' -interface SGLSkeletonProps extends Omit { - children?: ReactNode - width?: number | string - height?: number | string - textSize?: number | string +import type { SxProps, Theme } from '@mui/material/styles' + +interface SGLSkeletonProps + extends Omit { skeletonColor?: string - radius?: number | string - opacity?: number sx?: SxProps } export const SGLSkeleton = ({ - children, - variant = 'text', - animation = 'wave', - width, - height, - textSize = '1rem', skeletonColor = '#8F3DFF', - radius, - opacity = 1, + animation = 'wave', sx, ...props }: SGLSkeletonProps) => { return ( - {children} - + /> ) } \ No newline at end of file From fdd253b80e33163cdd8cf5494f91435520dd3cdc Mon Sep 17 00:00:00 2001 From: Rotem Date: Tue, 26 May 2026 20:29:41 +0300 Subject: [PATCH 3/3] update skeleton --- src/components/UI/Skeleton/SGLSkeleton.tsx | 20 +++++++++----------- src/components/UI/Skeleton/styles.ts | 12 ++++++++++++ 2 files changed, 21 insertions(+), 11 deletions(-) create mode 100644 src/components/UI/Skeleton/styles.ts diff --git a/src/components/UI/Skeleton/SGLSkeleton.tsx b/src/components/UI/Skeleton/SGLSkeleton.tsx index 5b009f7..a0e49b9 100644 --- a/src/components/UI/Skeleton/SGLSkeleton.tsx +++ b/src/components/UI/Skeleton/SGLSkeleton.tsx @@ -2,26 +2,24 @@ import Skeleton, { type SkeletonProps as MuiSkeletonProps, } from '@mui/material/Skeleton' -import type { SxProps, Theme } from '@mui/material/styles' +import type { CSSProperties } from '@mui/material/styles' +import { skeletonStyles } from './styles' -interface SGLSkeletonProps - extends Omit { - skeletonColor?: string - sx?: SxProps +interface SGLSkeletonProps extends Omit { + style?: CSSProperties } export const SGLSkeleton = ({ - skeletonColor = '#8F3DFF', animation = 'wave', - sx, + style, ...props }: SGLSkeletonProps) => { return ( ({ + ...skeletonStyles(theme), + ...style, + })} animation={animation} {...props} /> diff --git a/src/components/UI/Skeleton/styles.ts b/src/components/UI/Skeleton/styles.ts new file mode 100644 index 0000000..3a68c35 --- /dev/null +++ b/src/components/UI/Skeleton/styles.ts @@ -0,0 +1,12 @@ +import type { Theme } from '@mui/material/styles' + +export const skeletonStyles = (theme: Theme) => { + return { + backgroundColor: theme.palette.lightGrey.main, + opacity: 1, + + '&.MuiSkeleton-wave::after': { + animationDuration: '1.6s', + }, + } +} \ No newline at end of file