@ecohouse/ui 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecohouse/ui",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "Cross-platform presentation-only UI components for EcoHouse (React Native + React Native Web)",
@@ -0,0 +1,31 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { CommentCard } from "./CommentCard";
3
+
4
+ const meta = {
5
+ title: "Components/Comment Card",
6
+ component: CommentCard,
7
+ args: {
8
+ userName: "Աննա Սարգսյան",
9
+ date: "Հուլիս 2026",
10
+ commentText:
11
+ "Աննկարագրելի գեղեցիկ և հանգիստ վայր։ QR-ով մուտքն անչափ հարմար էր, իսկ քոթեջի ներսում ամեն ինչ մտածված էր մինչև ամենափոքր մանրուքը։",
12
+ rating: 4,
13
+ imageUrl: "https://i.pravatar.cc/150?img=47",
14
+ },
15
+ parameters: {
16
+ backgrounds: { default: "black" },
17
+ },
18
+ } satisfies Meta<typeof CommentCard>;
19
+
20
+ export default meta;
21
+ type Story = StoryObj<typeof meta>;
22
+
23
+ export const Default: Story = {};
24
+
25
+ export const WithoutImage: Story = {
26
+ args: { imageUrl: undefined },
27
+ };
28
+
29
+ export const ShortComment: Story = {
30
+ args: { commentText: "Հիանալի վայր և սպասարկում։" },
31
+ };
@@ -0,0 +1,209 @@
1
+ import { forwardRef, useEffect, useMemo, useRef, useState, type ComponentRef } from "react";
2
+ import {
3
+ Image,
4
+ Pressable,
5
+ StyleSheet,
6
+ Text,
7
+ View,
8
+ type StyleProp,
9
+ type TextStyle,
10
+ type ViewProps,
11
+ type ViewStyle,
12
+ } from "react-native";
13
+ import { UserIcon } from "../../icons";
14
+ import { colors, commentCardTypography } from "../../theme";
15
+ import { mergeRefs } from "../../utils/mergeRefs";
16
+ import { useApplyWebClassName } from "../../utils/useApplyWebClassName";
17
+ import { RatingInput } from "../RatingInput";
18
+
19
+ export interface CommentCardProps extends Omit<ViewProps, "style" | "children"> {
20
+ userName: string;
21
+ date: string;
22
+ commentText: string;
23
+ rating: number;
24
+ imageUrl?: string | null;
25
+ maxCommentLines?: number;
26
+ maxCommentLength?: number;
27
+ readMoreLabel?: string;
28
+ readLessLabel?: string;
29
+ onExpandedChange?: (expanded: boolean) => void;
30
+ style?: StyleProp<ViewStyle>;
31
+ commentStyle?: StyleProp<TextStyle>;
32
+ className?: string;
33
+ }
34
+
35
+ const CARD_WIDTH = 370;
36
+ const CARD_MIN_HEIGHT = 173;
37
+ const AVATAR_SIZE = 44;
38
+
39
+ export const CommentCard = forwardRef<ComponentRef<typeof View>, CommentCardProps>(
40
+ function CommentCard(
41
+ {
42
+ userName,
43
+ date,
44
+ commentText,
45
+ rating,
46
+ imageUrl,
47
+ maxCommentLines = 3,
48
+ maxCommentLength = 111,
49
+ readMoreLabel = "Դիտել ավելին",
50
+ readLessLabel = "Փակել",
51
+ onExpandedChange,
52
+ style,
53
+ commentStyle,
54
+ className,
55
+ ...rest
56
+ },
57
+ forwardedRef,
58
+ ) {
59
+ const containerRef = useRef<ComponentRef<typeof View>>(null);
60
+ const setContainerRef = useMemo(() => mergeRefs(containerRef, forwardedRef), [forwardedRef]);
61
+ const [imageFailed, setImageFailed] = useState(false);
62
+ const [expanded, setExpanded] = useState(false);
63
+ const [actionHovered, setActionHovered] = useState(false);
64
+ const hasImage = Boolean(imageUrl) && !imageFailed;
65
+ const shouldShowAction = Array.from(commentText).length >= maxCommentLength;
66
+
67
+ useApplyWebClassName(containerRef, className);
68
+
69
+ useEffect(() => {
70
+ setImageFailed(false);
71
+ }, [imageUrl]);
72
+
73
+ useEffect(() => {
74
+ setExpanded(false);
75
+ setActionHovered(false);
76
+ }, [commentText, maxCommentLength, maxCommentLines]);
77
+
78
+ const toggleExpanded = () => {
79
+ const next = !expanded;
80
+ setExpanded(next);
81
+ onExpandedChange?.(next);
82
+ };
83
+
84
+ return (
85
+ <View {...rest} ref={setContainerRef} style={[styles.root, style]}>
86
+ <View style={styles.header}>
87
+ <View style={styles.avatar}>
88
+ {hasImage ? (
89
+ <Image
90
+ source={{ uri: imageUrl ?? undefined }}
91
+ style={styles.avatarImage}
92
+ onError={() => setImageFailed(true)}
93
+ />
94
+ ) : (
95
+ <UserIcon size={20} color={colors.primary} />
96
+ )}
97
+ </View>
98
+
99
+ <View style={styles.identity}>
100
+ <Text numberOfLines={1} style={styles.name}>
101
+ {userName}
102
+ </Text>
103
+ <Text numberOfLines={1} style={styles.date}>
104
+ {date}
105
+ </Text>
106
+ </View>
107
+
108
+ <RatingInput value={rating} readOnly showValue={false} size={16} />
109
+ </View>
110
+
111
+ <Text
112
+ numberOfLines={expanded ? undefined : maxCommentLines}
113
+ style={[styles.comment, commentStyle]}
114
+ >
115
+ {commentText}
116
+ </Text>
117
+
118
+ {shouldShowAction ? (
119
+ <Pressable
120
+ onPress={toggleExpanded}
121
+ accessibilityRole="button"
122
+ accessibilityState={{ expanded }}
123
+ hitSlop={6}
124
+ onHoverIn={() => setActionHovered(true)}
125
+ onHoverOut={() => setActionHovered(false)}
126
+ style={styles.action}
127
+ >
128
+ <Text
129
+ style={[
130
+ styles.actionText,
131
+ expanded && styles.closeActionText,
132
+ actionHovered &&
133
+ (expanded ? styles.closeActionTextHovered : styles.openActionTextHovered),
134
+ ]}
135
+ >
136
+ {expanded ? readLessLabel : readMoreLabel}
137
+ </Text>
138
+ </Pressable>
139
+ ) : null}
140
+ </View>
141
+ );
142
+ },
143
+ );
144
+
145
+ const styles = StyleSheet.create({
146
+ root: {
147
+ width: CARD_WIDTH,
148
+ minHeight: CARD_MIN_HEIGHT,
149
+ padding: 16,
150
+ gap: 12,
151
+ borderRadius: 12,
152
+ backgroundColor: colors.grey750,
153
+ },
154
+ header: {
155
+ flexDirection: "row",
156
+ alignItems: "center",
157
+ gap: 8,
158
+ },
159
+ avatar: {
160
+ width: AVATAR_SIZE,
161
+ height: AVATAR_SIZE,
162
+ flexShrink: 0,
163
+ alignItems: "center",
164
+ justifyContent: "center",
165
+ overflow: "hidden",
166
+ borderRadius: AVATAR_SIZE / 2,
167
+ backgroundColor: colors.grey600,
168
+ },
169
+ avatarImage: {
170
+ width: AVATAR_SIZE,
171
+ height: AVATAR_SIZE,
172
+ },
173
+ identity: {
174
+ minWidth: 0,
175
+ flex: 1,
176
+ gap: 4,
177
+ },
178
+ name: {
179
+ ...commentCardTypography.name,
180
+ color: colors.white,
181
+ },
182
+ date: {
183
+ ...commentCardTypography.date,
184
+ color: colors.grey0,
185
+ },
186
+ comment: {
187
+ ...commentCardTypography.comment,
188
+ color: colors.white,
189
+ },
190
+ action: {
191
+ alignSelf: "flex-start",
192
+ marginTop: "auto",
193
+ minHeight: 16,
194
+ justifyContent: "center",
195
+ },
196
+ actionText: {
197
+ ...commentCardTypography.action,
198
+ color: colors.white,
199
+ },
200
+ closeActionText: {
201
+ color: colors.primary,
202
+ },
203
+ openActionTextHovered: {
204
+ color: colors.primary,
205
+ },
206
+ closeActionTextHovered: {
207
+ color: colors.white,
208
+ },
209
+ });
@@ -0,0 +1,2 @@
1
+ export { CommentCard } from "./CommentCard";
2
+ export type { CommentCardProps } from "./CommentCard";
@@ -0,0 +1,41 @@
1
+ import { useState } from "react";
2
+ import type { Meta, StoryObj } from "@storybook/react-vite";
3
+ import { RatingInput } from "./RatingInput";
4
+
5
+ const meta = {
6
+ title: "Components/Rating Input",
7
+ component: RatingInput,
8
+ args: {
9
+ defaultValue: 5,
10
+ showValue: true,
11
+ disabled: false,
12
+ },
13
+ argTypes: {
14
+ onValueChange: { action: "valueChange" },
15
+ },
16
+ parameters: {
17
+ backgrounds: { default: "black" },
18
+ },
19
+ } satisfies Meta<typeof RatingInput>;
20
+
21
+ export default meta;
22
+ type Story = StoryObj<typeof meta>;
23
+
24
+ export const WithValue: Story = {};
25
+
26
+ export const WithoutValue: Story = {
27
+ args: { showValue: false },
28
+ };
29
+
30
+ export const ReadOnly: Story = {
31
+ args: { defaultValue: 4, readOnly: true },
32
+ };
33
+
34
+ function ControlledRatingInput() {
35
+ const [value, setValue] = useState(3);
36
+ return <RatingInput value={value} onValueChange={setValue} />;
37
+ }
38
+
39
+ export const Controlled: Story = {
40
+ render: () => <ControlledRatingInput />,
41
+ };
@@ -0,0 +1,168 @@
1
+ import { forwardRef, useMemo, useRef, useState, type ComponentRef } from "react";
2
+ import {
3
+ Pressable,
4
+ StyleSheet,
5
+ Text,
6
+ View,
7
+ type PressableProps,
8
+ type StyleProp,
9
+ type TextStyle,
10
+ type ViewProps,
11
+ type ViewStyle,
12
+ } from "react-native";
13
+ import { StarFilledIcon, StarIcon } from "../../icons";
14
+ import { colors, ratingTypography } from "../../theme";
15
+ import { mergeRefs } from "../../utils/mergeRefs";
16
+ import { useApplyWebClassName } from "../../utils/useApplyWebClassName";
17
+
18
+ const STAR_COUNT = 5;
19
+ const BASE_ITEM_SIZE = 16;
20
+ const ICON_WIDTH_RATIO = 12.57 / BASE_ITEM_SIZE;
21
+ const ICON_HEIGHT_RATIO = 11.98 / BASE_ITEM_SIZE;
22
+ const STAR_GAP_RATIO = 2 / BASE_ITEM_SIZE;
23
+
24
+ export interface RatingInputProps extends Omit<ViewProps, "style" | "children"> {
25
+ value?: number;
26
+ defaultValue?: number;
27
+ onValueChange?: (value: number) => void;
28
+ showValue?: boolean;
29
+ precision?: number;
30
+ /** Star item size. Glyph dimensions and default spacing scale with it. */
31
+ size?: number;
32
+ /** Overrides the proportional spacing between star items. */
33
+ starGap?: number;
34
+ readOnly?: boolean;
35
+ disabled?: boolean;
36
+ style?: StyleProp<ViewStyle>;
37
+ valueStyle?: StyleProp<TextStyle>;
38
+ className?: string;
39
+ hitSlop?: PressableProps["hitSlop"];
40
+ accessibilityLabel?: string;
41
+ }
42
+
43
+ function clamp(value: number) {
44
+ return Math.max(0, Math.min(value, STAR_COUNT));
45
+ }
46
+
47
+ export const RatingInput = forwardRef<ComponentRef<typeof View>, RatingInputProps>(
48
+ function RatingInput(
49
+ {
50
+ value,
51
+ defaultValue = 0,
52
+ onValueChange,
53
+ showValue = true,
54
+ precision = 1,
55
+ size = 20,
56
+ starGap,
57
+ readOnly = false,
58
+ disabled = false,
59
+ style,
60
+ valueStyle,
61
+ className,
62
+ hitSlop = 6,
63
+ accessibilityLabel,
64
+ ...rest
65
+ },
66
+ forwardedRef,
67
+ ) {
68
+ const containerRef = useRef<ComponentRef<typeof View>>(null);
69
+ const setContainerRef = useMemo(() => mergeRefs(containerRef, forwardedRef), [forwardedRef]);
70
+ const isControlled = value !== undefined;
71
+ const [uncontrolledValue, setUncontrolledValue] = useState(() => clamp(defaultValue));
72
+ const selectedValue = clamp(isControlled ? value : uncontrolledValue);
73
+ const selectedStarCount = Math.round(selectedValue);
74
+ const iconWidth = size * ICON_WIDTH_RATIO;
75
+ const iconHeight = size * ICON_HEIGHT_RATIO;
76
+ const resolvedStarGap = starGap ?? size * STAR_GAP_RATIO;
77
+ const resolvedAccessibilityLabel =
78
+ accessibilityLabel ?? (readOnly ? `${selectedValue} out of ${STAR_COUNT} stars` : "Rating");
79
+
80
+ useApplyWebClassName(containerRef, className);
81
+
82
+ const selectValue = (nextValue: number) => {
83
+ if (disabled || nextValue === selectedValue) return;
84
+ if (!isControlled) setUncontrolledValue(nextValue);
85
+ onValueChange?.(nextValue);
86
+ };
87
+
88
+ return (
89
+ <View
90
+ {...rest}
91
+ ref={setContainerRef}
92
+ style={[styles.root, disabled && styles.disabled, style]}
93
+ >
94
+ {showValue ? (
95
+ <Text numberOfLines={1} style={[styles.value, valueStyle]}>
96
+ {selectedValue.toFixed(precision)}
97
+ </Text>
98
+ ) : null}
99
+
100
+ <View
101
+ accessibilityRole={readOnly ? "image" : "radiogroup"}
102
+ accessibilityLabel={resolvedAccessibilityLabel}
103
+ accessibilityState={{ disabled }}
104
+ style={[styles.stars, { gap: resolvedStarGap }]}
105
+ >
106
+ {Array.from({ length: STAR_COUNT }, (_, index) => {
107
+ const starValue = index + 1;
108
+ const isSelected = starValue <= selectedStarCount;
109
+ const icon = isSelected ? (
110
+ <StarFilledIcon size={iconWidth} height={iconHeight} />
111
+ ) : (
112
+ <StarIcon size={iconWidth} height={iconHeight} />
113
+ );
114
+ const itemStyle = [styles.starItem, { width: size, height: size }];
115
+
116
+ if (readOnly) {
117
+ return (
118
+ <View key={starValue} style={itemStyle}>
119
+ {icon}
120
+ </View>
121
+ );
122
+ }
123
+
124
+ return (
125
+ <Pressable
126
+ key={starValue}
127
+ disabled={disabled}
128
+ hitSlop={hitSlop}
129
+ onPress={() => selectValue(starValue)}
130
+ accessibilityRole="radio"
131
+ accessibilityLabel={`${starValue} star${starValue === 1 ? "" : "s"}`}
132
+ accessibilityState={{ checked: isSelected, disabled }}
133
+ style={itemStyle}
134
+ >
135
+ {icon}
136
+ </Pressable>
137
+ );
138
+ })}
139
+ </View>
140
+ </View>
141
+ );
142
+ },
143
+ );
144
+
145
+ const styles = StyleSheet.create({
146
+ root: {
147
+ flexDirection: "row",
148
+ alignItems: "center",
149
+ flexWrap: "nowrap",
150
+ alignSelf: "flex-start",
151
+ gap: 16,
152
+ },
153
+ stars: {
154
+ flexDirection: "row",
155
+ alignItems: "center",
156
+ },
157
+ starItem: {
158
+ alignItems: "center",
159
+ justifyContent: "center",
160
+ },
161
+ value: {
162
+ ...ratingTypography,
163
+ color: colors.white,
164
+ },
165
+ disabled: {
166
+ opacity: 0.5,
167
+ },
168
+ });
@@ -0,0 +1,2 @@
1
+ export { RatingInput } from "./RatingInput";
2
+ export type { RatingInputProps } from "./RatingInput";
@@ -38,3 +38,9 @@ export type { TextareaProps } from "./Textarea";
38
38
 
