procon_bypass_man-web 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}
|