[Update] Config Page: Add Supporters Section. -2024.12
@@ -85,6 +85,7 @@ config_page:
|
|||||||
vr: VR
|
vr: VR
|
||||||
others: Others
|
others: Others
|
||||||
advanced_settings: Advanced Settings
|
advanced_settings: Advanced Settings
|
||||||
|
supporters: Supporters
|
||||||
about_vrct: About VRCT
|
about_vrct: About VRCT
|
||||||
|
|
||||||
device:
|
device:
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
Others,
|
Others,
|
||||||
AdvancedSettings,
|
AdvancedSettings,
|
||||||
Vr,
|
Vr,
|
||||||
|
Supporters,
|
||||||
AboutVrct,
|
AboutVrct,
|
||||||
} from "@setting_box";
|
} from "@setting_box";
|
||||||
|
|
||||||
@@ -28,6 +29,8 @@ export const SettingBox = () => {
|
|||||||
return <Vr />;
|
return <Vr />;
|
||||||
case "advanced_settings":
|
case "advanced_settings":
|
||||||
return <AdvancedSettings />;
|
return <AdvancedSettings />;
|
||||||
|
case "supporters":
|
||||||
|
return <Supporters />;
|
||||||
case "about_vrct":
|
case "about_vrct":
|
||||||
return <AboutVrct />;
|
return <AboutVrct />;
|
||||||
|
|
||||||
|
|||||||
@@ -6,3 +6,4 @@ export { Others, VrcMicMuteSyncContainer } from "./others/Others";
|
|||||||
export { AdvancedSettings } from "./advanced_settings/AdvancedSettings";
|
export { AdvancedSettings } from "./advanced_settings/AdvancedSettings";
|
||||||
export { Vr } from "./vr/Vr";
|
export { Vr } from "./vr/Vr";
|
||||||
export { AboutVrct } from "./about_vrct/AboutVrct";
|
export { AboutVrct } from "./about_vrct/AboutVrct";
|
||||||
|
export { Supporters } from "./supporters/Supporters";
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
import styles from "./Supporters.module.scss";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
const mogu_count = 8;
|
||||||
|
const mochi_count = 3;
|
||||||
|
const fuwa_count = 4;
|
||||||
|
const basic_count = 5;
|
||||||
|
const former_count = 2;
|
||||||
|
const default_icon_numbers = ["05", "06", "07", "11"];
|
||||||
|
|
||||||
|
const supporters_filenames = Array.from({ length: 22 }, (_, 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 shuffleArray = (array) => {
|
||||||
|
return array
|
||||||
|
.map((value) => ({ value, sort: Math.random() }))
|
||||||
|
.sort((a, b) => a.sort - b.sort)
|
||||||
|
.map(({ value }) => value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCategoryImages = (start, count) => {
|
||||||
|
const category_images = supporters_filenames.slice(start, start + count);
|
||||||
|
return shuffleArray(category_images);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mogu_images = getCategoryImages(0, mogu_count);
|
||||||
|
const mochi_images = getCategoryImages(mogu_count, mochi_count);
|
||||||
|
const fuwa_images = getCategoryImages(mogu_count + mochi_count, fuwa_count);
|
||||||
|
const basic_images = getCategoryImages(mogu_count + mochi_count + fuwa_count, basic_count);
|
||||||
|
const former_images = getCategoryImages(mogu_count + mochi_count + fuwa_count + basic_count, former_count);
|
||||||
|
|
||||||
|
const getRandomImage = (images) => {
|
||||||
|
const random_index = Math.floor(Math.random() * images.length);
|
||||||
|
return images[random_index];
|
||||||
|
};
|
||||||
|
|
||||||
|
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`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Supporters = () => {
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<SupportUsContainer />
|
||||||
|
<SupportersContainer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const SupportUsContainer = () => {
|
||||||
|
return (
|
||||||
|
<div className={styles.support_us_container}>
|
||||||
|
<img className={styles.fanbox_img} src={fanbox_img} />
|
||||||
|
<div className={styles.support_us_button_wrapper}>
|
||||||
|
<div className={styles.fanbox_wrapper}>
|
||||||
|
<a className={styles.fanbox_button} href="https://vrct-dev.fanbox.cc/" target="_blank" rel="noreferrer" >
|
||||||
|
{/* for adjust size to their parent component's width. */}
|
||||||
|
<img style={ {height: "100%", width: "100%", "objectFit": "contain" }} src={fanbox_button} />
|
||||||
|
</a>
|
||||||
|
<p className={styles.mainly_japanese}>日本語 / Mainly Japanese</p>
|
||||||
|
</div>
|
||||||
|
<div className={styles.kofi_wrapper}>
|
||||||
|
<img className={styles.kofi_preparing} src={kofi_preparing} />
|
||||||
|
<p className={styles.mainly_english}>Mainly English</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SupportersContainer = () => {
|
||||||
|
const renderImages = (image_list, class_name) => {
|
||||||
|
return image_list.map((file_name) => {
|
||||||
|
const img_src = getSupportersImageByFileName(file_name);
|
||||||
|
const is_default_icon = default_icon_numbers.some((default_num) => file_name.endsWith(default_num));
|
||||||
|
const chato_expression_src = is_default_icon
|
||||||
|
? getChatoImageByFileName(getRandomImage(chato_expressions_filenames))
|
||||||
|
: null;
|
||||||
|
const random_delay = getRandomDelay(0.1, 6);
|
||||||
|
|
||||||
|
return img_src ? (
|
||||||
|
<div
|
||||||
|
key={file_name}
|
||||||
|
className={clsx(styles.supporter_image_wrapper, class_name)}
|
||||||
|
style={{ "--delay": random_delay }}
|
||||||
|
>
|
||||||
|
<img className={styles.supporter_image} src={img_src} />
|
||||||
|
{chato_expression_src && (
|
||||||
|
<img
|
||||||
|
className={styles.default_chato_expression_image}
|
||||||
|
src={chato_expression_src}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : null;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.supporters_container}>
|
||||||
|
<img className={styles.vrct_supporters_title} src={vrct_supporters_title} />
|
||||||
|
<p className={styles.vrct_supporters_desc}>{`VRCT3.0のアップデートに向けて、むちゃ大変な開発を支えてくれた "Early Supporters" です。\nThey are the 'Early Supporters' who supported us through the incredibly challenging development toward the VRCT3.0 update.`}</p>
|
||||||
|
<div className={styles.supporters_wrapper}>
|
||||||
|
{renderImages(mogu_images, `${styles.mogu_image}`)}
|
||||||
|
{renderImages(mochi_images)}
|
||||||
|
{renderImages(fuwa_images)}
|
||||||
|
{renderImages(basic_images)}
|
||||||
|
{renderImages(former_images)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
.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;
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ export const SidebarSection = () => {
|
|||||||
<Tab tab_id="advanced_settings" />
|
<Tab tab_id="advanced_settings" />
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.separated_tabs_wrapper}>
|
<div className={styles.separated_tabs_wrapper}>
|
||||||
|
<Tab tab_id="supporters" />
|
||||||
<Tab tab_id="about_vrct" />
|
<Tab tab_id="about_vrct" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
BIN
src-ui/assets/supporters/c_fanbox_1620x580.png
Normal file
|
After Width: | Height: | Size: 4.0 MiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
BIN
src-ui/assets/supporters/fanbox_button.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
src-ui/assets/supporters/kofi_preparing.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_01.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_02.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_03.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_04.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_05.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_06.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_07.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_08.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_09.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_10.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_11.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_12.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_13.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_14.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_15.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_16.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_17.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_18.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_19.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_20.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_21.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src-ui/assets/supporters/supporters_images/supporter_22.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src-ui/assets/supporters/vrct_supporters_title.png
Normal file
|
After Width: | Height: | Size: 14 KiB |