[Update] Migrate to tauri-app(Web UI)
BIN
src-ui/assets/about_vrct/contributors_github_icon.png
Normal file
|
After Width: | Height: | Size: 724 B |
BIN
src-ui/assets/about_vrct/contributors_members.png
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
src-ui/assets/about_vrct/contributors_section_title.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
src-ui/assets/about_vrct/contributors_x_icon.png
Normal file
|
After Width: | Height: | Size: 806 B |
BIN
src-ui/assets/about_vrct/dev_github_icon.png
Normal file
|
After Width: | Height: | Size: 929 B |
BIN
src-ui/assets/about_vrct/dev_misya.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
src-ui/assets/about_vrct/dev_section_title.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
src-ui/assets/about_vrct/dev_shiina.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
src-ui/assets/about_vrct/dev_x_icon.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
src-ui/assets/about_vrct/localization_members.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
src-ui/assets/about_vrct/localization_section_title.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
src-ui/assets/about_vrct/poster_showcase_section_title.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
src-ui/assets/about_vrct/project_link_booth.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
src-ui/assets/about_vrct/project_link_contact_us.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
src-ui/assets/about_vrct/project_link_documents.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
src-ui/assets/about_vrct/project_link_vrct_github.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/bar_asagao.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/cafe_cian.png
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/ikoiba.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/ippaidou.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/kimodameshi.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/kokekkopiyopiyo.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/kr_jp_exchange.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/kuroinu_work_room.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/mamehinata_dogrun.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/monogatari_meetup.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/nihongokurabu.png
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/parallel_collar.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/re_yatuha_room.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/smokerz_guild_v2.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 12 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/sushi_guru_annex.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/uj_club.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/usanezumi_shrine2.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
src-ui/assets/about_vrct/showcased_worlds/yuttari_eikaiwa.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
src-ui/assets/about_vrct/special_thanks_members.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
src-ui/assets/about_vrct/special_thanks_message_en.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src-ui/assets/about_vrct/special_thanks_message_ja.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src-ui/assets/about_vrct/special_thanks_section_title.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
src-ui/assets/about_vrct/vrchat_disclaimer.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
src-ui/assets/about_vrct/vrct_logo_for_about_vrct.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
BIN
src-ui/assets/about_vrct/vrct_posters/iya_vrct_manga_en.png
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
src-ui/assets/about_vrct/vrct_posters/iya_vrct_manga_ja.png
Normal file
|
After Width: | Height: | Size: 146 KiB |
BIN
src-ui/assets/about_vrct/vrct_posters/iya_vrct_manga_ko.png
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
src-ui/assets/about_vrct/vrct_posters/iya_vrct_poster_cn.png
Normal file
|
After Width: | Height: | Size: 107 KiB |
BIN
src-ui/assets/about_vrct/vrct_posters/iya_vrct_poster_en.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
src-ui/assets/about_vrct/vrct_posters/iya_vrct_poster_ja.png
Normal file
|
After Width: | Height: | Size: 107 KiB |
BIN
src-ui/assets/about_vrct/vrct_posters/iya_vrct_poster_ko.png
Normal file
|
After Width: | Height: | Size: 100 KiB |
1
src-ui/assets/arrow_left.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M16.67 0l2.83 2.829-9.339 9.175 9.339 9.167-2.83 2.829-12.17-11.996z"/></svg>
|
||||
|
After Width: | Height: | Size: 146 B |
BIN
src-ui/assets/chato_white.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
src-ui/assets/chato_white_square.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
1
src-ui/assets/configuration.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M24 14.187v-4.374c-2.148-.766-2.726-.802-3.027-1.529-.303-.729.083-1.169 1.059-3.223l-3.093-3.093c-2.026.963-2.488 1.364-3.224 1.059-.727-.302-.768-.889-1.527-3.027h-4.375c-.764 2.144-.8 2.725-1.529 3.027-.752.313-1.203-.1-3.223-1.059l-3.093 3.093c.977 2.055 1.362 2.493 1.059 3.224-.302.727-.881.764-3.027 1.528v4.375c2.139.76 2.725.8 3.027 1.528.304.734-.081 1.167-1.059 3.223l3.093 3.093c1.999-.95 2.47-1.373 3.223-1.059.728.302.764.88 1.529 3.027h4.374c.758-2.131.799-2.723 1.537-3.031.745-.308 1.186.099 3.215 1.062l3.093-3.093c-.975-2.05-1.362-2.492-1.059-3.223.3-.726.88-.763 3.027-1.528zm-4.875.764c-.577 1.394-.068 2.458.488 3.578l-1.084 1.084c-1.093-.543-2.161-1.076-3.573-.49-1.396.581-1.79 1.693-2.188 2.877h-1.534c-.398-1.185-.791-2.297-2.183-2.875-1.419-.588-2.507-.045-3.579.488l-1.083-1.084c.557-1.118 1.066-2.18.487-3.58-.579-1.391-1.691-1.784-2.876-2.182v-1.533c1.185-.398 2.297-.791 2.875-2.184.578-1.394.068-2.459-.488-3.579l1.084-1.084c1.082.538 2.162 1.077 3.58.488 1.392-.577 1.785-1.69 2.183-2.875h1.534c.398 1.185.792 2.297 2.184 2.875 1.419.588 2.506.045 3.579-.488l1.084 1.084c-.556 1.121-1.065 2.187-.488 3.58.577 1.391 1.689 1.784 2.875 2.183v1.534c-1.188.398-2.302.791-2.877 2.183zm-7.125-5.951c1.654 0 3 1.346 3 3s-1.346 3-3 3-3-1.346-3-3 1.346-3 3-3zm0-2c-2.762 0-5 2.238-5 5s2.238 5 5 5 5-2.238 5-5-2.238-5-5-5z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
1
src-ui/assets/foreground.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7 0h4v2h-4v-2zm9 2v3h2v-5h-5v2h3zm-16 9h2v-4h-2v4zm4 5h-2v-3h-2v5h4v-2zm-2-11v-3h3v-2h-5v5h2zm22 2v17h-18v-17h18zm-2 5h-14v10h14v-10z"/></svg>
|
||||
|
After Width: | Height: | Size: 212 B |
1
src-ui/assets/headphones.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6 23v-11c-4.036 0-6 2.715-6 5.5 0 2.807 1.995 5.5 6 5.5zm18-5.5c0-2.785-1.964-5.5-6-5.5v11c4.005 0 6-2.693 6-5.5zm-12-13.522c-3.879-.008-6.861 2.349-7.743 6.195-.751.145-1.479.385-2.161.716.629-5.501 4.319-9.889 9.904-9.889 5.589 0 9.29 4.389 9.916 9.896-.684-.334-1.415-.575-2.169-.721-.881-3.85-3.867-6.205-7.747-6.197z"/></svg>
|
||||
|
After Width: | Height: | Size: 400 B |
1
src-ui/assets/help.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm1.25 17c0 .69-.559 1.25-1.25 1.25-.689 0-1.25-.56-1.25-1.25s.561-1.25 1.25-1.25c.691 0 1.25.56 1.25 1.25zm1.393-9.998c-.608-.616-1.515-.955-2.551-.955-2.18 0-3.59 1.55-3.59 3.95h2.011c0-1.486.829-2.013 1.538-2.013.634 0 1.307.421 1.364 1.226.062.847-.39 1.277-.962 1.821-1.412 1.343-1.438 1.993-1.432 3.468h2.005c-.013-.664.03-1.203.935-2.178.677-.73 1.519-1.638 1.536-3.022.011-.924-.284-1.719-.854-2.297z"/></svg>
|
||||
|
After Width: | Height: | Size: 634 B |
1
src-ui/assets/mic.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2c1.103 0 2 .897 2 2v7c0 1.103-.897 2-2 2s-2-.897-2-2v-7c0-1.103.897-2 2-2zm0-2c-2.209 0-4 1.791-4 4v7c0 2.209 1.791 4 4 4s4-1.791 4-4v-7c0-2.209-1.791-4-4-4zm8 9v2c0 4.418-3.582 8-8 8s-8-3.582-8-8v-2h2v2c0 3.309 2.691 6 6 6s6-2.691 6-6v-2h2zm-7 13v-2h-2v2h-4v2h10v-2h-4z"/></svg>
|
||||
|
After Width: | Height: | Size: 353 B |
1
src-ui/assets/narrow_arrow_down.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill-rule="evenodd" clip-rule="evenodd"><path d="M11 21.883l-6.235-7.527-.765.644 7.521 9 7.479-9-.764-.645-6.236 7.529v-21.884h-1v21.883z"/></svg>
|
||||
|
After Width: | Height: | Size: 207 B |
1
src-ui/assets/send_message.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M24 0l-6 22-8.129-7.239 7.802-8.234-10.458 7.227-7.215-1.754 24-12zm-15 16.668v7.332l3.258-4.431-3.258-2.901z"/></svg>
|
||||
|
After Width: | Height: | Size: 187 B |
1
src-ui/assets/translation.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21 21h-1.713l-.658-1.846h-3l-.663 1.846h-1.659l3.04-8h1.603l3.05 8zm-2.814-3.12l-1.049-3.018-1.054 3.018h2.103zm-9.464-12.037l.125-.562-1.02-.199-.101.464c-.345-.05-.712-.057-1.083-.019.009-.249.023-.494.045-.728h1.141v-.966h-1.004c.049-.246.092-.394.134-.533l-.997-.3c-.072.245-.134.484-.195.833h-1.138v.966h1.014c-.027.312-.043.637-.048.964-1.119.411-1.595 1.195-1.595 1.905 0 .84.663 1.578 1.709 1.482 1.301-.118 2.169-1.1 2.679-2.308.525.303.746.814.548 1.286-.185.436-.725.852-1.757.831v1.041c1.146.018 2.272-.417 2.715-1.469.431-1.028-.062-2.151-1.172-2.688zm-1.342.71c-.162.36-.375.717-.648.998-.041-.3-.07-.628-.086-.978.249-.032.499-.038.734-.02zm-1.758.336c.028.44.078.844.148 1.205-.927.169-.963-.744-.148-1.205zm15.378 5.111c.552 0 1 .449 1 1v8c0 .551-.448 1-1 1h-8c-.552 0-1-.449-1-1v-8c0-.551.448-1 1-1h8zm0-2h-8c-1.656 0-3 1.343-3 3v8c0 1.657 1.344 3 3 3h8c1.657 0 3-1.343 3-3v-8c0-1.657-1.343-3-3-3zm-13 3c0-.342.035-.677.102-1h-5.102c-.552 0-1-.449-1-1v-8c0-.551.448-1 1-1h8c.552 0 1 .449 1 1v5.101c.323-.066.657-.101 1-.101h1v-5c0-1.657-1.343-3-3-3h-8c-1.656 0-3 1.343-3 3v8c0 1.657 1.344 3 3 3h5v-1z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
BIN
src-ui/assets/vrct_logo_for_dark_mode.png
Normal file
|
After Width: | Height: | Size: 197 KiB |
190
src-ui/store.js
Normal file
@@ -0,0 +1,190 @@
|
||||
import {
|
||||
atom,
|
||||
useAtomValue,
|
||||
useSetAtom
|
||||
} from "jotai";
|
||||
|
||||
import { translator_list, generateTestData } from "@data";
|
||||
|
||||
export const store = {
|
||||
backend_subprocess: null,
|
||||
config_window: null,
|
||||
log_box_ref: null,
|
||||
};
|
||||
|
||||
const createAtomWithHook = (initialValue, property_names) => {
|
||||
const atomInstance = atom(initialValue);
|
||||
|
||||
const useHook = () => {
|
||||
const currentAtom = useAtomValue(atomInstance);
|
||||
|
||||
const setAtom = useSetAtom(atomInstance);
|
||||
|
||||
const updateAtom = (value) => {
|
||||
setAtom(value);
|
||||
};
|
||||
|
||||
const addAtom = (value) => {
|
||||
setAtom((old_value) => [...old_value, value]);
|
||||
};
|
||||
|
||||
return {
|
||||
[property_names.current]: currentAtom,
|
||||
[property_names.update]: updateAtom,
|
||||
[property_names.add]: addAtom,
|
||||
};
|
||||
};
|
||||
|
||||
return { atomInstance, useHook };
|
||||
};
|
||||
|
||||
import { loadable } from "jotai/utils";
|
||||
const createAsyncAtomWithHook = (initialValue, property_names) => {
|
||||
const atomInstance = atom(initialValue);
|
||||
const asyncAtom = atom(async (get) => get(atomInstance));
|
||||
|
||||
const loadableAtom = loadable(asyncAtom);
|
||||
|
||||
const useHook = () => {
|
||||
const asyncCurrentAtom = useAtomValue(loadableAtom);
|
||||
// const currentAtom = useAtomValue(atomInstance);
|
||||
|
||||
const setAtom = useSetAtom(atomInstance);
|
||||
const updateAtom = (value) => {
|
||||
setAtom(value);
|
||||
};
|
||||
|
||||
const asyncSetAtom = useSetAtom(atom(null, async (get, set, payloadAsyncFunc, ...args) => {
|
||||
set(atomInstance, payloadAsyncFunc(...args));
|
||||
}));
|
||||
const asyncUpdateAtom = async (asyncFunction, ...args) => {
|
||||
asyncSetAtom(asyncFunction, ...args);
|
||||
};
|
||||
|
||||
const addAtom = (value) => {
|
||||
setAtom((old_value) => [...old_value, value]);
|
||||
};
|
||||
const asyncAddAtom = useSetAtom(atom(null, async (get, set, payloadAsyncFunc, ...args) => {
|
||||
const ald_value = await get(atomInstance);
|
||||
set(atomInstance, payloadAsyncFunc([...ald_value, ...args]));
|
||||
}));
|
||||
|
||||
return {
|
||||
[property_names.current]: asyncCurrentAtom,
|
||||
[property_names.update]: updateAtom,
|
||||
[property_names.async_update]: asyncUpdateAtom,
|
||||
[property_names.add]: addAtom,
|
||||
[property_names.async_add]: asyncAddAtom,
|
||||
};
|
||||
};
|
||||
|
||||
return { atomInstance, useHook };
|
||||
};
|
||||
|
||||
export const { atomInstance: uiLanguage, useHook: useUiLanguage } = createAtomWithHook("en", {
|
||||
current: "currentUiLanguage",
|
||||
update: "updateUiLanguage",
|
||||
});
|
||||
|
||||
|
||||
export const { atomInstance: State_Translation, useHook: useState_Translation } = createAsyncAtomWithHook(false, {
|
||||
current: "currentState_Translation",
|
||||
update: "updateState_Translation",
|
||||
async_update: "asyncUpdateState_Translation",
|
||||
});
|
||||
export const { atomInstance: State_TranscriptionSend, useHook: useState_TranscriptionSend } = createAsyncAtomWithHook(false, {
|
||||
current: "currentState_TranscriptionSend",
|
||||
update: "updateState_TranscriptionSend",
|
||||
async_update: "asyncUpdateState_TranscriptionSend",
|
||||
});
|
||||
export const { atomInstance: State_TranscriptionReceive, useHook: useState_TranscriptionReceive } = createAsyncAtomWithHook(false, {
|
||||
current: "currentState_TranscriptionReceive",
|
||||
update: "updateState_TranscriptionReceive",
|
||||
async_update: "asyncUpdateState_TranscriptionReceive",
|
||||
});
|
||||
export const { atomInstance: State_Foreground, useHook: useState_Foreground } = createAsyncAtomWithHook(false, {
|
||||
current: "currentState_Foreground",
|
||||
update: "updateState_Foreground",
|
||||
async_update: "asyncUpdateState_Foreground",
|
||||
});
|
||||
|
||||
|
||||
|
||||
export const { atomInstance: messageLogs, useHook: useMessageLogs } = createAtomWithHook(generateTestData(20), {
|
||||
current: "currentMessageLogs",
|
||||
update: "updateMessageLogs",
|
||||
add: "addMessageLogs",
|
||||
});
|
||||
|
||||
export const { atomInstance: isCompactMode, useHook: useIsCompactMode } = createAtomWithHook(false, {
|
||||
current: "currentIsCompactMode",
|
||||
update: "updateIsCompactMode",
|
||||
});
|
||||
|
||||
export const { atomInstance: isOpenedLanguageSelector, useHook: useIsOpenedLanguageSelector } = createAtomWithHook(
|
||||
{ your_language: false, target_language: false },
|
||||
{
|
||||
current: "currentIsOpenedLanguageSelector",
|
||||
update: "updateIsOpenedLanguageSelector",
|
||||
}
|
||||
);
|
||||
|
||||
export const { atomInstance: selectedTab, useHook: useSelectedTab } = createAtomWithHook(1, {
|
||||
current: "currentSelectedTab",
|
||||
update: "updateSelectedTab",
|
||||
});
|
||||
|
||||
|
||||
export const { atomInstance: isOpenedConfigWindow, useHook: useIsOpenedConfigWindow } = createAtomWithHook(false, {
|
||||
current: "currentIsOpenedConfigWindow",
|
||||
update: "updateIsOpenedConfigWindow",
|
||||
} );
|
||||
|
||||
export const { atomInstance: selectedConfigTab, useHook: useSelectedConfigTab } = createAtomWithHook("appearance", {
|
||||
current: "currentSelectedConfigTab",
|
||||
update: "updateSelectedConfigTab",
|
||||
});
|
||||
|
||||
export const { atomInstance: openedDropdownMenu, useHook: useOpenedDropdownMenu } = createAtomWithHook("", {
|
||||
current: "currentOpenedDropdownMenu",
|
||||
update: "updateOpenedDropdownMenu",
|
||||
});
|
||||
|
||||
|
||||
export const { atomInstance: selectedMicDevice, useHook: useSelectedMicDevice } = createAsyncAtomWithHook("device b", {
|
||||
current: "currentSelectedMicDevice",
|
||||
update: "updateSelectedMicDevice",
|
||||
});
|
||||
const test_list = {
|
||||
a: "Device A",
|
||||
"device b": "Device B",
|
||||
};
|
||||
export const { atomInstance: micDeviceList, useHook: useMicDeviceList } = createAtomWithHook(test_list, {
|
||||
current: "currentMicDeviceList",
|
||||
update: "updateMicDeviceList",
|
||||
});
|
||||
|
||||
export const { atomInstance: translatorList, useHook: useTranslatorList } = createAtomWithHook(translator_list, {
|
||||
current: "currentTranslatorList",
|
||||
update: "updateTranslatorList",
|
||||
});
|
||||
|
||||
export const { atomInstance: selectedTranslator, useHook: useSelectedTranslator } = createAtomWithHook("CTranslate2", {
|
||||
current: "currentSelectedTranslator",
|
||||
update: "updateSelectedTranslator",
|
||||
});
|
||||
|
||||
export const { atomInstance: openedTranslatorSelector, useHook: useOpenedTranslatorSelector } = createAtomWithHook(false, {
|
||||
current: "currentOpenedTranslatorSelector",
|
||||
update: "updateOpenedTranslatorSelector",
|
||||
});
|
||||
|
||||
export const { atomInstance: vrctPosterIndex, useHook: useVrctPosterIndex } = createAtomWithHook(0, {
|
||||
current: "currentVrctPosterIndex",
|
||||
update: "updateVrctPosterIndex",
|
||||
});
|
||||
|
||||
export const { atomInstance: posterShowcaseWorldPageIndex, useHook: usePosterShowcaseWorldPageIndex } = createAtomWithHook(0, {
|
||||
current: "currentPosterShowcaseWorldPageIndex",
|
||||
update: "updatePosterShowcaseWorldPageIndex",
|
||||
});
|
||||
7
src-ui/utils/chunkArray.js
Normal file
@@ -0,0 +1,7 @@
|
||||
export const chunkArray = (array, size) => {
|
||||
const chunked = [];
|
||||
for (let i = 0; i < array.length; i += size) {
|
||||
chunked.push(array.slice(i, i + size));
|
||||
}
|
||||
return chunked;
|
||||
};
|
||||
27
src-ui/utils/logics/scrollToBottom.js
Normal file
@@ -0,0 +1,27 @@
|
||||
export const scrollToBottom = (ref, smooth = false) => {
|
||||
const element = ref.current;
|
||||
const scroll_height = element.scrollHeight - element.clientHeight;
|
||||
|
||||
if (smooth) {
|
||||
const duration = 300; // スクロールにかける時間(ミリ秒)
|
||||
const start_time = performance.now();
|
||||
const scroll_top = element.scrollTop;
|
||||
|
||||
const scroll = (current_time) => {
|
||||
const elapsed = current_time - start_time;
|
||||
const progress = Math.min(elapsed / duration, 1);
|
||||
const ease_in_out_quad = (t) => t < 0.5
|
||||
? 2 * t * t
|
||||
: -1 + (4 - 2 * t) * t;
|
||||
element.scrollTop = scroll_top + (scroll_height - scroll_top) * ease_in_out_quad(progress);
|
||||
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(scroll);
|
||||
}
|
||||
};
|
||||
|
||||
requestAnimationFrame(scroll);
|
||||
} else {
|
||||
element.scrollTop = scroll_height;
|
||||
}
|
||||
};
|
||||
81
src-ui/utils/logics/useMainFunction.js
Normal file
@@ -0,0 +1,81 @@
|
||||
import { getCurrent } from "@tauri-apps/api/window";
|
||||
|
||||
import {
|
||||
useState_Translation,
|
||||
useState_TranscriptionSend,
|
||||
useState_TranscriptionReceive,
|
||||
useState_Foreground,
|
||||
} from "@store";
|
||||
|
||||
import { useStdoutToPython } from "./useStdoutToPython";
|
||||
|
||||
export const useMainFunction = () => {
|
||||
const {
|
||||
currentState_Translation,
|
||||
updateState_Translation,
|
||||
asyncUpdateState_Translation,
|
||||
} = useState_Translation();
|
||||
const {
|
||||
currentState_TranscriptionSend,
|
||||
updateState_TranscriptionSend,
|
||||
asyncUpdateState_TranscriptionSend,
|
||||
} = useState_TranscriptionSend();
|
||||
const {
|
||||
currentState_TranscriptionReceive,
|
||||
updateState_TranscriptionReceive,
|
||||
asyncUpdateState_TranscriptionReceive,
|
||||
} = useState_TranscriptionReceive();
|
||||
const {
|
||||
currentState_Foreground,
|
||||
updateState_Foreground,
|
||||
} = useState_Foreground();
|
||||
|
||||
const { asyncStdoutToPython } = useStdoutToPython();
|
||||
|
||||
const asyncPending = () => new Promise(() => {});
|
||||
return {
|
||||
toggleTranslation: () => {
|
||||
asyncStdoutToPython({id: "/controller/callback_toggle_translation", data: !currentState_Translation.data});
|
||||
asyncUpdateState_Translation(asyncPending);
|
||||
},
|
||||
currentState_Translation: currentState_Translation,
|
||||
updateState_Translation: (payload) => {
|
||||
updateState_Translation(payload.data);
|
||||
},
|
||||
|
||||
toggleTranscriptionSend: () => {
|
||||
asyncStdoutToPython({id: "/controller/callback_toggle_transcription_send", data: !currentState_TranscriptionSend.data});
|
||||
asyncUpdateState_TranscriptionSend(asyncPending);
|
||||
},
|
||||
currentState_TranscriptionSend: currentState_TranscriptionSend,
|
||||
updateState_TranscriptionSend: (payload) => {
|
||||
updateState_TranscriptionSend(payload.data);
|
||||
},
|
||||
|
||||
toggleTranscriptionReceive: () => {
|
||||
asyncStdoutToPython({id: "/controller/callback_toggle_transcription_receive", data: !currentState_TranscriptionReceive.data});
|
||||
asyncUpdateState_TranscriptionReceive(asyncPending);
|
||||
},
|
||||
currentState_TranscriptionReceive: currentState_TranscriptionReceive,
|
||||
updateState_TranscriptionReceive: (payload) => {
|
||||
updateState_TranscriptionReceive(payload.data);
|
||||
},
|
||||
|
||||
toggleForeground: () => {
|
||||
const main_window = getCurrent();
|
||||
const is_foreground_enabled = !currentState_Foreground.data;
|
||||
main_window.setAlwaysOnTop(is_foreground_enabled);
|
||||
updateState_Foreground(is_foreground_enabled);
|
||||
|
||||
},
|
||||
currentState_Foreground: currentState_Foreground,
|
||||
};
|
||||
};
|
||||
|
||||
const asyncTestFunction = (...args) => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(...args);
|
||||
}, 3000);
|
||||
});
|
||||
};
|
||||
55
src-ui/utils/logics/useMessage.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import {
|
||||
useMessageLogs,
|
||||
} from "@store";
|
||||
|
||||
import { useStdoutToPython } from "./useStdoutToPython";
|
||||
|
||||
export const useMessage = () => {
|
||||
const { currentMessageLogs, addMessageLogs, updateMessageLogs } = useMessageLogs();
|
||||
const { asyncStdoutToPython } = useStdoutToPython();
|
||||
|
||||
return {
|
||||
sendMessage: (message) => {
|
||||
asyncStdoutToPython({id: "send_message", data: message});
|
||||
const uuid = crypto.randomUUID();
|
||||
const date = new Date().toLocaleTimeString(
|
||||
"ja-JP",
|
||||
{hour12: false, hour: "2-digit", minute:"2-digit"},
|
||||
);
|
||||
|
||||
addMessageLogs({
|
||||
id: uuid,
|
||||
category: "sent",
|
||||
status: "pending",
|
||||
created_at: date,
|
||||
messages: {
|
||||
original: message,
|
||||
translated: [
|
||||
message,
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
const updateItemById = (id) => (prevItems) => {
|
||||
return prevItems.map(item => {
|
||||
if (item.id === id) {
|
||||
item.status = "ok";
|
||||
}
|
||||
return item;
|
||||
});
|
||||
};
|
||||
updateMessageLogs(updateItemById(uuid));
|
||||
}, 3000);
|
||||
},
|
||||
currentMessageLogs: currentMessageLogs,
|
||||
};
|
||||
};
|
||||
|
||||
// const asyncTestFunction = (...args) => {
|
||||
// return new Promise((resolve) => {
|
||||
// setTimeout(() => {
|
||||
// resolve(...args);
|
||||
// }, 3000);
|
||||
// });
|
||||
// };
|
||||
53
src-ui/utils/logics/useStartPython.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import { Command } from "@tauri-apps/api/shell";
|
||||
import { store } from "@store";
|
||||
|
||||
import { useMainFunction } from "./useMainFunction";
|
||||
|
||||
export const useStartPython = () => {
|
||||
const {
|
||||
updateState_Translation,
|
||||
updateState_TranscriptionSend,
|
||||
updateState_TranscriptionReceive,
|
||||
} = useMainFunction();
|
||||
|
||||
const routes = {
|
||||
"/controller/callback_toggle_translation": updateState_Translation,
|
||||
"/controller/callback_toggle_transcription_send": updateState_TranscriptionSend,
|
||||
"/controller/callback_toggle_transcription_receive": updateState_TranscriptionReceive,
|
||||
};
|
||||
|
||||
const receiveRoutes = (parsed_data) => {
|
||||
if (parsed_data.status === "ok") {
|
||||
const route = routes[parsed_data.id];
|
||||
if (route) {
|
||||
route({ data: parsed_data.data });
|
||||
} else {
|
||||
console.error(`Invalid path: ${parsed_data.id}`);
|
||||
}
|
||||
} else {
|
||||
console.log("Received data status is not 'ok'.", parsed_data);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const asyncStartPython = async () => {
|
||||
const command = Command.sidecar("bin/test");
|
||||
command.on("error", error => console.error(`error: "${error}"`));
|
||||
command.stdout.on("data", (line) => {
|
||||
let parsed_data = "";
|
||||
try {
|
||||
parsed_data = JSON.parse(line);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
parsed_data = line;
|
||||
}
|
||||
console.log("from python:", parsed_data);
|
||||
receiveRoutes(parsed_data);
|
||||
});
|
||||
command.stderr.on("data", line => console.error("stderr:", line));
|
||||
const backend_subprocess = await command.spawn();
|
||||
store.backend_subprocess = backend_subprocess;
|
||||
};
|
||||
|
||||
return { asyncStartPython };
|
||||
};
|
||||
17
src-ui/utils/logics/useStdoutToPython.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { store } from "@store";
|
||||
|
||||
export const useStdoutToPython = () => {
|
||||
const asyncStdoutToPython = async (value) => {
|
||||
// send to python
|
||||
const backend_subprocess = store.backend_subprocess;
|
||||
if (backend_subprocess) {
|
||||
await backend_subprocess.write(JSON.stringify(value) + "\n").then(() => {
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
} else {
|
||||
console.error("Backend subprocess is not found.", backend_subprocess);
|
||||
}
|
||||
};
|
||||
return { asyncStdoutToPython };
|
||||
};
|
||||
107
src-ui/utils/mixins.scss
Normal file
@@ -0,0 +1,107 @@
|
||||
// デフォルト変数
|
||||
$default_loader_size: 2rem !default;
|
||||
$default_loader_line_width: 0.2rem !default;
|
||||
|
||||
// Loader Mixin
|
||||
@mixin loader($loader_size: $default_loader_size, $loader_line_width: $default_loader_line_width, $position: right, $position_amount: 0) {
|
||||
$half_line_width: calc($loader_line_width / 2);
|
||||
$calc_translate: calc(-50% + #{$half_line_width});
|
||||
|
||||
position: absolute;
|
||||
top: calc(50% - #{$half_line_width});
|
||||
#{$position}: $position_amount;
|
||||
transform: translate($calc_translate, $calc_translate);
|
||||
width: $loader_size;
|
||||
height: $loader_size;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
border-top: $loader_line_width solid var(--dark_400_color);
|
||||
border-right: $loader_line_width solid transparent;
|
||||
animation: rotate_animation 0.6s linear infinite;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: $loader_size;
|
||||
height: $loader_size;
|
||||
border-radius: 50%;
|
||||
border-bottom: $loader_line_width solid var(--primary_400_color);
|
||||
border-left: $loader_line_width solid transparent;
|
||||
}
|
||||
|
||||
// @keyframes
|
||||
@keyframes rotate_animation {
|
||||
0% {
|
||||
transform: translate($calc_translate, $calc_translate) rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: translate($calc_translate, $calc_translate) rotate(360deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
$toggle_background_color_on: var(--primary_400_color);
|
||||
$toggle_background_color_off: var(--dark_775_color);
|
||||
$toggle_control_color: var(--dark_400_color);
|
||||
$toggle_width: 4rem;
|
||||
$toggle_height: 1.6rem;
|
||||
$toggle_gutter: 0.1rem;
|
||||
$toggle_radius: 50%;
|
||||
$toggle_control_speed: .15s;
|
||||
$toggle_control_ease: ease-out;
|
||||
|
||||
$toggle_radius: calc($toggle_height / 2);
|
||||
$toggle_control_size: $toggle_height - calc($toggle_gutter * 2);
|
||||
|
||||
@mixin toggle_control_styles {
|
||||
display: block;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: auto;
|
||||
padding-left: $toggle_width;
|
||||
.control {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: $toggle_height;
|
||||
width: $toggle_width;
|
||||
border-radius: $toggle_radius;
|
||||
background-color: $toggle_background_color_off;
|
||||
// transition: background-color $toggle_control_speed $toggle_control_ease;
|
||||
&:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: $toggle_gutter;
|
||||
top: $toggle_gutter;
|
||||
width: $toggle_control_size;
|
||||
height: $toggle_control_size;
|
||||
border-radius: $toggle_radius;
|
||||
background: $toggle_control_color;
|
||||
transition: left $toggle_control_speed $toggle_control_ease;
|
||||
}
|
||||
&.is_hovered {
|
||||
background-color: var(--dark_725_color);
|
||||
}
|
||||
&.is_mouse_down {
|
||||
background-color: var(--dark_825_color);
|
||||
}
|
||||
&.is_active {
|
||||
background-color: $toggle_background_color_on;
|
||||
&.is_hovered {
|
||||
background-color: var(--primary_350_color);
|
||||
}
|
||||
&.is_mouse_down {
|
||||
background-color: var(--primary_700_color);
|
||||
}
|
||||
&:after {
|
||||
left: $toggle_width - $toggle_control_size - $toggle_gutter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.toggle_control {
|
||||
@include toggle_control_styles;
|
||||
}
|
||||
9
src-ui/utils/randomIntMinMax.js
Normal file
@@ -0,0 +1,9 @@
|
||||
export const randomIntMinMax = (min, max) => {
|
||||
if (min === max) return min;
|
||||
if (max === undefined) {
|
||||
max = min;
|
||||
min = 0;
|
||||
}
|
||||
const int = Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
return int;
|
||||
};
|
||||
418
src-ui/utils/reset.css
Normal file
@@ -0,0 +1,418 @@
|
||||
/*! destyle.css v4.0.1 | MIT License | https://github.com/nicolas-cusan/destyle.css */
|
||||
|
||||
/* Reset box-model and set borders */
|
||||
/* ============================================ */
|
||||
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
box-sizing: border-box;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* Document */
|
||||
/* ============================================ */
|
||||
|
||||
/**
|
||||
* 1. Correct the line height in all browsers.
|
||||
* 2. Prevent adjustments of font size after orientation changes in iOS.
|
||||
* 3. Remove gray overlay on links for iOS.
|
||||
*/
|
||||
|
||||
html {
|
||||
line-height: 1.15; /* 1 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
-webkit-tap-highlight-color: transparent; /* 3*/
|
||||
}
|
||||
|
||||
/* Sections */
|
||||
/* ============================================ */
|
||||
|
||||
/**
|
||||
* Remove the margin in all browsers.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the `main` element consistently in IE.
|
||||
*/
|
||||
|
||||
main {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Vertical rhythm */
|
||||
/* ============================================ */
|
||||
|
||||
p,
|
||||
table,
|
||||
blockquote,
|
||||
address,
|
||||
pre,
|
||||
iframe,
|
||||
form,
|
||||
figure,
|
||||
dl {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Headings */
|
||||
/* ============================================ */
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: inherit;
|
||||
font-weight: inherit;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Lists (enumeration) */
|
||||
/* ============================================ */
|
||||
|
||||
ul,
|
||||
ol {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
/* Lists (definition) */
|
||||
/* ============================================ */
|
||||
|
||||
dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
/* Grouping content */
|
||||
/* ============================================ */
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in Firefox.
|
||||
* 2. Show the overflow in Edge and IE.
|
||||
*/
|
||||
|
||||
hr {
|
||||
box-sizing: content-box; /* 1 */
|
||||
height: 0; /* 1 */
|
||||
overflow: visible; /* 2 */
|
||||
border-top-width: 1px;
|
||||
margin: 0;
|
||||
clear: both;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: inherit; /* 2 */
|
||||
}
|
||||
|
||||
address {
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/* Text-level semantics */
|
||||
/* ============================================ */
|
||||
|
||||
/**
|
||||
* Remove the gray background on active links in IE 10.
|
||||
*/
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Remove the bottom border in Chrome 57-
|
||||
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
text-decoration: underline dotted; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: inherit; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||
* all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
/* Replaced content */
|
||||
/* ============================================ */
|
||||
|
||||
/**
|
||||
* Prevent vertical alignment issues.
|
||||
*/
|
||||
|
||||
svg,
|
||||
img,
|
||||
embed,
|
||||
object,
|
||||
iframe {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
/* Forms */
|
||||
/* ============================================ */
|
||||
|
||||
/**
|
||||
* Reset form fields to make them styleable.
|
||||
* 1. Make form elements stylable across systems iOS especially.
|
||||
* 2. Inherit text-transform from parent.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
-webkit-appearance: none; /* 1 */
|
||||
appearance: none;
|
||||
vertical-align: middle;
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
text-align: inherit;
|
||||
text-transform: inherit; /* 2 */
|
||||
|
||||
/* Customize */
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct cursors for clickable elements.
|
||||
*/
|
||||
|
||||
button,
|
||||
[type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:disabled,
|
||||
[type="button"]:disabled,
|
||||
[type="reset"]:disabled,
|
||||
[type="submit"]:disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Improve outlines for Firefox and unify style with input elements & buttons.
|
||||
*/
|
||||
|
||||
:-moz-focusring {
|
||||
outline: auto;
|
||||
}
|
||||
|
||||
select:disabled {
|
||||
opacity: inherit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove padding
|
||||
*/
|
||||
|
||||
option {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset to invisible
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||
*/
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the default vertical scrollbar in IE 10+.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||
*/
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the outline style in Safari.
|
||||
*/
|
||||
|
||||
[type="search"] {
|
||||
outline-offset: -2px; /* 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner padding in Chrome and Safari on macOS.
|
||||
*/
|
||||
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||
* 2. Fix font inheritance.
|
||||
*/
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix appearance for Firefox
|
||||
*/
|
||||
[type="number"] {
|
||||
appearance: textfield;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clickable labels
|
||||
*/
|
||||
|
||||
label[for] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Interactive */
|
||||
/* ============================================ */
|
||||
|
||||
/*
|
||||
* Add the correct display in Edge, IE 10+, and Firefox.
|
||||
*/
|
||||
|
||||
details {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the correct display in all browsers.
|
||||
*/
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove outline for editable content.
|
||||
*/
|
||||
|
||||
[contenteditable]:focus {
|
||||
outline: auto;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
/* ============================================ */
|
||||
|
||||
/**
|
||||
1. Correct table border color inheritance in all Chrome and Safari.
|
||||
*/
|
||||
|
||||
table {
|
||||
border-color: inherit; /* 1 */
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
vertical-align: top;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
}
|
||||
40
src-ui/utils/root.css
Normal file
@@ -0,0 +1,40 @@
|
||||
@import "./reset.css";
|
||||
@import "./variables.css";
|
||||
|
||||
:root {
|
||||
font-size: 62.5%;
|
||||
color: #F2F2F2;
|
||||
font-family: "Yu Gothic UI";
|
||||
}
|
||||
|
||||
* {
|
||||
&::-webkit-scrollbar {
|
||||
width: 0.8rem;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background-color: var(--dark_925_color);
|
||||
border-radius: 0.4rem;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: var(--dark_800_color);
|
||||
border-radius: 0.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
p, img, button {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
#root {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* SVG内のすべての要素にfillを適用 (colorの調整をcssでするため) */
|
||||
svg {
|
||||
fill: currentColor;
|
||||
}
|
||||
9
src-ui/utils/useSvg.jsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import React from "react";
|
||||
|
||||
export const useSvg = (svg_component, ...props) => {
|
||||
const svgWithClass = svg_component
|
||||
? React.cloneElement(svg_component, ...props)
|
||||
: null;
|
||||
|
||||
return svgWithClass;
|
||||
};
|
||||
43
src-ui/utils/useWindow.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import { WebviewWindow } from "@tauri-apps/api/window";
|
||||
import { store, useIsOpenedConfigWindow } from "@store";
|
||||
import { getCurrent } from "@tauri-apps/api/window";
|
||||
|
||||
export const useWindow = () => {
|
||||
const { updateIsOpenedConfigWindow } = useIsOpenedConfigWindow();
|
||||
|
||||
const createConfigWindow = async () => {
|
||||
const main_window = getCurrent();
|
||||
if (store.config_window === null) {
|
||||
const config_window = new WebviewWindow("vrct_config_window",{
|
||||
url: "./src-ui/windows/config_window/index.html",
|
||||
center: true,
|
||||
width: 1080,
|
||||
height: 700,
|
||||
});
|
||||
|
||||
config_window.once("tauri://created", function () {
|
||||
store.config_window = config_window;
|
||||
updateIsOpenedConfigWindow(true);
|
||||
});
|
||||
config_window.once("tauri://error", function (e) {
|
||||
console.log(e);
|
||||
});
|
||||
|
||||
const unlisten_d = config_window.once("tauri://destroyed", (event) => {
|
||||
store.config_window = null;
|
||||
updateIsOpenedConfigWindow(false);
|
||||
unlisten_d();
|
||||
});
|
||||
|
||||
main_window.onCloseRequested((event) => {
|
||||
config_window.close();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const closeConfigWindow = () => {
|
||||
store.config_window.close();
|
||||
};
|
||||
|
||||
return { createConfigWindow, closeConfigWindow };
|
||||
};
|
||||
51
src-ui/utils/variables.css
Normal file
@@ -0,0 +1,51 @@
|
||||
:root {
|
||||
--primary_100_color: #b7ded8;
|
||||
--primary_150_color: #a1d4cc;
|
||||
--primary_200_color: #8acac0;
|
||||
--primary_250_color: #76bfb4;
|
||||
--primary_300_color: #61b4a7;
|
||||
--primary_350_color: #55ac9e;
|
||||
--primary_400_color: #48a495;
|
||||
--primary_450_color: #429c8c;
|
||||
--primary_500_color: #3b9483;
|
||||
--primary_600_color: #368777;
|
||||
--primary_650_color: #347f6f;
|
||||
--primary_700_color: #317767;
|
||||
--primary_750_color: #2f6f60;
|
||||
--primary_800_color: #2c6759;
|
||||
--primary_900_color: #214b3f;
|
||||
|
||||
--sent_400_color: #6197b4;
|
||||
--received_300_color: #a861b4;
|
||||
|
||||
--dark_basic_text_color: #f2f2f2;
|
||||
--dark_100_color: #f5f7fb;
|
||||
--dark_200_color: #f1f2f6;
|
||||
--dark_300_color: #e9eaee;
|
||||
--dark_350_color: #d8d9dd;
|
||||
--dark_400_color: #c7c8cc;
|
||||
--dark_450_color: #b8b9bd;
|
||||
--dark_500_color: #a9aaae;
|
||||
--dark_600_color: #7f8084;
|
||||
--dark_650_color: #75767a;
|
||||
--dark_700_color: #6a6c6f;
|
||||
--dark_725_color: #636467;
|
||||
--dark_750_color: #5b5c5f;
|
||||
--dark_775_color: #535457;
|
||||
--dark_800_color: #4b4c4f;
|
||||
--dark_825_color: #434447;
|
||||
--dark_850_color: #3a3b3e;
|
||||
--dark_863_color: #36373a;
|
||||
--dark_875_color: #323336;
|
||||
--dark_888_color: #2e2f32;
|
||||
--dark_900_color: #292a2d;
|
||||
--dark_925_color: #242528;
|
||||
--dark_950_color: #1f2022;
|
||||
--dark_975_color: #1a1b1d;
|
||||
--dark_1000_color: #151517;
|
||||
|
||||
|
||||
--main_window_topbar_height: 4.8rem;
|
||||
--config_window_sidebar_width: 22rem;
|
||||
--config_window_topbar_height: 5.2rem;
|
||||
}
|
||||
20
src-ui/windows/config_window/ConfigWindow.jsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import "../../../locales/config.js";
|
||||
import "@utils/root.css";
|
||||
|
||||
import styles from "./ConfigWindow.module.scss";
|
||||
|
||||
import { Topbar } from "./topbar/Topbar";
|
||||
import { SidebarSection } from "./sidebar_section/SidebarSection";
|
||||
import { SettingSection } from "./setting_section/SettingSection.jsx";
|
||||
|
||||
export const ConfigWindow = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Topbar />
|
||||
<div className={styles.main_container}>
|
||||
<SidebarSection />
|
||||
<SettingSection />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
16
src-ui/windows/config_window/ConfigWindow.module.scss
Normal file
@@ -0,0 +1,16 @@
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
background-color: var(--dark_950_color);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.main_container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
padding-top: var(--config_window_topbar_height);
|
||||
}
|
||||
14
src-ui/windows/config_window/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Config Window</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="./index.jsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
15
src-ui/windows/config_window/index.jsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
// import "../locales/config.js";
|
||||
import { ConfigWindow } from "./ConfigWindow";
|
||||
// import "./reset.css";
|
||||
// import "./root.css";
|
||||
// import { useWindow } from "@utils/useWindow";
|
||||
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")).render(
|
||||
<React.StrictMode>
|
||||
<ConfigWindow />
|
||||
</React.StrictMode>,
|
||||
);
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import styles from "./SettingSection.module.scss";
|
||||
import { SettingBox } from "./setting_box/SettingBox";
|
||||
|
||||
export const SettingSection = () => {
|
||||
return (
|
||||
<div className={styles.scroll_container}>
|
||||
<div className={styles.container}>
|
||||
<SettingBox />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
.scroll_container {
|
||||
width: 100%;
|
||||
margin-left: 4rem;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 4rem;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { useSettingBox } from "../useSettingBox";
|
||||
import { useSelectedMicDevice, useMicDeviceList } from "@store";
|
||||
export const Appearance = () => {
|
||||
const { currentSelectedMicDevice, updateSelectedMicDevice } = useSelectedMicDevice();
|
||||
const { currentMicDeviceList } = useMicDeviceList();
|
||||
const { DropdownMenuContainer } = useSettingBox();
|
||||
|
||||
const selectFunction = (selected_data) => {
|
||||
const asyncFunction = () => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(selected_data.selected_id);
|
||||
}, 3000);
|
||||
});
|
||||
};
|
||||
updateSelectedMicDevice(asyncFunction);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<DropdownMenuContainer dropdown_id="mic_host" label="Mic Host/Driver" desc="description" selected_id="b" list={{a: "A", b: "B", c: "C"}} />
|
||||
<DropdownMenuContainer dropdown_id="mic_device" label="Mic Device" desc="description" selected_id={currentSelectedMicDevice.data} list={currentMicDeviceList} selectFunction={selectFunction} state={currentSelectedMicDevice.state} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
import styles from "./SettingBox.module.scss";
|
||||
import { useSelectedConfigTab } from "@store";
|
||||
|
||||
import { Appearance } from "./appearance/Appearance";
|
||||
import { AboutVrct } from "./about_vrct/AboutVrct";
|
||||
|
||||
export const SettingBox = () => {
|
||||
const { currentSelectedConfigTab } = useSelectedConfigTab();
|
||||
switch (currentSelectedConfigTab) {
|
||||
case "appearance":
|
||||
return <Appearance />;
|
||||
case "about_vrct":
|
||||
return <AboutVrct />;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,135 @@
|
||||
import styles from "./AboutVrct.module.scss";
|
||||
import dev_section_title from "@images/about_vrct/dev_section_title.png";
|
||||
import dev_misya from "@images/about_vrct/dev_misya.png";
|
||||
import dev_shiina from "@images/about_vrct/dev_shiina.png";
|
||||
import vrct_logo_for_about_vrct from "@images/about_vrct/vrct_logo_for_about_vrct.png";
|
||||
import contributors_section_title from "@images/about_vrct/contributors_section_title.png";
|
||||
import contributors_members from "@images/about_vrct/contributors_members.png";
|
||||
import localization_section_title from "@images/about_vrct/localization_section_title.png";
|
||||
import localization_members from "@images/about_vrct/localization_members.png";
|
||||
|
||||
import special_thanks_section_title from "@images/about_vrct/special_thanks_section_title.png";
|
||||
import special_thanks_members from "@images/about_vrct/special_thanks_members.png";
|
||||
import special_thanks_message_en from "@images/about_vrct/special_thanks_message_en.png";
|
||||
import special_thanks_message_ja from "@images/about_vrct/special_thanks_message_ja.png";
|
||||
|
||||
import poster_showcase_section_title from "@images/about_vrct/poster_showcase_section_title.png";
|
||||
|
||||
import vrchat_disclaimer from "@images/about_vrct/vrchat_disclaimer.png";
|
||||
|
||||
import clsx from "clsx";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useUiLanguage } from "@store";
|
||||
import { PosterShowcaseContents } from "./poster_showcase_contents/PosterShowcaseContents";
|
||||
|
||||
export const AboutVrct = () => {
|
||||
const { t } = useTranslation();
|
||||
const { currentUiLanguage } = useUiLanguage();
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.dev_section}>
|
||||
<img src={dev_section_title} className={clsx(styles.section_title, styles.the_developers)} />
|
||||
<div className={styles.dev_section_wrapper}>
|
||||
<div className={styles.dev_card_wrapper}>
|
||||
<img src={dev_misya} className={styles.dev_card_img} />
|
||||
<OpenLinkContainer className={styles.dev_misya_x} href_id="dev_misya_x" />
|
||||
<OpenLinkContainer className={styles.dev_misya_github} href_id="dev_misya_github" />
|
||||
</div>
|
||||
<div className={styles.dev_card_wrapper}>
|
||||
<img src={dev_shiina} className={styles.dev_card_img} />
|
||||
<OpenLinkContainer className={styles.dev_shiina_x} href_id="dev_shiina_x" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.project_links_and_logo_section}>
|
||||
<img src={vrct_logo_for_about_vrct} className={styles.about_vrct_logo} />
|
||||
<div className={styles.project_links_wrapper}>
|
||||
<OpenLinkContainer className={styles.project_link} href_id="project_link_booth" />
|
||||
<OpenLinkContainer className={styles.project_link} href_id="project_link_documents" />
|
||||
<OpenLinkContainer className={styles.project_link} href_id="project_link_vrct_github" />
|
||||
<OpenLinkContainer className={styles.project_link} href_id="project_link_contact_us" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.contributors_section}>
|
||||
<img src={contributors_section_title} className={clsx(styles.section_title, styles.contributors)} />
|
||||
<div className={styles.contributors_img_wrapper}>
|
||||
<img src={contributors_members} className={clsx(styles.contributors_img, styles.contributors)} />
|
||||
<OpenLinkContainer className={styles.contributors_done_san_x} href_id="contributors_done_san_x" />
|
||||
<OpenLinkContainer className={styles.contributors_iya_x} href_id="contributors_iya_x" />
|
||||
<OpenLinkContainer className={styles.contributors_rera_x} href_id="contributors_rera_x" />
|
||||
<OpenLinkContainer className={styles.contributors_rera_github} href_id="contributors_rera_github" />
|
||||
<OpenLinkContainer className={styles.contributors_poposuke_x} href_id="contributors_poposuke_x" />
|
||||
<OpenLinkContainer className={styles.contributors_kumaguma_x} href_id="contributors_kumaguma_x" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.localization_section}>
|
||||
<img src={localization_section_title} className={clsx(styles.section_title, styles.localization)} />
|
||||
<img src={localization_members} className={clsx(styles.localization_members_img, styles.localization)} />
|
||||
</div>
|
||||
|
||||
<div className={styles.special_thanks_section}>
|
||||
<img src={special_thanks_section_title} className={clsx(styles.section_title, styles.special_thanks)} />
|
||||
<img src={special_thanks_members} className={styles.special_thanks_members_img} />
|
||||
{
|
||||
currentUiLanguage === "ja"
|
||||
? <img src={special_thanks_message_ja} className={styles.special_thanks_message_img} />
|
||||
: <img src={special_thanks_message_en} className={styles.special_thanks_message_img} />
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
<div className={styles.poster_showcase_section}>
|
||||
<img src={poster_showcase_section_title} className={clsx(styles.section_title, styles.poster_showcase)} />
|
||||
<PosterShowcaseContents />
|
||||
</div>
|
||||
|
||||
<div className={styles.vrchat_disclaimer_section}>
|
||||
<img src={vrchat_disclaimer} className={styles.vrchat_disclaimer} />
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
import dev_x_icon from "@images/about_vrct/dev_x_icon.png";
|
||||
import dev_github_icon from "@images/about_vrct/dev_github_icon.png";
|
||||
import contributors_x_icon from "@images/about_vrct/contributors_x_icon.png";
|
||||
import contributors_github_icon from "@images/about_vrct/contributors_github_icon.png";
|
||||
|
||||
import project_link_booth from "@images/about_vrct/project_link_booth.png";
|
||||
import project_link_documents from "@images/about_vrct/project_link_documents.png";
|
||||
import project_link_vrct_github from "@images/about_vrct/project_link_vrct_github.png";
|
||||
import project_link_contact_us from "@images/about_vrct/project_link_contact_us.png";
|
||||
|
||||
const about_vrct_links = {
|
||||
dev_misya_x: { img: dev_x_icon, href: "https://twitter.com/misya_ai" },
|
||||
dev_misya_github: { img: dev_github_icon, href: "https://github.com/misyaguziya" },
|
||||
dev_shiina_x: { img: dev_x_icon, href: "https://twitter.com/Shiina_12siy" },
|
||||
|
||||
project_link_booth: { img: project_link_booth, href: "https://misyaguziya.booth.pm/items/5155325" },
|
||||
project_link_documents: { img: project_link_documents, href: "https://mzsoftware.notion.site/VRCT-Documents-be79b7a165f64442ad8f326d86c22246" },
|
||||
project_link_vrct_github: { img: project_link_vrct_github, href: "https://github.com/misyaguziya/VRCT" },
|
||||
project_link_contact_us: { img: project_link_contact_us, href: "https://docs.google.com/forms/d/e/1FAIpQLSei-xoydOY60ivXqhOjaTzNN8PiBQIDcNhzfy6cw2sjYkcg_g/viewform" },
|
||||
|
||||
contributors_done_san_x: { img: contributors_x_icon, href: "https://twitter.com/done_vrc" },
|
||||
contributors_iya_x: { img: contributors_x_icon, href: "https://twitter.com/IYAA_HHHH" },
|
||||
contributors_rera_x: { img: contributors_x_icon, href: "https://twitter.com/rerassi" },
|
||||
contributors_rera_github: { img: contributors_github_icon, href: "https://github.com/soumt-r" },
|
||||
contributors_poposuke_x: { img: contributors_x_icon, href: "https://twitter.com/sig_popo" },
|
||||
contributors_kumaguma_x: { img: contributors_x_icon, href: "https://twitter.com/K_kumaguma_A" },
|
||||
};
|
||||
|
||||
const OpenLinkContainer = ({className, href_id}) => {
|
||||
const href = about_vrct_links[href_id].href;
|
||||
const img = about_vrct_links[href_id].img;
|
||||
return (
|
||||
<a className={className} href={href} target="_blank" rel="noreferrer" >
|
||||
{/* for adjust size to their parent component's width. */}
|
||||
<img style={ {height: "100%", width: "100%", "objectFit": "contain" }} src={img} />
|
||||
</a>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,171 @@
|
||||
.container {
|
||||
display: flex;
|
||||
gap: 2.2rem;
|
||||
flex-direction: column;
|
||||
width: 72rem;
|
||||
// background-color: gray;
|
||||
}
|
||||
|
||||
.section_title {
|
||||
height: 1.2rem;
|
||||
object-fit: contain;
|
||||
object-position: left;
|
||||
&.the_developers {
|
||||
margin-bottom: 0.8rem;
|
||||
}
|
||||
&.contributors {
|
||||
margin-bottom: 0.8rem;
|
||||
}
|
||||
&.special_thanks {
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
&.poster_showcase {
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
}
|
||||
|
||||
.dev_section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.dev_section_wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.dev_card_wrapper {
|
||||
width: 34.6rem;
|
||||
position: relative;
|
||||
}
|
||||
.dev_card_img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@mixin dev_sns_styles($right) {
|
||||
position: absolute;
|
||||
right: $right;
|
||||
bottom: 1.2rem;
|
||||
width: 2.8rem;
|
||||
padding: 0.4rem;
|
||||
border-radius: 0.4rem;
|
||||
&:hover {
|
||||
background-color: var(--dark_800_color);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--dark_900_color)
|
||||
}
|
||||
}
|
||||
.dev_misya_x {
|
||||
@include dev_sns_styles(6rem);
|
||||
}
|
||||
.dev_misya_github {
|
||||
@include dev_sns_styles(3rem);
|
||||
}
|
||||
.dev_shiina_x {
|
||||
@include dev_sns_styles(3rem);
|
||||
}
|
||||
|
||||
|
||||
.project_links_and_logo_section {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
text-align: center;
|
||||
padding: 0 5.5rem;
|
||||
}
|
||||
.about_vrct_logo {
|
||||
width: 20rem;
|
||||
object-fit: contain;
|
||||
}
|
||||
.project_links_wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.project_link {
|
||||
height: 2.6rem;
|
||||
padding: 0.4rem 1rem;
|
||||
border-radius: 0.4rem;
|
||||
&:hover {
|
||||
background-color: var(--dark_850_color);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--dark_900_color)
|
||||
}
|
||||
}
|
||||
|
||||
.contributors_img_wrapper {
|
||||
position: relative;
|
||||
}
|
||||
.contributors_img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@mixin contributors_sns_styles($top, $left) {
|
||||
position: absolute;
|
||||
left: $left;
|
||||
top: $top;
|
||||
width: 2.4rem;
|
||||
padding: 0.4rem;
|
||||
border-radius: 0.4rem;
|
||||
&:hover {
|
||||
background-color: var(--dark_825_color);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--dark_888_color)
|
||||
}
|
||||
}
|
||||
|
||||
$first_line_top: 6.2rem;
|
||||
.contributors_done_san_x {
|
||||
@include contributors_sns_styles($first_line_top, 2rem);
|
||||
}
|
||||
.contributors_iya_x {
|
||||
@include contributors_sns_styles($first_line_top, 27.6rem);
|
||||
}
|
||||
.contributors_rera_x {
|
||||
@include contributors_sns_styles($first_line_top, 52.2rem);
|
||||
}
|
||||
.contributors_rera_github {
|
||||
@include contributors_sns_styles($first_line_top, 55rem);
|
||||
}
|
||||
|
||||
$second_line_top: 16.6rem;
|
||||
.contributors_poposuke_x {
|
||||
@include contributors_sns_styles($second_line_top, 14.8rem);
|
||||
}
|
||||
.contributors_kumaguma_x {
|
||||
@include contributors_sns_styles($second_line_top, 40.8rem);
|
||||
}
|
||||
|
||||
.localization_section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.localization_members_img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.special_thanks_section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.special_thanks_members_img {
|
||||
width: 100%;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
.special_thanks_message_img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.poster_showcase_section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.vrchat_disclaimer {
|
||||
width: 100%;
|
||||
margin-top: 8rem;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import styles from "./PosterShowcaseContents.module.scss";
|
||||
import { PostersContents } from "./posters_contents/PostersContents";
|
||||
import { PosterShowcaseWorldsContents } from "./poster_showcase_worlds_contents/PosterShowcaseWorldsContents";
|
||||
|
||||
export const PosterShowcaseContents = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<PosterShowcaseWorldsContents />
|
||||
<PostersContents />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: start;
|
||||
gap: 2rem;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import clsx from "clsx";
|
||||
import styles from "./PosterShowcaseWorldsContents.module.scss";
|
||||
import { usePosterShowcaseWorldPageIndex } from "@store";
|
||||
const images = import.meta.glob("@images/about_vrct/showcased_worlds/*.{png,jpg,jpeg,svg}", { eager: true });
|
||||
|
||||
const getImageByFileName = (file_name) => {
|
||||
const imagePath = Object.keys(images).find((path) => path.includes(file_name));
|
||||
return imagePath ? images[imagePath]?.default : null;
|
||||
};
|
||||
|
||||
import poster_showcase_worlds_settings from "./poster_showcase_worlds_settings";
|
||||
import { chunkArray } from "@utils/chunkArray";
|
||||
|
||||
export const PosterShowcaseWorldsContents = () => {
|
||||
const { currentPosterShowcaseWorldPageIndex } = usePosterShowcaseWorldPageIndex();
|
||||
const poster_showcase_world_images = poster_showcase_worlds_settings.map((setting) => ({
|
||||
img: getImageByFileName(setting.image_file_name),
|
||||
x_post_num: setting.x_post_num
|
||||
}));
|
||||
|
||||
const chunked_poster_showcase_world_images = chunkArray(poster_showcase_world_images, 8);
|
||||
const target_poster_showcase_world_images = chunked_poster_showcase_world_images[currentPosterShowcaseWorldPageIndex];
|
||||
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.poster_showcase_world_container}>
|
||||
{target_poster_showcase_world_images.map((poster, index) => {
|
||||
let content = (
|
||||
<div className={styles.poster_showcase_world_img} >
|
||||
<img style={ {height: "100%", width: "100%", "objectFit": "contain" }} src={poster.img} />
|
||||
</div>
|
||||
);
|
||||
if (poster.x_post_num !== null) {
|
||||
content = (
|
||||
<a href={`https://twitter.com/Shiina_12siy/status/${poster.x_post_num}`} target="_blank" rel="noreferrer" >
|
||||
{content}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
const class_names = clsx(styles.poster_showcase_world_wrapper, {
|
||||
[styles.clickable]: (poster.x_post_num !== null)
|
||||
});
|
||||
return (
|
||||
<div className={class_names} key={index}>
|
||||
{content}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<PosterShowcaseWorldsPagination page_length={chunked_poster_showcase_world_images.length}/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
import chat_white_square from "@images/chato_white_square.png";
|
||||
import { useEffect } from "react";
|
||||
import { randomIntMinMax } from "@utils/randomIntMinMax";
|
||||
const PosterShowcaseWorldsPagination = ({ page_length }) => {
|
||||
const { currentPosterShowcaseWorldPageIndex, updatePosterShowcaseWorldPageIndex } = usePosterShowcaseWorldPageIndex();
|
||||
|
||||
useEffect(() => {
|
||||
updatePosterShowcaseWorldPageIndex(randomIntMinMax(page_length -1));
|
||||
},[page_length]);
|
||||
|
||||
const setPage = (index) => {
|
||||
updatePosterShowcaseWorldPageIndex(index);
|
||||
};
|
||||
|
||||
const getClassNames = (index, baseClass) => clsx(baseClass, {
|
||||
[styles.is_active]: (currentPosterShowcaseWorldPageIndex === index),
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={styles.pagination_container}>
|
||||
{[...Array(page_length).keys()].map((index) => {
|
||||
return (
|
||||
<div key={index} className={getClassNames(index, styles.pagination_box)} onClick={() => setPage(index)}>
|
||||
<div className={styles.chato_box}>
|
||||
<img src={chat_white_square} className={getClassNames(index, styles.pagination_chato_img)}/>
|
||||
</div>
|
||||
<div className={styles.indicator_box}>
|
||||
<div className={getClassNames(index, styles.indicator)}></div>
|
||||
<p className={getClassNames(index, styles.pagination_num)}>{index + 1}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||