39
39
  export { Toggle } from "./Toggle";
40
40
  export type { ToggleProps } from "./Toggle";
41
+
42
+ export { RatingInput } from "./RatingInput";
43
+ export type { RatingInputProps } from "./RatingInput";
44
+
45
+ export { CommentCard } from "./CommentCard";
46
+ export type { CommentCardProps } from "./CommentCard";
@@ -0,0 +1,35 @@
1
+ import Svg, { Path } from "react-native-svg";
2
+ import { colors } from "../../theme";
3
+ import { STAR_PATH } from "./starPath";
4
+ import type { IconProps } from "../types";
5
+
6
+ export interface StarIconProps extends IconProps {
7
+ active?: boolean;
8
+ height?: number;
9
+ }
10
+
11
+ /** Native — active is solid orange; inactive is a grey outline. */
12
+ export function StarIcon({
13
+ active = false,
14
+ size = 28,
15
+ height,
16
+ color,
17
+ strokeWidth = 2,
18
+ }: StarIconProps) {
19
+ const resolvedColor = color ?? (active ? "#E38E5E" : colors.grey150);
20
+
21
+ return (
22
+ <Svg width={size} height={height ?? (size * 26) / 28} viewBox="0 0 28 26" fill="none">
23
+ <Path
24
+ d={STAR_PATH}
25
+ fill={active ? resolvedColor : "none"}
26
+ stroke={resolvedColor}
27
+ strokeWidth={strokeWidth}
28
+ strokeLinecap="round"
29
+ strokeLinejoin="round"
30
+ />
31
+ </Svg>
32
+ );
33
+ }
34
+
35
+ export { STAR_PATH } from "./starPath";
@@ -0,0 +1,41 @@
1
+ import { colors } from "../../theme";
2
+ import { STAR_PATH } from "./starPath";
3
+ import type { IconProps } from "../types";
4
+
5
+ export interface StarIconProps extends IconProps {
6
+ active?: boolean;
7
+ height?: number;
8
+ }
9
+
10
+ /** Web / Storybook — active is solid orange; inactive is a grey outline. */
11
+ export function StarIcon({
12
+ active = false,
13
+ size = 28,
14
+ height,
15
+ color,
16
+ strokeWidth = 2,
17
+ }: StarIconProps) {
18
+ const resolvedColor = color ?? (active ? "#E38E5E" : colors.grey150);
19
+
20
+ return (
21
+ <svg
22
+ width={size}
23
+ height={height ?? (size * 26) / 28}
24
+ viewBox="0 0 28 26"
25
+ fill="none"
26
+ xmlns="http://www.w3.org/2000/svg"
27
+ aria-hidden
28
+ >
29
+ <path
30
+ d={STAR_PATH}
31
+ fill={active ? resolvedColor : "none"}
32
+ stroke={resolvedColor}
33
+ strokeWidth={strokeWidth}
34
+ strokeLinecap="round"
35
+ strokeLinejoin="round"
36
+ />
37
+ </svg>
38
+ );
39
+ }
40
+
41
+ export { STAR_PATH } from "./starPath";
@@ -0,0 +1,2 @@
1
+ export { StarIcon, STAR_PATH } from "./StarIcon";
2
+ export type { StarIconProps } from "./StarIcon";
@@ -0,0 +1,3 @@
1
+ /** Star icon path — 28×26 viewBox. */
2
+ export const STAR_PATH =
3
+ "M12.6112 2.09824C12.9186 1.47565 13.0722 1.16436 13.2808 1.0649C13.4623 0.978367 13.6732 0.978367 13.8546 1.0649C14.0632 1.16436 14.2169 1.47565 14.5242 2.09824L17.4398 8.00486C17.5305 8.18866 17.5759 8.28056 17.6422 8.35192C17.7009 8.41509 17.7713 8.46628 17.8495 8.50264C17.9378 8.54371 18.0392 8.55854 18.242 8.58818L24.7637 9.54142C25.4505 9.6418 25.7938 9.69199 25.9528 9.85973C26.091 10.0057 26.156 10.2062 26.1297 10.4055C26.0995 10.6346 25.8509 10.8767 25.3537 11.361L20.6363 15.9557C20.4893 16.0989 20.4157 16.1706 20.3683 16.2558C20.3263 16.3312 20.2993 16.4141 20.2889 16.4998C20.2772 16.5966 20.2945 16.6978 20.3292 16.9001L21.4423 23.39C21.5597 24.0745 21.6184 24.4167 21.5081 24.6198C21.4121 24.7965 21.2415 24.9205 21.0438 24.9571C20.8165 24.9992 20.5092 24.8376 19.8945 24.5144L14.0642 21.4483C13.8826 21.3527 13.7917 21.305 13.696 21.2862C13.6113 21.2696 13.5242 21.2696 13.4394 21.2862C13.3437 21.305 13.2529 21.3527 13.0713 21.4483L7.24094 24.5144C6.62626 24.8376 6.31892 24.9992 6.09167 24.9571C5.89395 24.9205 5.72334 24.7965 5.62736 24.6198C5.51704 24.4167 5.57574 24.0745 5.69314 23.39L6.80622 16.9001C6.84092 16.6978 6.85828 16.5966 6.84653 16.4998C6.83614 16.4141 6.80919 16.3312 6.76718 16.2558C6.71974 16.1706 6.64621 16.0989 6.49916 15.9557L1.78179 11.361C1.28459 10.8767 1.03599 10.6346 1.00574 10.4055C0.979423 10.2062 1.04445 10.0057 1.18271 9.85973C1.34162 9.69199 1.685 9.6418 2.37177 9.54142L8.89346 8.58818C9.09627 8.55854 9.19768 8.54371 9.286 8.50264C9.36419 8.46628 9.43459 8.41509 9.49329 8.35192C9.55958 8.28056 9.60495 8.18866 9.69567 8.00486L12.6112 2.09824Z";
@@ -0,0 +1,28 @@
1
+ import Svg, { Path } from "react-native-svg";
2
+ import { STAR_PATH } from "../Star/starPath";
3
+ import type { IconProps } from "../types";
4
+
5
+ interface StarFilledIconProps extends IconProps {
6
+ height?: number;
7
+ }
8
+
9
+ /** Native — supplied solid orange 28×26 star icon. */
10
+ export function StarFilledIcon({
11
+ size = 28,
12
+ height,
13
+ color = "#E38E5E",
14
+ strokeWidth = 2,
15
+ }: StarFilledIconProps) {
16
+ return (
17
+ <Svg width={size} height={height ?? (size * 26) / 28} viewBox="0 0 28 26" fill={color}>
18
+ <Path
19
+ d={STAR_PATH}
20
+ fill={color}
21
+ stroke={color}
22
+ strokeWidth={strokeWidth}
23
+ strokeLinecap="round"
24
+ strokeLinejoin="round"
25
+ />
26
+ </Svg>
27
+ );
28
+ }
@@ -0,0 +1,34 @@
1
+ import { STAR_PATH } from "../Star/starPath";
2
+ import type { IconProps } from "../types";
3
+
4
+ interface StarFilledIconProps extends IconProps {
5
+ height?: number;
6
+ }
7
+
8
+ /** Web / Storybook — supplied solid orange 28×26 star icon. */
9
+ export function StarFilledIcon({
10
+ size = 28,
11
+ height,
12
+ color = "#E38E5E",
13
+ strokeWidth = 2,
14
+ }: StarFilledIconProps) {
15
+ return (
16
+ <svg
17
+ width={size}
18
+ height={height ?? (size * 26) / 28}
19
+ viewBox="0 0 28 26"
20
+ fill={color}
21
+ xmlns="http://www.w3.org/2000/svg"
22
+ aria-hidden
23
+ >
24
+ <path
25
+ d={STAR_PATH}
26
+ fill={color}
27
+ stroke={color}
28
+ strokeWidth={strokeWidth}
29
+ strokeLinecap="round"
30
+ strokeLinejoin="round"
31
+ />
32
+ </svg>
33
+ );
34
+ }
@@ -0,0 +1 @@
1
+ export { StarFilledIcon } from "./StarFilledIcon";
@@ -35,6 +35,9 @@ export { SearchIcon } from "./Search";
35
35
  export { SettingsIcon } from "./Settings";
