procon_bypass_man-web 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.babelrc +6 -0
- data/.circleci/config.yml +73 -0
- data/.gitignore +12 -0
- data/.rspec +1 -0
- data/.rubocop.yml +26 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +97 -0
- data/LICENSE.txt +21 -0
- data/Procfile +2 -0
- data/README.md +43 -0
- data/Rakefile +4 -0
- data/bin/console +15 -0
- data/bin/pbm_web +7 -0
- data/bin/setup +8 -0
- data/jest.config.ts +194 -0
- data/lib/procon_bypass_man/web.rb +20 -0
- data/lib/procon_bypass_man/web/db.rb +33 -0
- data/lib/procon_bypass_man/web/migration/001_create_settings_table.sql +4 -0
- data/lib/procon_bypass_man/web/models/base_model.rb +47 -0
- data/lib/procon_bypass_man/web/models/setting.rb +22 -0
- data/lib/procon_bypass_man/web/public/bundle.js +2 -0
- data/lib/procon_bypass_man/web/public/bundle.js.LICENSE.txt +57 -0
- data/lib/procon_bypass_man/web/public/index.html +1 -0
- data/lib/procon_bypass_man/web/server.rb +139 -0
- data/lib/procon_bypass_man/web/setting_parser.rb +190 -0
- data/lib/procon_bypass_man/web/storage.rb +25 -0
- data/lib/procon_bypass_man/web/version.rb +7 -0
- data/package.json +48 -0
- data/procon_bypass_man-web.gemspec +36 -0
- data/src/app.tsx +5 -0
- data/src/components/button_setting.tsx +142 -0
- data/src/components/buttons_modal.tsx +110 -0
- data/src/components/buttons_setting.tsx +67 -0
- data/src/components/installable_macros.tsx +58 -0
- data/src/components/installable_modes.tsx +57 -0
- data/src/components/macro_settings.tsx +85 -0
- data/src/components/mode_settings.tsx +62 -0
- data/src/contexts/buttons_setting.ts +2 -0
- data/src/index.html +11 -0
- data/src/lib/button_state.test.ts +110 -0
- data/src/lib/button_state.ts +52 -0
- data/src/lib/button_state_diff.test.ts +123 -0
- data/src/lib/button_state_diff.ts +63 -0
- data/src/lib/buttons_setting_converter.test.ts +185 -0
- data/src/lib/buttons_setting_converter.ts +107 -0
- data/src/lib/http_client.ts +93 -0
- data/src/pages/bpm_page.tsx +92 -0
- data/src/pages/buttons_setting_page.tsx +281 -0
- data/src/pages/global_setting_page.tsx +83 -0
- data/src/pages/home.tsx +17 -0
- data/src/pages/recoding_mode_page.tsx +15 -0
- data/src/pages/top.tsx +107 -0
- data/src/reducers/layer_reducer.ts +120 -0
- data/src/types/button.ts +2 -0
- data/src/types/buttons_setting_type.ts +63 -0
- data/src/types/layer_key.ts +2 -0
- data/src/types/pbm_stats.ts +1 -0
- data/src/types/plugin.ts +43 -0
- data/tmp/.keep +0 -0
- data/tsconfig.json +75 -0
- data/webpack.config.js +56 -0
- data/yarn.lock +6815 -0
- metadata +150 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
module ProconBypassMan
|
2
|
+
module Web
|
3
|
+
class Storage
|
4
|
+
def self.instance
|
5
|
+
new
|
6
|
+
end
|
7
|
+
|
8
|
+
def root_path
|
9
|
+
ProconBypassMan::Web::Setting.find_or_create_by&.root_path
|
10
|
+
end
|
11
|
+
|
12
|
+
def root_path=(value)
|
13
|
+
ProconBypassMan::Web::Setting.find_or_create_by&.update!(root_path: value)
|
14
|
+
end
|
15
|
+
|
16
|
+
def setting_path
|
17
|
+
ProconBypassMan::Web::Setting.find_or_create_by&.setting_path
|
18
|
+
end
|
19
|
+
|
20
|
+
def setting_path=(value)
|
21
|
+
ProconBypassMan::Web::Setting.find_or_create_by&.update!(setting_path: value)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/package.json
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
{
|
2
|
+
"name": "procon_bypass_man-web",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"main": "index.js",
|
5
|
+
"license": "MIT",
|
6
|
+
"devDependencies": {
|
7
|
+
"@babel/core": "^7.14.8",
|
8
|
+
"@babel/preset-env": "^7.14.9",
|
9
|
+
"@babel/preset-react": "^7.14.5",
|
10
|
+
"@babel/preset-typescript": "^7.14.5",
|
11
|
+
"@emotion/react": "^11.4.0",
|
12
|
+
"@types/jest": "^26.0.24",
|
13
|
+
"@types/js-yaml": "^4.0.2",
|
14
|
+
"@types/lodash": "^4.14.172",
|
15
|
+
"@types/md5": "^2.3.1",
|
16
|
+
"@types/react": "^17.0.11",
|
17
|
+
"@types/react-dom": "^17.0.8",
|
18
|
+
"babel-jest": "^27.0.6",
|
19
|
+
"babel-loader": "^8.2.2",
|
20
|
+
"deep-object-diff": "^1.1.0",
|
21
|
+
"file-loader": "^6.2.0",
|
22
|
+
"html-webpack-plugin": "^5.3.1",
|
23
|
+
"jest": "^27.0.6",
|
24
|
+
"js-yaml": "^4.1.0",
|
25
|
+
"lodash": "^4.17.21",
|
26
|
+
"md5": "^2.3.0",
|
27
|
+
"ts-jest": "^27.0.4",
|
28
|
+
"ts-loader": "^9.2.3",
|
29
|
+
"ts-node": "^10.1.0",
|
30
|
+
"typescript": "^4.3.4",
|
31
|
+
"webpack": "^5.39.1",
|
32
|
+
"webpack-cli": "^4.7.2",
|
33
|
+
"webpack-dev-server": "^3.11.2"
|
34
|
+
},
|
35
|
+
"scripts": {
|
36
|
+
"build": "webpack",
|
37
|
+
"server": "webpack serve",
|
38
|
+
"release-build": "NODE_ENV=production webpack",
|
39
|
+
"test": "jest"
|
40
|
+
},
|
41
|
+
"dependencies": {
|
42
|
+
"@types/react-router-dom": "^5.1.7",
|
43
|
+
"axios": "^0.21.1",
|
44
|
+
"react": "^17.0.2",
|
45
|
+
"react-dom": "^17.0.2",
|
46
|
+
"react-router-dom": "^5.2.0"
|
47
|
+
}
|
48
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/procon_bypass_man/web/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "procon_bypass_man-web"
|
7
|
+
spec.version = ProconBypassMan::Web::VERSION
|
8
|
+
spec.authors = ["jiikko"]
|
9
|
+
spec.email = ["n905i.1214@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "PBM for web"
|
12
|
+
spec.description = spec.summary
|
13
|
+
spec.homepage = "https://github.com/splaplapla/procon_bypass_man-web"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
19
|
+
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
23
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
24
|
+
end
|
25
|
+
spec.bindir = "exe"
|
26
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
27
|
+
spec.require_paths = ["lib"]
|
28
|
+
|
29
|
+
# Uncomment to register a new dependency of your gem
|
30
|
+
spec.add_dependency "sinatra"
|
31
|
+
spec.add_dependency "webrick"
|
32
|
+
spec.add_dependency "sqlite3"
|
33
|
+
|
34
|
+
# For more information and examples about making a new gem, checkout our
|
35
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
36
|
+
end
|
data/src/app.tsx
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
/** @jsx jsx */
|
2
|
+
|
3
|
+
import { jsx, css } from '@emotion/react'
|
4
|
+
import React, { useState, useContext } from "react";
|
5
|
+
import { Button } from "../types/button";
|
6
|
+
import { ButtonState } from "./../lib/button_state";
|
7
|
+
import { ButtonsModal } from "./buttons_modal";
|
8
|
+
import { ButtonsSettingContext } from "./../contexts/buttons_setting";
|
9
|
+
import { ButtonsSettingType, ButtonsInLayer, ButtonInLayer, Layers, Flip } from "../types/buttons_setting_type";
|
10
|
+
import { LayerKey } from "../types/layer_key";
|
11
|
+
import { disableFlipType, alwaysFlipType, flipIfPressedSelfType, flipIfPressedSomeButtonsType, ignoreButtonsInFlipingType, remapType, openMenuType, closeMenuType } from "../reducers/layer_reducer";
|
12
|
+
|
13
|
+
type ButtonMenuProp = {
|
14
|
+
name: Button;
|
15
|
+
layerKey: LayerKey;
|
16
|
+
buttonValue: ButtonInLayer;
|
17
|
+
layersDispatch: any;
|
18
|
+
};
|
19
|
+
|
20
|
+
const ButtonMenu = ({ name, layerKey, buttonValue, layersDispatch }: ButtonMenuProp) => {
|
21
|
+
const flipRadioName = `${layerKey}_button_menu_${name}`;
|
22
|
+
const buttonState = new ButtonState(name, buttonValue.flip, buttonValue.remap);
|
23
|
+
|
24
|
+
// for modal
|
25
|
+
const [openModal, setOpenModal] = useState(false)
|
26
|
+
const [modalCallbackOnSubmit, setModalCallbackOnSubmit] = useState(undefined as any)
|
27
|
+
const [modalCloseCallback, setModalCloseCallback] = useState(undefined as any)
|
28
|
+
const [modalTitle, setModalTitle] = useState("")
|
29
|
+
const [modalPrefillButtons, setModalPrefillButtons] = useState<Array<Button>>([])
|
30
|
+
|
31
|
+
// 無効
|
32
|
+
const handleNullFlipValue = (e: React.ChangeEvent<HTMLInputElement>) => {
|
33
|
+
layersDispatch({ type: disableFlipType, payload: { layerKey: layerKey, button: name }});
|
34
|
+
};
|
35
|
+
|
36
|
+
// 常に連打
|
37
|
+
const handleFlipValue = (e: React.ChangeEvent<HTMLInputElement>) => {
|
38
|
+
layersDispatch({ type: alwaysFlipType, payload: { layerKey: layerKey, button: name }});
|
39
|
+
};
|
40
|
+
|
41
|
+
// 自分自身への条件付き連打
|
42
|
+
const openIfPressedRadioboxModal = (e: React.ChangeEvent<HTMLInputElement>) => {
|
43
|
+
layersDispatch({ type: flipIfPressedSelfType, payload: { layerKey: layerKey, button: name }});
|
44
|
+
};
|
45
|
+
|
46
|
+
// 条件付き連打
|
47
|
+
const flipIfPressedSomeButtons = buttonValue?.flip?.if_pressed || [] as Array<Button>;
|
48
|
+
const setFlipIfPressedSomeButtonsWithPersistence = (bs: Array<Button>) => {
|
49
|
+
layersDispatch({ type: flipIfPressedSomeButtonsType, payload: { layerKey: layerKey, button: name, targetButtons: bs }});
|
50
|
+
}
|
51
|
+
const openIfPressedSomeButtonsModal = (e: React.ChangeEvent<HTMLInputElement> | React.MouseEvent<HTMLInputElement>) => {
|
52
|
+
setOpenModal(true)
|
53
|
+
setModalTitle("特定のキーを押したときだけ")
|
54
|
+
setModalPrefillButtons(flipIfPressedSomeButtons);
|
55
|
+
setModalCallbackOnSubmit(() => setFlipIfPressedSomeButtonsWithPersistence);
|
56
|
+
setModalCloseCallback(() => setOpenModal);
|
57
|
+
}
|
58
|
+
|
59
|
+
// 無視
|
60
|
+
const forceNeutralButtons = buttonValue.flip?.force_neutral || [] as Array<Button>
|
61
|
+
const setIgnoreButtonsOnFlipingWithPersistence = (bs: Array<Button>) => {
|
62
|
+
layersDispatch({ type: ignoreButtonsInFlipingType, payload: { layerKey: layerKey, button: name, targetButtons: bs }});
|
63
|
+
}
|
64
|
+
const handleIgnoreButton = (e: React.ChangeEvent<HTMLInputElement>) => {
|
65
|
+
setOpenModal(true)
|
66
|
+
setModalTitle("連打中は特定のボタンの入力を無視する")
|
67
|
+
setModalPrefillButtons(buttonValue.flip?.force_neutral || [] as Array<Button>);
|
68
|
+
setModalCallbackOnSubmit(() => setIgnoreButtonsOnFlipingWithPersistence);
|
69
|
+
setModalCloseCallback(() => setOpenModal);
|
70
|
+
};
|
71
|
+
|
72
|
+
// リマップ
|
73
|
+
const setRemapButtonsWithPersistence = (bs: Array<Button>) => {
|
74
|
+
layersDispatch({ type: remapType, payload: { layerKey: layerKey, button: name, targetButtons: bs }});
|
75
|
+
}
|
76
|
+
const handleRemapButton = (e: React.ChangeEvent<HTMLInputElement>) => {
|
77
|
+
setOpenModal(true)
|
78
|
+
setModalTitle("リマップ")
|
79
|
+
setModalPrefillButtons(buttonValue.remap?.to || []);
|
80
|
+
setModalCallbackOnSubmit(() => setRemapButtonsWithPersistence);
|
81
|
+
setModalCloseCallback(() => setOpenModal);
|
82
|
+
};
|
83
|
+
|
84
|
+
return(
|
85
|
+
<>
|
86
|
+
<fieldset><legend><strong>連打設定</strong></legend>
|
87
|
+
<label><input type="radio" onChange={handleNullFlipValue} checked={buttonState.isDisabledFlip()}/>無効</label><br />
|
88
|
+
<label><input type="radio" onChange={handleFlipValue} checked={buttonState.isAlwaysFlip()}/>常に連打する</label><br />
|
89
|
+
<label><input type="radio" onChange={openIfPressedRadioboxModal} checked={buttonState.isFlipIfPressedSelf()}/>このボタンを押している時だけ連打する({name})</label><br />
|
90
|
+
<label>
|
91
|
+
<input type="radio" onChange={openIfPressedSomeButtonsModal} onClick={openIfPressedSomeButtonsModal} checked={buttonState.isFlipIfPressedSomeButtons()}/>
|
92
|
+
特定のキーを押したときだけ連打する{flipIfPressedSomeButtons.length > 0 && `(${flipIfPressedSomeButtons.join(", ")})`}
|
93
|
+
</label>
|
94
|
+
</fieldset>
|
95
|
+
|
96
|
+
<fieldset><legend><strong>連打オプション</strong></legend>
|
97
|
+
<label>
|
98
|
+
<input type="checkbox" onChange={handleIgnoreButton} checked={forceNeutralButtons.length > 0} disabled={buttonState.isDisabledFlip()} />
|
99
|
+
連打中は特定のボタンの入力を無視する{forceNeutralButtons.length > 0 && `(${forceNeutralButtons.join(", ")})`}
|
100
|
+
</label>
|
101
|
+
</fieldset>
|
102
|
+
|
103
|
+
<fieldset><legend><strong>リマップ設定</strong></legend>
|
104
|
+
<label>
|
105
|
+
<input type="checkbox" onChange={handleRemapButton} checked={buttonState.isRemap()} disabled={!buttonState.isDisabledFlip()} />
|
106
|
+
別のボタンに置き換える{buttonState.isRemap() && `(${buttonValue.remap?.to?.join(", ")})`}
|
107
|
+
</label>
|
108
|
+
</fieldset>
|
109
|
+
<div css={css`position: relative;`}>
|
110
|
+
{openModal && <ButtonsModal callbackOnSubmit={modalCallbackOnSubmit} callbackOnClose={modalCloseCallback} title={modalTitle} prefill={modalPrefillButtons} positionOnShown={"relative"} />}
|
111
|
+
</div>
|
112
|
+
</>
|
113
|
+
)
|
114
|
+
}
|
115
|
+
|
116
|
+
type Prop = {
|
117
|
+
name: Button;
|
118
|
+
layerKey: LayerKey;
|
119
|
+
};
|
120
|
+
|
121
|
+
export const ButtonSetting: React.FC<Prop> = ({ name, layerKey }) => {
|
122
|
+
const settingContext = useContext(ButtonsSettingContext);
|
123
|
+
const handleToggle = () => {
|
124
|
+
if(isOpenMenu()) { // 閉じる
|
125
|
+
settingContext.layersDispatch({ type: closeMenuType, payload: { layerKey: layerKey, button: name }});
|
126
|
+
} else { // 開く
|
127
|
+
settingContext.layersDispatch({ type: openMenuType, payload: { layerKey: layerKey, button: name }});
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
const isOpenMenu = () => {
|
132
|
+
return settingContext.layers[layerKey][name].open;
|
133
|
+
}
|
134
|
+
const buttonValue = settingContext.layers[layerKey][name] || {} as ButtonInLayer;
|
135
|
+
|
136
|
+
return (
|
137
|
+
<>
|
138
|
+
<label><input type="checkbox" checked={isOpenMenu()} onChange={handleToggle}/>{name}</label>
|
139
|
+
{isOpenMenu() && <ButtonMenu name={name} layerKey={layerKey} buttonValue={buttonValue} layersDispatch={settingContext.layersDispatch} />}
|
140
|
+
</>
|
141
|
+
);
|
142
|
+
};
|
@@ -0,0 +1,110 @@
|
|
1
|
+
/** @jsx jsx */
|
2
|
+
|
3
|
+
import { jsx, css } from '@emotion/react'
|
4
|
+
import React, { useState } from "react";
|
5
|
+
import { Button, buttons } from "../types/button";
|
6
|
+
|
7
|
+
type Props = {
|
8
|
+
callbackOnSubmit: any;
|
9
|
+
callbackOnClose: any;
|
10
|
+
prefill: Array<Button>;
|
11
|
+
title: string;
|
12
|
+
positionOnShown: string;
|
13
|
+
};
|
14
|
+
|
15
|
+
type CheckedButtons = {
|
16
|
+
[key in Button] : boolean
|
17
|
+
}
|
18
|
+
|
19
|
+
export const ButtonsModal = ({ callbackOnSubmit, callbackOnClose, title, prefill, positionOnShown }: Props) => {
|
20
|
+
const [checkedButtonMap, setCheckedButtonMap] = useState(
|
21
|
+
prefill.reduce((a, b) => { a[b] = true; return a },
|
22
|
+
buttons.reduce((a, b) => { a[b] = false; return a }, {} as CheckedButtons)
|
23
|
+
)
|
24
|
+
)
|
25
|
+
const callback = callbackOnSubmit;
|
26
|
+
const handleSubmit = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
27
|
+
e.preventDefault();
|
28
|
+
const bs = Object.entries(checkedButtonMap).reduce((acc, item) => {
|
29
|
+
const checked: boolean = item[1];
|
30
|
+
const button = item[0] as Button;
|
31
|
+
checked && acc.push(button);
|
32
|
+
return acc;
|
33
|
+
}, [] as Array<Button>).sort();
|
34
|
+
|
35
|
+
callbackOnSubmit(bs);
|
36
|
+
callbackOnClose(false);
|
37
|
+
};
|
38
|
+
const handleCancel = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
39
|
+
e.preventDefault();
|
40
|
+
callbackOnClose(false);
|
41
|
+
}
|
42
|
+
const titlestyle = css(`
|
43
|
+
margin-top: 10px;
|
44
|
+
font-size: 1.17em;
|
45
|
+
font-weight: bold;
|
46
|
+
`)
|
47
|
+
const style = () => {
|
48
|
+
if(positionOnShown === "relative") {
|
49
|
+
return css(`
|
50
|
+
position: absolute;
|
51
|
+
align: left;
|
52
|
+
top: -400px;
|
53
|
+
width: 400px;
|
54
|
+
height: 400px;
|
55
|
+
border: solid;
|
56
|
+
background-color: white;
|
57
|
+
`);
|
58
|
+
} else {
|
59
|
+
return css(`
|
60
|
+
position: absolute;
|
61
|
+
align: left;
|
62
|
+
top: 0px;
|
63
|
+
left: 20px;
|
64
|
+
width: 400px;
|
65
|
+
height: 400px;
|
66
|
+
border: solid;
|
67
|
+
background-color: white;
|
68
|
+
`);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
const aStyle = css`
|
72
|
+
background-color: #4669ff;
|
73
|
+
border-bottom: solid 2px #003aff;
|
74
|
+
border-right: solid 2px #003aff;
|
75
|
+
border-radius: 20px;
|
76
|
+
font-weight: bold;
|
77
|
+
color: #FFF;
|
78
|
+
text-decoration: none;
|
79
|
+
padding: 10px;
|
80
|
+
display: inline-block;
|
81
|
+
margin-left: 10px;
|
82
|
+
`;
|
83
|
+
|
84
|
+
const handleClick = (e: React.ChangeEvent<HTMLInputElement>) => {
|
85
|
+
setCheckedButtonMap((previousButtonStats) => {
|
86
|
+
previousButtonStats[e.target.value as Button] = e.target.checked;
|
87
|
+
return previousButtonStats;
|
88
|
+
})
|
89
|
+
}
|
90
|
+
|
91
|
+
return (
|
92
|
+
<>
|
93
|
+
<div css={style()}>
|
94
|
+
<div css={titlestyle}>{title}</div>
|
95
|
+
|
96
|
+
{buttons.map((b, index) => (
|
97
|
+
<div key={index}>
|
98
|
+
<label><input type="checkbox" value={b} defaultChecked={checkedButtonMap[b]} onChange={handleClick} />{b}</label>
|
99
|
+
</div>
|
100
|
+
))}
|
101
|
+
|
102
|
+
<hr />
|
103
|
+
<div css={css`display: flex`}>
|
104
|
+
<a href={"#"} onClick={handleCancel} css={aStyle}>変更せず閉じる</a>
|
105
|
+
<a href={"#"} onClick={handleSubmit} css={aStyle}>決定する</a>
|
106
|
+
</div>
|
107
|
+
</div>
|
108
|
+
</>
|
109
|
+
)
|
110
|
+
}
|
@@ -0,0 +1,67 @@
|
|
1
|
+
/** @jsx jsx */
|
2
|
+
|
3
|
+
import { jsx, css } from '@emotion/react'
|
4
|
+
import React, { useState, useContext } from "react";
|
5
|
+
import { ButtonSetting } from "./button_setting";
|
6
|
+
import { MacroSettings } from "./macro_settings";
|
7
|
+
import { ModeSettings } from "./mode_settings";
|
8
|
+
import { Button, buttons } from "../types/button";
|
9
|
+
import { LayerKey } from "../types/layer_key";
|
10
|
+
import { ButtonsSettingContext } from "./../contexts/buttons_setting";
|
11
|
+
|
12
|
+
type Props = {
|
13
|
+
layerKey: LayerKey;
|
14
|
+
layerRef: any;
|
15
|
+
};
|
16
|
+
|
17
|
+
export const ButtonsSetting = ({ layerKey, layerRef }:Props) => {
|
18
|
+
const [visibility, setVisibility] = useState("hidden");
|
19
|
+
const visibilityStyle = () => {
|
20
|
+
if(visibility === "hidden") {
|
21
|
+
return css`display: none;`;
|
22
|
+
}
|
23
|
+
}
|
24
|
+
const ulStyle = css`
|
25
|
+
border: 1px solid #666;
|
26
|
+
display: flex;
|
27
|
+
flex-wrap: wrap;
|
28
|
+
justify-content: center;
|
29
|
+
list-style-type: none;
|
30
|
+
margin: 0 0 0 1em;
|
31
|
+
padding: 0;
|
32
|
+
width: 900px;
|
33
|
+
`;
|
34
|
+
const liStyle = css`
|
35
|
+
border: 1px solid #aaa;
|
36
|
+
margin: 0.2em;
|
37
|
+
padding: 0.5em;
|
38
|
+
width: 200px;
|
39
|
+
`;
|
40
|
+
layerRef.setVisibility = setVisibility;
|
41
|
+
|
42
|
+
const { layers } = useContext(ButtonsSettingContext);
|
43
|
+
const isEnableMode = !layers[layerKey].mode.disable;
|
44
|
+
|
45
|
+
return(
|
46
|
+
<div css={visibilityStyle()}>
|
47
|
+
<h4>モード</h4>
|
48
|
+
<ModeSettings layerKey={layerKey} />
|
49
|
+
|
50
|
+
<h4>マクロ</h4>
|
51
|
+
{isEnableMode && `モードが有効なので選択できません`}
|
52
|
+
{!isEnableMode && <MacroSettings layerKey={layerKey} />}
|
53
|
+
|
54
|
+
<h4>各ボタンの設定</h4>
|
55
|
+
{isEnableMode && `モードが有効なので選択できません`}
|
56
|
+
{!isEnableMode &&
|
57
|
+
<div css={ulStyle}>
|
58
|
+
{buttons.map((b, i) => (
|
59
|
+
<div key={i} css={liStyle}>
|
60
|
+
<ButtonSetting layerKey={layerKey} name={b} />
|
61
|
+
</div>
|
62
|
+
))}
|
63
|
+
</div>
|
64
|
+
}
|
65
|
+
</div>
|
66
|
+
)
|
67
|
+
}
|