diff --git a/src-ui/app/config_page/setting_section/setting_box/supporters copy/C_Supporters.jsx b/src-ui/app/config_page/setting_section/setting_box/supporters copy/C_Supporters.jsx
new file mode 100644
index 00000000..1d64b9c5
--- /dev/null
+++ b/src-ui/app/config_page/setting_section/setting_box/supporters copy/C_Supporters.jsx
@@ -0,0 +1,224 @@
+import { useState, useEffect } from "react";
+import styles from "./Supporters.module.scss";
+import clsx from "clsx";
+import { useTranslation } from "react-i18next";
+
+import {
+ useSettingBoxScrollPosition,
+} from "@logics_configs"
+
+const supporter_images = import.meta.glob("@images/supporters/supporters_images/*.{png,jpg,jpeg,svg}", { eager: true });
+const chato_expression_images = import.meta.glob("@images/supporters/chato_expressions/*.{png,jpg,jpeg,svg}", { eager: true });
+import fanbox_img from "@images/supporters/c_fanbox_1620x580.png";
+import vrct_supporters_title from "@images/supporters/vrct_supporters_title.png";
+import fanbox_button from "@images/supporters/fanbox_button.png";
+import kofi_preparing from "@images/supporters/kofi_preparing.png";
+
+import ExternalLink from "@images/external_link.svg?react";
+
+const mogu_count = 8;
+const mochi_count = 3;
+const fuwa_count = 4;
+const basic_count = 5;
+const former_count = 2;
+const and_you_count = 1;
+const default_icon_numbers = ["05", "06", "07", "11"];
+
+const supporters_filenames = Array.from({ length: 23 }, (_, index) => `supporter_${String(index + 1).padStart(2, "0")}`);
+const chato_expressions_filenames = Array.from({ length: 7 }, (_, index) => `chato_expression_${String(index + 1).padStart(2, "0")}`);
+
+const SHUFFLE_INTERVAL_TIME = 20000;
+const shuffleArray = (array) => {
+ return array
+ .map((value) => ({ value, sort: Math.random() }))
+ .sort((a, b) => a.sort - b.sort)
+ .map(({ value }) => value);
+};
+
+export const Supporters = () => {
+ return (
+
+
+
+
+ );
+};
+
+const SupportUsContainer = () => {
+ return (
+
+

+
+
+
+
+
+
日本語 / Mainly Japanese
+
+
+

+
Mainly English
+
+
+
+ );
+};
+
+const getRandomImage = (images) => {
+ const random_index = Math.floor(Math.random() * images.length);
+ return images[random_index];
+};
+
+export const SupportersContainer = () => {
+
+ return (
+
+

+
{`VRCT3.0のアップデートに向けて、めちゃ大変な開発を支えてくれた "Early Supporters" です。\nThey are the 'Early Supporters' who supported us through the incredibly challenging development toward the VRCT3.0 update.`}
+
+
+
+
{`みなさんのおかげで、みしゃ社長は布団で寝ることを許され(in開発室) しいなは喜び庭駆け回っています!!!ふわもちもぐもぐです!ありがとうございます。これからもまだまだ進化するVRCTをどうかよろしくお願いします!\nThanks to everyone, Misha has been granted the privilege of sleeping in a proper bed (in the development room), and Shiina is so happy, running around the yard! Fuwa-mochi-mogu-mogu! Thank you so much! We hope you'll continue to support the ever-evolving VRCT!`}
+
+ );
+};
+
+const ProgressBar = () => {
+ const [is_active, setIsActive] = useState(false);
+
+ useEffect(() => {
+ setIsActive(true);
+ const interval = setInterval(() => {
+ setIsActive(false);
+ setTimeout(() => setIsActive(true), 50);
+ }, SHUFFLE_INTERVAL_TIME);
+
+ return () => clearInterval(interval);
+ }, []);
+
+ return (
+
+ );
+};
+
+const SupportsWrapper = () => {
+ const { saveScrollPosition, restoreScrollPosition } = useSettingBoxScrollPosition();
+ const [imagesState, setImagesState] = useState({
+ mogu_images: [],
+ mochi_images: [],
+ fuwa_images: [],
+ basic_images: [],
+ former_images: [],
+ and_you_images: [],
+ chato_images: [],
+ });
+
+ const shuffleImages = () => {
+ saveScrollPosition();
+ const getCategoryImages = (start, count) => {
+ const category_images = supporters_filenames.slice(start, start + count);
+ return shuffleArray(category_images);
+ };
+
+ const randomChatoImages = shuffleArray(
+ Array.from({ length: mogu_count + mochi_count + fuwa_count + basic_count + former_count }, () =>
+ getRandomImage(chato_expressions_filenames)
+ )
+ );
+
+ setImagesState({
+ mogu_images: getCategoryImages(0, mogu_count),
+ mochi_images: getCategoryImages(mogu_count, mochi_count),
+ fuwa_images: getCategoryImages(mogu_count + mochi_count, fuwa_count),
+ basic_images: getCategoryImages(mogu_count + mochi_count + fuwa_count, basic_count),
+ former_images: getCategoryImages(mogu_count + mochi_count + fuwa_count + basic_count, former_count),
+ and_you_images: getCategoryImages(mogu_count + mochi_count + fuwa_count + basic_count + former_count, and_you_count),
+ chato_images: randomChatoImages,
+ });
+ setTimeout(() => restoreScrollPosition(), 0);
+ };
+
+ useEffect(() => {
+ shuffleImages();
+ const interval = setInterval(() => {
+ shuffleImages();
+ }, SHUFFLE_INTERVAL_TIME);
+
+ return () => clearInterval(interval);
+ }, []);
+
+
+ const getSupportersImageByFileName = (file_name) => {
+ const image_path = Object.keys(supporter_images).find((path) => path.endsWith(file_name + ".png"));
+ return image_path ? supporter_images[image_path]?.default : null;
+ };
+
+ const getChatoImageByFileName = (file_name) => {
+ const image_path = Object.keys(chato_expression_images).find((path) => path.endsWith(file_name + ".png"));
+ return image_path ? chato_expression_images[image_path]?.default : null;
+ };
+
+ const getRandomDelay = (min, max) => {
+ const random_value = Math.random() * (max - min) + min;
+ return `${random_value.toFixed(1)}s`;
+ };
+
+
+ const renderImages = (image_list, chato_list, options = {}) => {
+ return image_list.map((file_name, index) => {
+ const img_src = getSupportersImageByFileName(file_name);
+ const is_default_icon = default_icon_numbers.some((element) => file_name.endsWith(element));
+ const chato_expression_src = is_default_icon ? getChatoImageByFileName(chato_list[index]) : null;
+ const random_delay = getRandomDelay(0.1, 6);
+
+ return img_src ? (
+
+

+ {chato_expression_src && (
+

+ )}
+ {options.is_and_you_icon ?
: null}
+
+ ) : null;
+ });
+ };
+
+ return (
+
+ );
+};
+
+const AndYouIcon = () => {
+ return (
+ <>
+
+
+ FANBOX
+
+
+ >
+ );
+};
\ No newline at end of file
diff --git a/src-ui/app/config_page/setting_section/setting_box/supporters copy/C_Supporters.module.scss b/src-ui/app/config_page/setting_section/setting_box/supporters copy/C_Supporters.module.scss
new file mode 100644
index 00000000..4288b653
--- /dev/null
+++ b/src-ui/app/config_page/setting_section/setting_box/supporters copy/C_Supporters.module.scss
@@ -0,0 +1,205 @@
+.container {
+ display: flex;
+ gap: 1.2rem;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ // background-color: gray;
+}
+
+.support_us_container {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 2rem;
+ width: 100%;
+
+}
+.fanbox_img {
+ width: 60vw;
+}
+
+.support_us_button_wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ gap: 4.8rem;
+}
+.fanbox_wrapper, .kofi_wrapper {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 1rem;
+}
+.fanbox_button {
+ width: 14rem;
+ transition: all 0.3s ease;
+ &:hover {
+ width: 16rem;
+ }
+}
+.kofi_preparing {
+ width: 6rem;
+}
+
+.mainly_japanese, .mainly_english {
+ font-size: 1.2rem;
+ color: var(--dark_400_color);
+}
+
+
+.supporters_container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ gap: 1rem;
+}
+.vrct_supporters_title {
+ height: 6rem;
+}
+.vrct_supporters_desc {
+ font-size: 1.4rem;
+ text-align: start;
+}
+
+.supporters_wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ align-content: start;
+ flex-wrap: wrap;
+ column-gap: 1.4rem;
+ row-gap: 0.8rem;
+}
+
+.supporter_image_wrapper {
+ position: relative;
+ width: 18rem;
+ overflow: hidden;
+}
+
+.supporter_image {
+ width: 100%;
+}
+
+.mogu_image {
+ position: relative;
+ &::after {
+ content: "";
+ position: absolute;
+ top: -200%;
+ left: -200%;
+ width: 300%;
+ height: 300%;
+ background: linear-gradient(45deg, rgba(255, 255, 255, 0) 30%, rgba(255, 255, 255, 0.7) 50%, rgba(255, 255, 255, 0) 70%);
+ transform: rotate(90deg);
+ animation: shine 2.5s infinite;
+ filter: blur(0.4rem);
+ animation-delay: var(--delay, 0s);
+ }
+
+}
+
+@keyframes shine {
+ 0% {
+ top: -200%;
+ left: -200%;
+ }
+ 50% {
+ top: 50%;
+ left: 50%;
+ opacity: 0.7;
+ }
+ 100% {
+ top: 200%;
+ left: 200%;
+ }
+}
+
+.default_chato_expression_image {
+ position: absolute;
+ top: 50%;
+ left: 2.9rem;
+ width: 2.8rem;
+ transform: translate(-50%, -50%) rotate(10deg);
+ opacity: 0.8;
+}
+
+.and_you_container {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ transition: all 0.3s ease;
+}
+
+.and_you_1, .and_you_2 {
+ width: 2.2rem;
+ height: 0.2rem;
+ border-radius: 50%;
+ background-color: var(--dark_400_color);
+}
+
+.and_you_2 {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%) rotate(90deg);
+}
+
+.supporter_image_wrapper {
+ &:hover .and_you_container {
+ top: 40%;
+ transform: translate(-50%, -50%) rotate(180deg);
+ }
+ &:hover .and_you_fanbox_link_text {
+ top: 70%;
+ opacity: 1;
+ }
+}
+
+.supporter_image_wrapper.and_you_image {
+ cursor: pointer;
+ &:active {
+ opacity: 0.6;
+ }
+}
+
+.and_you_fanbox_link_text {
+ font-size: 1.2rem;
+ color: var(--dark_400_color);
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ transition: all 0.3s ease;
+ opacity: 0;
+}
+
+.external_link_svg {
+ color: var(--dark_200_color);
+ width: 1.2rem;
+ margin-left: 0.6rem;
+ padding-bottom: 0.2rem;
+}
+
+.vrct_supporters_desc_end {
+ font-size: 1.4rem;
+ margin-top: 2rem;
+ color: var(--dark_300_color);
+}
+
+.progress_bar {
+ height: 0.2rem;
+ width: 0%;
+ &.progress_bar_active {
+ transition: width 20000ms linear;
+ background-color: var(--primary_400_color);
+ width: 100%;
+ }
+}
\ No newline at end of file
diff --git a/src-ui/app/config_page/setting_section/setting_box/supporters/Supporters.jsx b/src-ui/app/config_page/setting_section/setting_box/supporters/Supporters.jsx
index 1d64b9c5..662f64e3 100644
--- a/src-ui/app/config_page/setting_section/setting_box/supporters/Supporters.jsx
+++ b/src-ui/app/config_page/setting_section/setting_box/supporters/Supporters.jsx
@@ -1,39 +1,6 @@
-import { useState, useEffect } from "react";
import styles from "./Supporters.module.scss";
-import clsx from "clsx";
-import { useTranslation } from "react-i18next";
-
-import {
- useSettingBoxScrollPosition,
-} from "@logics_configs"
-
-const supporter_images = import.meta.glob("@images/supporters/supporters_images/*.{png,jpg,jpeg,svg}", { eager: true });
-const chato_expression_images = import.meta.glob("@images/supporters/chato_expressions/*.{png,jpg,jpeg,svg}", { eager: true });
-import fanbox_img from "@images/supporters/c_fanbox_1620x580.png";
-import vrct_supporters_title from "@images/supporters/vrct_supporters_title.png";
-import fanbox_button from "@images/supporters/fanbox_button.png";
-import kofi_preparing from "@images/supporters/kofi_preparing.png";
-
-import ExternalLink from "@images/external_link.svg?react";
-
-const mogu_count = 8;
-const mochi_count = 3;
-const fuwa_count = 4;
-const basic_count = 5;
-const former_count = 2;
-const and_you_count = 1;
-const default_icon_numbers = ["05", "06", "07", "11"];
-
-const supporters_filenames = Array.from({ length: 23 }, (_, index) => `supporter_${String(index + 1).padStart(2, "0")}`);
-const chato_expressions_filenames = Array.from({ length: 7 }, (_, index) => `chato_expression_${String(index + 1).padStart(2, "0")}`);
-
-const SHUFFLE_INTERVAL_TIME = 20000;
-const shuffleArray = (array) => {
- return array
- .map((value) => ({ value, sort: Math.random() }))
- .sort((a, b) => a.sort - b.sort)
- .map(({ value }) => value);
-};
+import { SupportUsContainer } from "./support_us_container/SupportUsContainer";
+import { SupportersContainer } from "./supporters_container/SupportersContainer";
export const Supporters = () => {
return (
@@ -42,183 +9,4 @@ export const Supporters = () => {
);
-};
-
-const SupportUsContainer = () => {
- return (
-
-

-
-
-
-
-
-
日本語 / Mainly Japanese
-
-
-

-
Mainly English
-
-
-
- );
-};
-
-const getRandomImage = (images) => {
- const random_index = Math.floor(Math.random() * images.length);
- return images[random_index];
-};
-
-export const SupportersContainer = () => {
-
- return (
-
-

-
{`VRCT3.0のアップデートに向けて、めちゃ大変な開発を支えてくれた "Early Supporters" です。\nThey are the 'Early Supporters' who supported us through the incredibly challenging development toward the VRCT3.0 update.`}
-
-
-
-
{`みなさんのおかげで、みしゃ社長は布団で寝ることを許され(in開発室) しいなは喜び庭駆け回っています!!!ふわもちもぐもぐです!ありがとうございます。これからもまだまだ進化するVRCTをどうかよろしくお願いします!\nThanks to everyone, Misha has been granted the privilege of sleeping in a proper bed (in the development room), and Shiina is so happy, running around the yard! Fuwa-mochi-mogu-mogu! Thank you so much! We hope you'll continue to support the ever-evolving VRCT!`}
-
- );
-};
-
-const ProgressBar = () => {
- const [is_active, setIsActive] = useState(false);
-
- useEffect(() => {
- setIsActive(true);
- const interval = setInterval(() => {
- setIsActive(false);
- setTimeout(() => setIsActive(true), 50);
- }, SHUFFLE_INTERVAL_TIME);
-
- return () => clearInterval(interval);
- }, []);
-
- return (
-
- );
-};
-
-const SupportsWrapper = () => {
- const { saveScrollPosition, restoreScrollPosition } = useSettingBoxScrollPosition();
- const [imagesState, setImagesState] = useState({
- mogu_images: [],
- mochi_images: [],
- fuwa_images: [],
- basic_images: [],
- former_images: [],
- and_you_images: [],
- chato_images: [],
- });
-
- const shuffleImages = () => {
- saveScrollPosition();
- const getCategoryImages = (start, count) => {
- const category_images = supporters_filenames.slice(start, start + count);
- return shuffleArray(category_images);
- };
-
- const randomChatoImages = shuffleArray(
- Array.from({ length: mogu_count + mochi_count + fuwa_count + basic_count + former_count }, () =>
- getRandomImage(chato_expressions_filenames)
- )
- );
-
- setImagesState({
- mogu_images: getCategoryImages(0, mogu_count),
- mochi_images: getCategoryImages(mogu_count, mochi_count),
- fuwa_images: getCategoryImages(mogu_count + mochi_count, fuwa_count),
- basic_images: getCategoryImages(mogu_count + mochi_count + fuwa_count, basic_count),
- former_images: getCategoryImages(mogu_count + mochi_count + fuwa_count + basic_count, former_count),
- and_you_images: getCategoryImages(mogu_count + mochi_count + fuwa_count + basic_count + former_count, and_you_count),
- chato_images: randomChatoImages,
- });
- setTimeout(() => restoreScrollPosition(), 0);
- };
-
- useEffect(() => {
- shuffleImages();
- const interval = setInterval(() => {
- shuffleImages();
- }, SHUFFLE_INTERVAL_TIME);
-
- return () => clearInterval(interval);
- }, []);
-
-
- const getSupportersImageByFileName = (file_name) => {
- const image_path = Object.keys(supporter_images).find((path) => path.endsWith(file_name + ".png"));
- return image_path ? supporter_images[image_path]?.default : null;
- };
-
- const getChatoImageByFileName = (file_name) => {
- const image_path = Object.keys(chato_expression_images).find((path) => path.endsWith(file_name + ".png"));
- return image_path ? chato_expression_images[image_path]?.default : null;
- };
-
- const getRandomDelay = (min, max) => {
- const random_value = Math.random() * (max - min) + min;
- return `${random_value.toFixed(1)}s`;
- };
-
-
- const renderImages = (image_list, chato_list, options = {}) => {
- return image_list.map((file_name, index) => {
- const img_src = getSupportersImageByFileName(file_name);
- const is_default_icon = default_icon_numbers.some((element) => file_name.endsWith(element));
- const chato_expression_src = is_default_icon ? getChatoImageByFileName(chato_list[index]) : null;
- const random_delay = getRandomDelay(0.1, 6);
-
- return img_src ? (
-
-

- {chato_expression_src && (
-

- )}
- {options.is_and_you_icon ?
: null}
-
- ) : null;
- });
- };
-
- return (
-
- );
-};
-
-const AndYouIcon = () => {
- return (
- <>
-
-
- FANBOX
-
-
- >
- );
};
\ No newline at end of file
diff --git a/src-ui/app/config_page/setting_section/setting_box/supporters/Supporters.module.scss b/src-ui/app/config_page/setting_section/setting_box/supporters/Supporters.module.scss
index 4288b653..d93f76c6 100644
--- a/src-ui/app/config_page/setting_section/setting_box/supporters/Supporters.module.scss
+++ b/src-ui/app/config_page/setting_section/setting_box/supporters/Supporters.module.scss
@@ -5,201 +5,4 @@
justify-content: center;
align-items: center;
width: 100%;
- // background-color: gray;
-}
-
-.support_us_container {
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- gap: 2rem;
- width: 100%;
-
-}
-.fanbox_img {
- width: 60vw;
-}
-
-.support_us_button_wrapper {
- display: flex;
- justify-content: center;
- align-items: center;
- width: 100%;
- gap: 4.8rem;
-}
-.fanbox_wrapper, .kofi_wrapper {
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- gap: 1rem;
-}
-.fanbox_button {
- width: 14rem;
- transition: all 0.3s ease;
- &:hover {
- width: 16rem;
- }
-}
-.kofi_preparing {
- width: 6rem;
-}
-
-.mainly_japanese, .mainly_english {
- font-size: 1.2rem;
- color: var(--dark_400_color);
-}
-
-
-.supporters_container {
- display: flex;
- justify-content: center;
- align-items: center;
- flex-direction: column;
- gap: 1rem;
-}
-.vrct_supporters_title {
- height: 6rem;
-}
-.vrct_supporters_desc {
- font-size: 1.4rem;
- text-align: start;
-}
-
-.supporters_wrapper {
- display: flex;
- justify-content: center;
- align-items: center;
- align-content: start;
- flex-wrap: wrap;
- column-gap: 1.4rem;
- row-gap: 0.8rem;
-}
-
-.supporter_image_wrapper {
- position: relative;
- width: 18rem;
- overflow: hidden;
-}
-
-.supporter_image {
- width: 100%;
-}
-
-.mogu_image {
- position: relative;
- &::after {
- content: "";
- position: absolute;
- top: -200%;
- left: -200%;
- width: 300%;
- height: 300%;
- background: linear-gradient(45deg, rgba(255, 255, 255, 0) 30%, rgba(255, 255, 255, 0.7) 50%, rgba(255, 255, 255, 0) 70%);
- transform: rotate(90deg);
- animation: shine 2.5s infinite;
- filter: blur(0.4rem);
- animation-delay: var(--delay, 0s);
- }
-
-}
-
-@keyframes shine {
- 0% {
- top: -200%;
- left: -200%;
- }
- 50% {
- top: 50%;
- left: 50%;
- opacity: 0.7;
- }
- 100% {
- top: 200%;
- left: 200%;
- }
-}
-
-.default_chato_expression_image {
- position: absolute;
- top: 50%;
- left: 2.9rem;
- width: 2.8rem;
- transform: translate(-50%, -50%) rotate(10deg);
- opacity: 0.8;
-}
-
-.and_you_container {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- transition: all 0.3s ease;
-}
-
-.and_you_1, .and_you_2 {
- width: 2.2rem;
- height: 0.2rem;
- border-radius: 50%;
- background-color: var(--dark_400_color);
-}
-
-.and_you_2 {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%) rotate(90deg);
-}
-
-.supporter_image_wrapper {
- &:hover .and_you_container {
- top: 40%;
- transform: translate(-50%, -50%) rotate(180deg);
- }
- &:hover .and_you_fanbox_link_text {
- top: 70%;
- opacity: 1;
- }
-}
-
-.supporter_image_wrapper.and_you_image {
- cursor: pointer;
- &:active {
- opacity: 0.6;
- }
-}
-
-.and_you_fanbox_link_text {
- font-size: 1.2rem;
- color: var(--dark_400_color);
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- transition: all 0.3s ease;
- opacity: 0;
-}
-
-.external_link_svg {
- color: var(--dark_200_color);
- width: 1.2rem;
- margin-left: 0.6rem;
- padding-bottom: 0.2rem;
-}
-
-.vrct_supporters_desc_end {
- font-size: 1.4rem;
- margin-top: 2rem;
- color: var(--dark_300_color);
-}
-
-.progress_bar {
- height: 0.2rem;
- width: 0%;
- &.progress_bar_active {
- transition: width 20000ms linear;
- background-color: var(--primary_400_color);
- width: 100%;
- }
}
\ No newline at end of file
diff --git a/src-ui/app/config_page/setting_section/setting_box/supporters/support_us_container/SupportUsContainer.jsx b/src-ui/app/config_page/setting_section/setting_box/supporters/support_us_container/SupportUsContainer.jsx
new file mode 100644
index 00000000..65b00fc1
--- /dev/null
+++ b/src-ui/app/config_page/setting_section/setting_box/supporters/support_us_container/SupportUsContainer.jsx
@@ -0,0 +1,24 @@
+import fanbox_img from "@images/supporters/c_fanbox_1620x580.png";
+import fanbox_button from "@images/supporters/fanbox_button.png";
+import kofi_preparing from "@images/supporters/kofi_preparing.png";
+import styles from "./SupportUsContainer.module.scss";
+
+export const SupportUsContainer = () => {
+ return (
+
+

+
+
+
+
+
+
日本語 / Mainly Japanese
+
+
+

+
Mainly English
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/src-ui/app/config_page/setting_section/setting_box/supporters/support_us_container/SupportUsContainer.module.scss b/src-ui/app/config_page/setting_section/setting_box/supporters/support_us_container/SupportUsContainer.module.scss
new file mode 100644
index 00000000..d1dea0ad
--- /dev/null
+++ b/src-ui/app/config_page/setting_section/setting_box/supporters/support_us_container/SupportUsContainer.module.scss
@@ -0,0 +1,58 @@
+.support_us_container {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 2rem;
+ width: 100%;
+
+}
+.fanbox_img {
+ width: 60vw;
+}
+
+.support_us_button_wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ gap: 4.8rem;
+}
+.fanbox_wrapper, .kofi_wrapper {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 1rem;
+}
+.fanbox_button {
+ width: 14rem;
+ transition: all 0.3s ease;
+ &:hover {
+ width: 16rem;
+ }
+}
+.kofi_preparing {
+ width: 6rem;
+}
+
+.mainly_japanese, .mainly_english {
+ font-size: 1.2rem;
+ color: var(--dark_400_color);
+}
+
+
+.supporters_container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ gap: 1rem;
+}
+.vrct_supporters_title {
+ height: 6rem;
+}
+.vrct_supporters_desc {
+ font-size: 1.4rem;
+ text-align: start;
+}
\ No newline at end of file
diff --git a/src-ui/app/config_page/setting_section/setting_box/supporters/supporters_container/SupportersContainer.jsx b/src-ui/app/config_page/setting_section/setting_box/supporters/supporters_container/SupportersContainer.jsx
new file mode 100644
index 00000000..6a44c3ec
--- /dev/null
+++ b/src-ui/app/config_page/setting_section/setting_box/supporters/supporters_container/SupportersContainer.jsx
@@ -0,0 +1,41 @@
+import styles from "./SupportersContainer.module.scss";
+import { useState, useEffect } from "react";
+import vrct_supporters_title from "@images/supporters/vrct_supporters_title.png";
+import { SupportersWrapper } from "./supporters_wrapper/SupportersWrapper";
+import { clsx } from "clsx";
+const SHUFFLE_INTERVAL_TIME = 20000;
+
+export const SupportersContainer = () => {
+ return (
+
+

+
{`VRCT3.0のアップデートに向けて、めちゃ大変な開発を支えてくれた "Early Supporters" です。\nThey are the 'Early Supporters' who supported us through the incredibly challenging development toward the VRCT3.0 update.`}
+
+
+
+
{`みなさんのおかげで、みしゃ社長は布団で寝ることを許され(in開発室) しいなは喜び庭駆け回っています!!!ふわもちもぐもぐです!ありがとうございます。これからもまだまだ進化するVRCTをどうかよろしくお願いします!\nThanks to everyone, Misha has been granted the privilege of sleeping in a proper bed (in the development room), and Shiina is so happy, running around the yard! Fuwa-mochi-mogu-mogu! Thank you so much! We hope you'll continue to support the ever-evolving VRCT!`}
+
+ );
+};
+
+const ProgressBar = () => {
+ const [is_active, setIsActive] = useState(false);
+
+ useEffect(() => {
+ setIsActive(true);
+ const interval = setInterval(() => {
+ setIsActive(false);
+ setTimeout(() => setIsActive(true), 50);
+ }, SHUFFLE_INTERVAL_TIME);
+
+ return () => clearInterval(interval);
+ }, []);
+
+ return (
+
+ );
+};
\ No newline at end of file
diff --git a/src-ui/app/config_page/setting_section/setting_box/supporters/supporters_container/SupportersContainer.module.scss b/src-ui/app/config_page/setting_section/setting_box/supporters/supporters_container/SupportersContainer.module.scss
new file mode 100644
index 00000000..f6ed3518
--- /dev/null
+++ b/src-ui/app/config_page/setting_section/setting_box/supporters/supporters_container/SupportersContainer.module.scss
@@ -0,0 +1,30 @@
+.supporters_container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ gap: 1rem;
+}
+.vrct_supporters_title {
+ height: 6rem;
+}
+.vrct_supporters_desc {
+ font-size: 1.4rem;
+ text-align: start;
+}
+
+.vrct_supporters_desc_end {
+ font-size: 1.4rem;
+ margin-top: 2rem;
+ color: var(--dark_300_color);
+}
+
+.progress_bar {
+ height: 0.2rem;
+ width: 0%;
+ &.progress_bar_active {
+ transition: width 20000ms linear;
+ background-color: var(--primary_400_color);
+ width: 100%;
+ }
+}
\ No newline at end of file
diff --git a/src-ui/app/config_page/setting_section/setting_box/supporters/supporters_container/supporters_wrapper/SupportersWrapper.jsx b/src-ui/app/config_page/setting_section/setting_box/supporters/supporters_container/supporters_wrapper/SupportersWrapper.jsx
new file mode 100644
index 00000000..24e47eb1
--- /dev/null
+++ b/src-ui/app/config_page/setting_section/setting_box/supporters/supporters_container/supporters_wrapper/SupportersWrapper.jsx
@@ -0,0 +1,232 @@
+import React, { useState, useCallback, useEffect } from "react";
+import clsx from "clsx";
+import ArrowLeftSvg from "@images/arrow_left.svg?react";
+import styles from "./SupportersWrapper.module.scss";
+import { shuffleArray, randomIntMinMax, randomMinMax } from "@utils";
+
+import {
+ useSettingBoxScrollPosition,
+} from "@logics_configs"
+
+import json_data from "./data.json";
+
+const target_supporting_month = "2025-01";
+
+const SHUFFLE_INTERVAL_TIME = 20000;
+
+
+
+const and_you_data = {
+ supporter_id: "and_you",
+};
+
+
+const getImagePath = (images, file_name) => {
+ const image_path = Object.keys(images).find((path) => path.endsWith(`${file_name}.png`));
+ return image_path ? images[image_path]?.default : null;
+};
+
+const image_sets = {
+ supporter_cards: import.meta.glob("@images/supporters/supporter_cards/*.png", { eager: true }),
+ chato_expressions: import.meta.glob("@images/supporters/chato_expressions/*.png", { eager: true }),
+ supporters_labels: import.meta.glob("@images/supporters/supporters_labels/*.png", { eager: true }),
+ supporters_icons: import.meta.glob("@images/supporters/supporters_icons/*.png", { eager: true }),
+};
+
+const getSupporterCard = (plan_name) => {
+ const card_map = {
+ "もぐもぐ_2000": "mogu_card",
+ "もちもち_1000": "mochi_card",
+ "ふわふわ_500": "fuwa_card",
+ "Basic_300": "basic_card",
+ };
+ return getImagePath(image_sets.supporter_cards, card_map[plan_name] || "basic_card");
+};
+
+const getChatoExpressionsPath = (file_name) =>
+ getImagePath(image_sets.chato_expressions, file_name);
+
+const getSupportersLabelsPath = (file_name) =>
+ getImagePath(image_sets.supporters_labels, file_name);
+
+const getSupportersIconsPath = (file_name) =>
+ getImagePath(image_sets.supporters_icons, file_name);
+
+const chato_ex_count = Object.keys(image_sets.chato_expressions).length;
+
+export const SupportersWrapper = () => {
+ const { saveScrollPosition, restoreScrollPosition } = useSettingBoxScrollPosition();
+
+ let credit_pending_count = 0;
+ const filtered_data = json_data.filter((supporter) => {
+ if (!supporter.supporter_id) return false;
+
+ const months = Object.keys(supporter).filter((key) => key.match(/^\d{4}-\d{2}$/));
+ const has_valid_month = months.some((month) => supporter[month]);
+ if (!has_valid_month) return false;
+
+ const basic_300_months = months.filter((month) => supporter[month] === "Basic_300");
+ const has_special_plan = months.some((month) => ["ふわふわ_500", "もちもち_1000", "もぐもぐ_2000"].includes(supporter[month]));
+
+ if (basic_300_months.length === 1 && !has_special_plan) {
+ credit_pending_count++;
+ return false;
+ }
+
+ return true;
+ });
+
+ const grouped_data = {
+ もぐもぐ_2000: [],
+ もちもち_1000: [],
+ ふわふわ_500: [],
+ Basic_300: [],
+ empty: [],
+ and_you: [],
+ };
+
+ filtered_data.forEach((supporter) => {
+ const value = supporter[target_supporting_month] || "empty";
+ if (grouped_data[value]) {
+ grouped_data[value].push(supporter);
+ } else {
+ grouped_data["empty"].push(supporter);
+ }
+ });
+
+ const [supportersData, setSupportersData] = useState(() => [
+ ...grouped_data["もぐもぐ_2000"],
+ ...grouped_data["もちもち_1000"],
+ ...grouped_data["ふわふわ_500"],
+ ...grouped_data["Basic_300"],
+ ...grouped_data["empty"],
+ and_you_data,
+ ]);
+
+
+ const [chatoExpressions, setChatoExpressions] = useState(() =>
+ supportersData.map(() =>
+ getChatoExpressionsPath(`chato_expression_${randomIntMinMax(1, chato_ex_count)}`)
+ )
+ );
+
+
+ const shuffleSupporters = useCallback(() => {
+ saveScrollPosition();
+ const newSupportersData = [
+ ...shuffleArray(grouped_data["もぐもぐ_2000"]),
+ ...shuffleArray(grouped_data["もちもち_1000"]),
+ ...shuffleArray(grouped_data["ふわふわ_500"]),
+ ...shuffleArray(grouped_data["Basic_300"]),
+ ...shuffleArray(grouped_data["empty"]),
+ and_you_data,
+ ];
+ setSupportersData(newSupportersData);
+
+
+ setChatoExpressions(
+ newSupportersData.map(() =>
+ getChatoExpressionsPath(`chato_expression_${randomIntMinMax(1, chato_ex_count)}`)
+ )
+ );
+ setTimeout(() => restoreScrollPosition(), 0);
+ }, [grouped_data]);
+
+ const renderImages = () => {
+ return supportersData.map((item, index) => {
+ const target_plan = item[target_supporting_month];
+ const img_src = getSupporterCard(target_plan);
+ const is_default_icon = item.supporter_icon_id === "";
+ const is_icon_plan = ["もぐもぐ_2000", "もちもち_1000"].includes(target_plan);
+ const is_and_you = item.supporter_id === "and_you";
+
+ const random_delay = `${randomMinMax(0.1, 6).toFixed(1)}s`;
+
+ const image_wrapper_classname = clsx(styles.supporter_image_wrapper, {
+ [styles.mogu_image]: target_plan === "もぐもぐ_2000",
+ });
+
+ const file_name = is_and_you ? "and_you" : `supporter_${item.supporter_id}`;
+ const label_img_src = getSupportersLabelsPath(file_name);
+ const icon_img_src = getSupportersIconsPath(`supporter_icon_${item.supporter_icon_id}`);
+
+ const supporter_label_component_classname = clsx(styles.supporter_label_component, {
+ [styles.is_icon_plan]: is_icon_plan,
+ });
+
+ const supporterLabelComponent = () => (
+
+ {is_icon_plan && (
+
+ {is_default_icon ? (
+

+ ) : (
+

+ )}
+
+ )}
+

+
+ );
+
+ return is_and_you ? (
+
+
+

+ {supporterLabelComponent()}
+
+
+
+
+ ): img_src ? (
+
+

+ {supporterLabelComponent()}
+
+ ) : null;
+ });
+ };
+
+
+ useEffect(() => {
+ shuffleSupporters();
+ const interval = setInterval(() => {
+ shuffleSupporters();
+ }, SHUFFLE_INTERVAL_TIME);
+
+ return () => clearInterval(interval);
+ }, []);
+
+ return (
+
+ );
+};
+
+
+const AndYouIcon = () => {
+ return (
+ <>
+
+
+ FANBOX Ko-fi Patreon
+
+
+ >
+ );
+};
\ No newline at end of file
diff --git a/src-ui/app/config_page/setting_section/setting_box/supporters/supporters_container/supporters_wrapper/SupportersWrapper.module.scss b/src-ui/app/config_page/setting_section/setting_box/supporters/supporters_container/supporters_wrapper/SupportersWrapper.module.scss
new file mode 100644
index 00000000..263131cf
--- /dev/null
+++ b/src-ui/app/config_page/setting_section/setting_box/supporters/supporters_container/supporters_wrapper/SupportersWrapper.module.scss
@@ -0,0 +1,188 @@
+.supporters_wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ align-content: start;
+ flex-wrap: wrap;
+ column-gap: 1.4rem;
+ row-gap: 0.8rem;
+}
+
+.supporter_image_wrapper {
+ position: relative;
+ width: 18rem;
+ overflow: hidden;
+}
+
+.supporter_image {
+ width: 100%;
+}
+
+.supporter_label_component {
+ position: absolute;
+ left: 0.6rem;
+ &.is_icon_plan {
+ top: 50%;
+ transform: translateY(-50%);
+ }
+ top: 0.4rem;
+ display: flex;
+ justify-content: center;
+ gap: 0.4rem;
+}
+
+.supporter_label_image {
+ height: 2rem;
+ // margin-top: 0.2rem;
+ &.small {
+ height: 1.4rem;
+ }
+}
+
+.supporter_icon_wrapper {
+ height: 4rem;
+ aspect-ratio: 1 /1;
+ border-radius: 50%;
+ background-color: #ffffff;
+ overflow: hidden;
+ position: relative;
+}
+
+.supporter_icon {
+ aspect-ratio: 1 / 1;
+ height: 100%;
+ width: 100%;
+}
+
+.default_chato_expression_image {
+ position: absolute;
+ top: 52%;
+ left: 50%;
+ transform: translate(-50%, -50%) rotate(10deg);
+ width: 2.8rem;
+ opacity: 0.8;
+}
+
+.mogu_image {
+ position: relative;
+ &::after {
+ content: "";
+ position: absolute;
+ top: -200%;
+ left: -200%;
+ width: 300%;
+ height: 300%;
+ background: linear-gradient(45deg, rgba(255, 255, 255, 0) 30%, rgba(255, 255, 255, 0.7) 50%, rgba(255, 255, 255, 0) 70%);
+ transform: rotate(90deg);
+ animation: shine 2.5s infinite;
+ filter: blur(0.4rem);
+ animation-delay: var(--delay, 0s);
+ }
+
+}
+
+@keyframes shine {
+ 0% {
+ top: -200%;
+ left: -200%;
+ }
+ 50% {
+ top: 50%;
+ left: 50%;
+ opacity: 0.7;
+ }
+ 100% {
+ top: 200%;
+ left: 200%;
+ }
+}
+
+
+
+.and_you_container {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ transition: all 0.3s ease;
+}
+
+.and_you_1, .and_you_2 {
+ width: 2.2rem;
+ height: 0.2rem;
+ border-radius: 50%;
+ background-color: var(--dark_400_color);
+}
+
+.and_you_2 {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%) rotate(90deg);
+}
+
+.supporter_image_wrapper {
+ &:hover .and_you_container {
+ top: 36%;
+ transform: translate(-50%, -50%) rotate(180deg);
+ animation: disappear 0.3s forwards;
+ }
+ &:hover .and_you_fanbox_link_text {
+ top: 74%;
+ opacity: 1;
+ }
+ &:hover .arrow_left_svg {
+ opacity: 0;
+ animation: arrow_up_down 0.3s forwards;
+ animation-delay: 0.3s;
+ }
+}
+
+.supporter_image_wrapper.and_you_image {
+ cursor: pointer;
+ &:active {
+ opacity: 0.6;
+ }
+}
+
+.and_you_fanbox_link_text {
+ font-size: 1.2rem;
+ color: var(--dark_400_color);
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 100%;
+ text-align: center;
+ transform: translate(-50%, -50%);
+ transition: all 0.3s ease;
+ opacity: 0;
+}
+
+.arrow_left_svg {
+ position: absolute;
+ top: 60%;
+ left: 50%;
+ transform: translate(-50%, -50%) rotate(90deg);
+ color: var(--dark_400_color);
+ width: 2rem;
+ opacity: 0;
+}
+
+@keyframes arrow_up_down {
+ 0% {
+ top: 60%;
+ }
+ 100% {
+ top: 36%;
+ opacity: 1;
+ }
+}
+
+@keyframes disappear {
+ 0% {
+ opacity: 1;
+ }
+ 100% {
+ opacity: 0;
+ }
+}
\ No newline at end of file
diff --git a/src-ui/app/config_page/setting_section/setting_box/supporters/supporters_container/supporters_wrapper/data.json b/src-ui/app/config_page/setting_section/setting_box/supporters/supporters_container/supporters_wrapper/data.json
new file mode 100644
index 00000000..12ef65eb
--- /dev/null
+++ b/src-ui/app/config_page/setting_section/setting_box/supporters/supporters_container/supporters_wrapper/data.json
@@ -0,0 +1,343 @@
+[
+ {
+ "supporter_id": 1,
+ "supporter_icon_id": "",
+ "2024-10": "Basic_300",
+ "2024-11": "Basic_300",
+ "2024-12": "Basic_300",
+ "2025-01": "Basic_300",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 2,
+ "supporter_icon_id": 8,
+ "2024-10": "もぐもぐ_2000",
+ "2024-11": "もぐもぐ_2000",
+ "2024-12": "もぐもぐ_2000",
+ "2025-01": "もぐもぐ_2000",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 3,
+ "supporter_icon_id": 4,
+ "2024-10": "もちもち_1000",
+ "2024-11": "もちもち_1000",
+ "2024-12": "もちもち_1000",
+ "2025-01": "もちもち_1000",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 4,
+ "supporter_icon_id": "",
+ "2024-10": "もぐもぐ_2000",
+ "2024-11": "もぐもぐ_2000",
+ "2024-12": "もぐもぐ_2000",
+ "2025-01": "もぐもぐ_2000",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 5,
+ "supporter_icon_id": "",
+ "2024-10": "ふわふわ_500",
+ "2024-11": "ふわふわ_500",
+ "2024-12": "ふわふわ_500",
+ "2025-01": "Basic_300",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 6,
+ "supporter_icon_id": "",
+ "2024-10": "ふわふわ_500",
+ "2024-11": "ふわふわ_500",
+ "2024-12": "ふわふわ_500",
+ "2025-01": "ふわふわ_500",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 7,
+ "supporter_icon_id": "",
+ "2024-10": "ふわふわ_500",
+ "2024-11": "ふわふわ_500",
+ "2024-12": "ふわふわ_500",
+ "2025-01": "ふわふわ_500",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 8,
+ "supporter_icon_id": "",
+ "2024-10": "Basic_300",
+ "2024-11": "Basic_300",
+ "2024-12": "Basic_300",
+ "2025-01": "",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 9,
+ "supporter_icon_id": 6,
+ "2024-10": "もぐもぐ_2000",
+ "2024-11": "もぐもぐ_2000",
+ "2024-12": "もぐもぐ_2000",
+ "2025-01": "もぐもぐ_2000",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 10,
+ "supporter_icon_id": "",
+ "2024-10": "Basic_300",
+ "2024-11": "Basic_300",
+ "2024-12": "Basic_300",
+ "2025-01": "Basic_300",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 11,
+ "supporter_icon_id": "",
+ "2024-10": "もぐもぐ_2000",
+ "2024-11": "もぐもぐ_2000",
+ "2024-12": "もぐもぐ_2000",
+ "2025-01": "もぐもぐ_2000",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 12,
+ "supporter_icon_id": "",
+ "2024-10": "もぐもぐ_2000",
+ "2024-11": "もぐもぐ_2000",
+ "2024-12": "もぐもぐ_2000",
+ "2025-01": "もぐもぐ_2000",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 13,
+ "supporter_icon_id": "",
+ "2024-10": "Basic_300",
+ "2024-11": "Basic_300",
+ "2024-12": "Basic_300",
+ "2025-01": "Basic_300",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 14,
+ "supporter_icon_id": 2,
+ "2024-10": "もちもち_1000",
+ "2024-11": "もちもち_1000",
+ "2024-12": "もちもち_1000",
+ "2025-01": "もちもち_1000",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 15,
+ "supporter_icon_id": 5,
+ "2024-10": "もぐもぐ_2000",
+ "2024-11": "もぐもぐ_2000",
+ "2024-12": "もぐもぐ_2000",
+ "2025-01": "もぐもぐ_2000",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 16,
+ "supporter_icon_id": "",
+ "2024-10": "もぐもぐ_2000",
+ "2024-11": "",
+ "2024-12": "",
+ "2025-01": "",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 17,
+ "supporter_icon_id": "",
+ "2024-10": "もちもち_1000",
+ "2024-11": "もちもち_1000",
+ "2024-12": "もちもち_1000",
+ "2025-01": "もちもち_1000",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 18,
+ "supporter_icon_id": "",
+ "2024-10": "Basic_300",
+ "2024-11": "Basic_300",
+ "2024-12": "",
+ "2025-01": "",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 19,
+ "supporter_icon_id": 1,
+ "2024-10": "もぐもぐ_2000",
+ "2024-11": "もぐもぐ_2000",
+ "2024-12": "もぐもぐ_2000",
+ "2025-01": "もぐもぐ_2000",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 20,
+ "supporter_icon_id": "",
+ "2024-10": "Basic_300",
+ "2024-11": "Basic_300",
+ "2024-12": "Basic_300",
+ "2025-01": "ふわふわ_500",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 21,
+ "supporter_icon_id": "",
+ "2024-10": "",
+ "2024-11": "ふわふわ_500",
+ "2024-12": "ふわふわ_500",
+ "2025-01": "ふわふわ_500",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 22,
+ "supporter_icon_id": 3,
+ "2024-10": "",
+ "2024-11": "",
+ "2024-12": "もぐもぐ_2000",
+ "2025-01": "もぐもぐ_2000",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 23,
+ "supporter_icon_id": "",
+ "2024-10": "",
+ "2024-11": "",
+ "2024-12": "",
+ "2025-01": "ふわふわ_500",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 24,
+ "supporter_icon_id": 7,
+ "2024-10": "",
+ "2024-11": "",
+ "2024-12": "",
+ "2025-01": "もぐもぐ_2000",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 25,
+ "supporter_icon_id": 9,
+ "2024-10": "",
+ "2024-11": "",
+ "2024-12": "",
+ "2025-01": "もぐもぐ_2000",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 26,
+ "supporter_icon_id": "",
+ "2024-10": "",
+ "2024-11": "",
+ "2024-12": "",
+ "2025-01": "もちもち_1000",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 27,
+ "supporter_icon_id": "",
+ "2024-10": "",
+ "2024-11": "",
+ "2024-12": "",
+ "2025-01": "Basic_300",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 28,
+ "supporter_icon_id": "",
+ "2024-10": "",
+ "2024-11": "",
+ "2024-12": "",
+ "2025-01": "Basic_300",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 29,
+ "supporter_icon_id": "",
+ "2024-10": "",
+ "2024-11": "",
+ "2024-12": "",
+ "2025-01": "",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": 30,
+ "supporter_icon_id": "",
+ "2024-10": "",
+ "2024-11": "",
+ "2024-12": "",
+ "2025-01": "",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ },
+ {
+ "supporter_id": "",
+ "supporter_icon_id": "",
+ "2024-10": "",
+ "2024-11": "",
+ "2024-12": "",
+ "2025-01": "",
+ "2025-02": "",
+ "2025-03": "",
+ "2025-04": ""
+ }
+]
\ No newline at end of file
diff --git a/src-ui/assets/supporters/chato_expressions/chato_expression_01.png b/src-ui/assets/supporters/chato_expressions/chato_expression_1.png
similarity index 100%
rename from src-ui/assets/supporters/chato_expressions/chato_expression_01.png
rename to src-ui/assets/supporters/chato_expressions/chato_expression_1.png
diff --git a/src-ui/assets/supporters/chato_expressions/chato_expression_02.png b/src-ui/assets/supporters/chato_expressions/chato_expression_2.png
similarity index 100%
rename from src-ui/assets/supporters/chato_expressions/chato_expression_02.png
rename to src-ui/assets/supporters/chato_expressions/chato_expression_2.png
diff --git a/src-ui/assets/supporters/chato_expressions/chato_expression_03.png b/src-ui/assets/supporters/chato_expressions/chato_expression_3.png
similarity index 100%
rename from src-ui/assets/supporters/chato_expressions/chato_expression_03.png
rename to src-ui/assets/supporters/chato_expressions/chato_expression_3.png
diff --git a/src-ui/assets/supporters/chato_expressions/chato_expression_04.png b/src-ui/assets/supporters/chato_expressions/chato_expression_4.png
similarity index 100%
rename from src-ui/assets/supporters/chato_expressions/chato_expression_04.png
rename to src-ui/assets/supporters/chato_expressions/chato_expression_4.png
diff --git a/src-ui/assets/supporters/chato_expressions/chato_expression_05.png b/src-ui/assets/supporters/chato_expressions/chato_expression_5.png
similarity index 100%
rename from src-ui/assets/supporters/chato_expressions/chato_expression_05.png
rename to src-ui/assets/supporters/chato_expressions/chato_expression_5.png
diff --git a/src-ui/assets/supporters/chato_expressions/chato_expression_06.png b/src-ui/assets/supporters/chato_expressions/chato_expression_6.png
similarity index 100%
rename from src-ui/assets/supporters/chato_expressions/chato_expression_06.png
rename to src-ui/assets/supporters/chato_expressions/chato_expression_6.png
diff --git a/src-ui/assets/supporters/chato_expressions/chato_expression_07.png b/src-ui/assets/supporters/chato_expressions/chato_expression_7.png
similarity index 100%
rename from src-ui/assets/supporters/chato_expressions/chato_expression_07.png
rename to src-ui/assets/supporters/chato_expressions/chato_expression_7.png
diff --git a/src-ui/assets/supporters/supporter_cards/basic_card.png b/src-ui/assets/supporters/supporter_cards/basic_card.png
new file mode 100644
index 00000000..c3a015ef
Binary files /dev/null and b/src-ui/assets/supporters/supporter_cards/basic_card.png differ
diff --git a/src-ui/assets/supporters/supporter_cards/fuwa_card.png b/src-ui/assets/supporters/supporter_cards/fuwa_card.png
new file mode 100644
index 00000000..379540ef
Binary files /dev/null and b/src-ui/assets/supporters/supporter_cards/fuwa_card.png differ
diff --git a/src-ui/assets/supporters/supporter_cards/mochi_card.png b/src-ui/assets/supporters/supporter_cards/mochi_card.png
new file mode 100644
index 00000000..b8459285
Binary files /dev/null and b/src-ui/assets/supporters/supporter_cards/mochi_card.png differ
diff --git a/src-ui/assets/supporters/supporter_cards/mogu_card.png b/src-ui/assets/supporters/supporter_cards/mogu_card.png
new file mode 100644
index 00000000..c049481d
Binary files /dev/null and b/src-ui/assets/supporters/supporter_cards/mogu_card.png differ
diff --git a/src-ui/assets/supporters/supporters_icons/supporter_icon_1.png b/src-ui/assets/supporters/supporters_icons/supporter_icon_1.png
new file mode 100644
index 00000000..b8629841
Binary files /dev/null and b/src-ui/assets/supporters/supporters_icons/supporter_icon_1.png differ
diff --git a/src-ui/assets/supporters/supporters_icons/supporter_icon_2.png b/src-ui/assets/supporters/supporters_icons/supporter_icon_2.png
new file mode 100644
index 00000000..ee0d91ac
Binary files /dev/null and b/src-ui/assets/supporters/supporters_icons/supporter_icon_2.png differ
diff --git a/src-ui/assets/supporters/supporters_icons/supporter_icon_3.png b/src-ui/assets/supporters/supporters_icons/supporter_icon_3.png
new file mode 100644
index 00000000..3bfe93d3
Binary files /dev/null and b/src-ui/assets/supporters/supporters_icons/supporter_icon_3.png differ
diff --git a/src-ui/assets/supporters/supporters_icons/supporter_icon_4.png b/src-ui/assets/supporters/supporters_icons/supporter_icon_4.png
new file mode 100644
index 00000000..7c088051
Binary files /dev/null and b/src-ui/assets/supporters/supporters_icons/supporter_icon_4.png differ
diff --git a/src-ui/assets/supporters/supporters_icons/supporter_icon_5.png b/src-ui/assets/supporters/supporters_icons/supporter_icon_5.png
new file mode 100644
index 00000000..28eff424
Binary files /dev/null and b/src-ui/assets/supporters/supporters_icons/supporter_icon_5.png differ
diff --git a/src-ui/assets/supporters/supporters_icons/supporter_icon_6.png b/src-ui/assets/supporters/supporters_icons/supporter_icon_6.png
new file mode 100644
index 00000000..5d7a6d97
Binary files /dev/null and b/src-ui/assets/supporters/supporters_icons/supporter_icon_6.png differ
diff --git a/src-ui/assets/supporters/supporters_icons/supporter_icon_7.png b/src-ui/assets/supporters/supporters_icons/supporter_icon_7.png
new file mode 100644
index 00000000..11d0860d
Binary files /dev/null and b/src-ui/assets/supporters/supporters_icons/supporter_icon_7.png differ
diff --git a/src-ui/assets/supporters/supporters_icons/supporter_icon_8.png b/src-ui/assets/supporters/supporters_icons/supporter_icon_8.png
new file mode 100644
index 00000000..b72e7e91
Binary files /dev/null and b/src-ui/assets/supporters/supporters_icons/supporter_icon_8.png differ
diff --git a/src-ui/assets/supporters/supporters_icons/supporter_icon_9.png b/src-ui/assets/supporters/supporters_icons/supporter_icon_9.png
new file mode 100644
index 00000000..10456112
Binary files /dev/null and b/src-ui/assets/supporters/supporters_icons/supporter_icon_9.png differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_01.png b/src-ui/assets/supporters/supporters_images/supporter_01.png
deleted file mode 100644
index d43986e8..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_01.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_02.png b/src-ui/assets/supporters/supporters_images/supporter_02.png
deleted file mode 100644
index 013b1f74..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_02.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_03.png b/src-ui/assets/supporters/supporters_images/supporter_03.png
deleted file mode 100644
index b5f47a6d..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_03.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_04.png b/src-ui/assets/supporters/supporters_images/supporter_04.png
deleted file mode 100644
index edf48965..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_04.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_05.png b/src-ui/assets/supporters/supporters_images/supporter_05.png
deleted file mode 100644
index a8874947..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_05.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_06.png b/src-ui/assets/supporters/supporters_images/supporter_06.png
deleted file mode 100644
index c7b10514..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_06.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_07.png b/src-ui/assets/supporters/supporters_images/supporter_07.png
deleted file mode 100644
index bb86cfa0..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_07.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_08.png b/src-ui/assets/supporters/supporters_images/supporter_08.png
deleted file mode 100644
index 45ff7330..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_08.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_09.png b/src-ui/assets/supporters/supporters_images/supporter_09.png
deleted file mode 100644
index 4564b031..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_09.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_10.png b/src-ui/assets/supporters/supporters_images/supporter_10.png
deleted file mode 100644
index 8ce252f0..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_10.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_11.png b/src-ui/assets/supporters/supporters_images/supporter_11.png
deleted file mode 100644
index cfa86fc3..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_11.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_12.png b/src-ui/assets/supporters/supporters_images/supporter_12.png
deleted file mode 100644
index 49f34c2d..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_12.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_13.png b/src-ui/assets/supporters/supporters_images/supporter_13.png
deleted file mode 100644
index 7bd136a3..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_13.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_14.png b/src-ui/assets/supporters/supporters_images/supporter_14.png
deleted file mode 100644
index 9e50bde8..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_14.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_15.png b/src-ui/assets/supporters/supporters_images/supporter_15.png
deleted file mode 100644
index f445a329..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_15.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_16.png b/src-ui/assets/supporters/supporters_images/supporter_16.png
deleted file mode 100644
index 815d2f12..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_16.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_17.png b/src-ui/assets/supporters/supporters_images/supporter_17.png
deleted file mode 100644
index b5ddd12e..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_17.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_18.png b/src-ui/assets/supporters/supporters_images/supporter_18.png
deleted file mode 100644
index d63f2288..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_18.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_19.png b/src-ui/assets/supporters/supporters_images/supporter_19.png
deleted file mode 100644
index 0f89d1ef..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_19.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_20.png b/src-ui/assets/supporters/supporters_images/supporter_20.png
deleted file mode 100644
index ee1fc327..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_20.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_21.png b/src-ui/assets/supporters/supporters_images/supporter_21.png
deleted file mode 100644
index b76bb6c3..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_21.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_22.png b/src-ui/assets/supporters/supporters_images/supporter_22.png
deleted file mode 100644
index b0006be4..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_22.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_images/supporter_23.png b/src-ui/assets/supporters/supporters_images/supporter_23.png
deleted file mode 100644
index 207be07e..00000000
Binary files a/src-ui/assets/supporters/supporters_images/supporter_23.png and /dev/null differ
diff --git a/src-ui/assets/supporters/supporters_labels/and_you.png b/src-ui/assets/supporters/supporters_labels/and_you.png
new file mode 100644
index 00000000..5dba52d7
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/and_you.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_1.png b/src-ui/assets/supporters/supporters_labels/supporter_1.png
new file mode 100644
index 00000000..da84f7bc
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_1.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_10.png b/src-ui/assets/supporters/supporters_labels/supporter_10.png
new file mode 100644
index 00000000..adcb90e1
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_10.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_11.png b/src-ui/assets/supporters/supporters_labels/supporter_11.png
new file mode 100644
index 00000000..34874cdb
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_11.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_12.png b/src-ui/assets/supporters/supporters_labels/supporter_12.png
new file mode 100644
index 00000000..91b4434c
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_12.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_13.png b/src-ui/assets/supporters/supporters_labels/supporter_13.png
new file mode 100644
index 00000000..97874ce5
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_13.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_14.png b/src-ui/assets/supporters/supporters_labels/supporter_14.png
new file mode 100644
index 00000000..ccc0dd1d
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_14.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_15.png b/src-ui/assets/supporters/supporters_labels/supporter_15.png
new file mode 100644
index 00000000..3856a8c0
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_15.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_16.png b/src-ui/assets/supporters/supporters_labels/supporter_16.png
new file mode 100644
index 00000000..01f48ec8
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_16.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_17.png b/src-ui/assets/supporters/supporters_labels/supporter_17.png
new file mode 100644
index 00000000..2597f4d1
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_17.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_18.png b/src-ui/assets/supporters/supporters_labels/supporter_18.png
new file mode 100644
index 00000000..91f6997b
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_18.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_19.png b/src-ui/assets/supporters/supporters_labels/supporter_19.png
new file mode 100644
index 00000000..40cdbf4f
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_19.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_2.png b/src-ui/assets/supporters/supporters_labels/supporter_2.png
new file mode 100644
index 00000000..f739f4f1
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_2.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_20.png b/src-ui/assets/supporters/supporters_labels/supporter_20.png
new file mode 100644
index 00000000..fa54e057
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_20.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_21.png b/src-ui/assets/supporters/supporters_labels/supporter_21.png
new file mode 100644
index 00000000..be534d66
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_21.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_22.png b/src-ui/assets/supporters/supporters_labels/supporter_22.png
new file mode 100644
index 00000000..ae85a713
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_22.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_23.png b/src-ui/assets/supporters/supporters_labels/supporter_23.png
new file mode 100644
index 00000000..578ec516
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_23.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_24.png b/src-ui/assets/supporters/supporters_labels/supporter_24.png
new file mode 100644
index 00000000..28da5526
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_24.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_25.png b/src-ui/assets/supporters/supporters_labels/supporter_25.png
new file mode 100644
index 00000000..5531503c
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_25.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_26.png b/src-ui/assets/supporters/supporters_labels/supporter_26.png
new file mode 100644
index 00000000..58efb139
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_26.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_3.png b/src-ui/assets/supporters/supporters_labels/supporter_3.png
new file mode 100644
index 00000000..4989b4d6
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_3.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_4.png b/src-ui/assets/supporters/supporters_labels/supporter_4.png
new file mode 100644
index 00000000..df433dba
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_4.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_5.png b/src-ui/assets/supporters/supporters_labels/supporter_5.png
new file mode 100644
index 00000000..ea70c489
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_5.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_6.png b/src-ui/assets/supporters/supporters_labels/supporter_6.png
new file mode 100644
index 00000000..e2c5952a
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_6.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_7.png b/src-ui/assets/supporters/supporters_labels/supporter_7.png
new file mode 100644
index 00000000..29f8df44
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_7.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_8.png b/src-ui/assets/supporters/supporters_labels/supporter_8.png
new file mode 100644
index 00000000..78b2349f
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_8.png differ
diff --git a/src-ui/assets/supporters/supporters_labels/supporter_9.png b/src-ui/assets/supporters/supporters_labels/supporter_9.png
new file mode 100644
index 00000000..cb25ec43
Binary files /dev/null and b/src-ui/assets/supporters/supporters_labels/supporter_9.png differ
diff --git a/src-ui/utils.js b/src-ui/utils.js
index b7296f49..145dc403 100644
--- a/src-ui/utils.js
+++ b/src-ui/utils.js
@@ -31,6 +31,19 @@ export const randomIntMinMax = (min, max) => {
return int;
};
+export const randomMinMax = (min, max) => {
+ return Math.random() * (max - min) + min;
+};
+
+export const shuffleArray = (array) => {
+ const new_array = [...array];
+ for (let i = new_array.length - 1; i > 0; i--) {
+ const j = Math.floor(Math.random() * (i + 1));
+ [new_array[i], new_array[j]] = [new_array[j], new_array[i]];
+ }
+ return new_array;
+};
+
export const updateLabelsById = (data_array, updates) => {
return data_array.map(item => {
const update = updates.find(update_item => update_item.id === item.id);