36
36
  export { ShowIcon } from "./Show";
37
37
  export { SidebarIcon } from "./Sidebar";
38
+ export { StarIcon } from "./Star";
39
+ export { StarFilledIcon } from "./StarFilled";
38
40
  export { UserIcon } from "./User";
39
41
  export { UsersAltIcon } from "./UsersAlt";
40
42
  export { VideoIcon } from "./Video";
43
+ export type { StarIconProps } from "./Star";
@@ -28,6 +28,8 @@ import { SearchIcon } from "./Search";
28
28
  import { SettingsIcon } from "./Settings";
29
29
  import { ShowIcon } from "./Show";
30
30
  import { SidebarIcon } from "./Sidebar";
31
+ import { StarIcon } from "./Star";
32
+ import { StarFilledIcon } from "./StarFilled";
31
33
  import { UserIcon } from "./User";
32
34
  import { UsersAltIcon } from "./UsersAlt";
33
35
  import { VideoIcon } from "./Video";
@@ -64,6 +66,8 @@ export const icons = {
64
66
  settings: SettingsIcon,
65
67
  show: ShowIcon,
66
68
  sidebar: SidebarIcon,
69
+ star: StarIcon,
70
+ starFilled: StarFilledIcon,
67
71
  user: UserIcon,
68
72
  usersAlt: UsersAltIcon,
69
73
  video: VideoIcon,
@@ -86,6 +90,8 @@ export const iconGroups = {
86
90
  "calendar",
87
91
  "calendarOutline",
88
92
  "heart",
93
+ "star",
94
+ "starFilled",
89
95
  "minus",
90
96
  "plus",
91
97
  ],