[Update] Config Page: Add Supporters Section. -2024.12
@@ -85,6 +85,7 @@ config_page:
|
||||
vr: VR
|
||||
others: Others
|
||||
advanced_settings: Advanced Settings
|
||||
supporters: Supporters
|
||||
about_vrct: About VRCT
|
||||
|
||||
device:
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
Others,
|
||||
AdvancedSettings,
|
||||
Vr,
|
||||
Supporters,
|
||||
AboutVrct,
|
||||
} from "@setting_box";
|
||||
|
||||
@@ -28,6 +29,8 @@ export const SettingBox = () => {
|
||||
return <Vr />;
|
||||
case "advanced_settings":
|
||||
return <AdvancedSettings />;
|
||||
case "supporters":
|
||||
return <Supporters />;
|
||||
case "about_vrct":
|
||||
return <AboutVrct />;
|
||||
|
||||
|
||||
@@ -6,3 +6,4 @@ export { Others, VrcMicMuteSyncContainer } from "./others/Others";
|
||||
export { AdvancedSettings } from "./advanced_settings/AdvancedSettings";
|
||||
export { Vr } from "./vr/Vr";
|
||||
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" />
|
||||
</div>
|
||||
<div className={styles.separated_tabs_wrapper}>
|
||||
<Tab tab_id="supporters" />
|
||||
<Tab tab_id="about_vrct" />
|
||||
</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 |