procon_bypass_man-web 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,6 +15,10 @@ module ProconBypassMan
15
15
  class App < Sinatra::Base
16
16
  require "yaml"
17
17
 
18
+ before do
19
+ env["rack.logger"] = ProconBypassMan::Web.logger
20
+ end
21
+
18
22
  register Sinatra::Reloader if defined?(Sinatra::Reloader)
19
23
  set :bind, '0.0.0.0'
20
24
 
@@ -119,13 +123,19 @@ module ProconBypassMan
119
123
  end
120
124
  end
121
125
 
126
+ # PBMから受け取って、emmitする
127
+ post '/api/pressed_buttons' do
128
+ status 200
129
+ body ''
130
+ end
131
+
122
132
  get '/' do
123
- send_file File.join(ProconBypassMan::Web.root, 'lib/procon_bypass_man/web', 'public', 'index.html')
133
+ send_file File.join(ProconBypassMan::Web.gem_root, 'lib/procon_bypass_man/web', 'public', 'index.html')
124
134
  end
125
135
 
126
136
  # サーバでパスとして解釈されないように、全部 `/`として受け付けるため
127
137
  get '/:none' do
128
- send_file File.join(ProconBypassMan::Web.root, 'lib/procon_bypass_man/web', 'public', 'index.html')
138
+ send_file File.join(ProconBypassMan::Web.gem_root, 'lib/procon_bypass_man/web', 'public', 'index.html')
129
139
  end
130
140
  end
131
141
 
@@ -0,0 +1,72 @@
1
+ module ProconBypassMan
2
+ module Web
3
+ class SettingParser
4
+ class Layer
5
+ module Syntax
6
+ def initialize(mode: )
7
+ @table = {
8
+ mode: mode&.to_s,
9
+ }.compact
10
+ end
11
+
12
+ def flip(button, if_pressed: nil, force_neutral: nil)
13
+ @table[:flip] ||= {}
14
+ if if_pressed.nil? && force_neutral.nil?
15
+ @table[:flip][button] = nil
16
+ else
17
+ if if_pressed
18
+ if if_pressed.is_a?(Array)
19
+ ifp = if_pressed
20
+ else
21
+ ifp = [if_pressed]
22
+ end
23
+ end
24
+ if force_neutral
25
+ if force_neutral.is_a?(Array)
26
+ fn = force_neutral
27
+ else
28
+ fn = [force_neutral]
29
+ end
30
+ end
31
+ @table[:flip][button] = { if_pressed: ifp, force_neutral: fn, enable: true }
32
+ end
33
+ self
34
+ end
35
+
36
+ def remap(button, to: nil)
37
+ case to
38
+ when Array
39
+ @table[:remap] ||= {}
40
+ @table[:remap][button] = { to: to }
41
+ when String, Symbol
42
+ @table[:remap] ||= {}
43
+ @table[:remap][button] = { to: [to] }
44
+ end
45
+
46
+ self
47
+ end
48
+
49
+ def macro(name, if_pressed: nil)
50
+ @table[:macro] ||= {}
51
+ if if_pressed.nil?
52
+ @table[:macro][name.to_s] = { if_pressed: [] }
53
+ else
54
+ @table[:macro][name.to_s] = { if_pressed: if_pressed }
55
+ end
56
+ self
57
+ end
58
+
59
+ def method_missing(name, *_args)
60
+ ProconBypassMan::Web.logger.info("unknown layer DSL #{name}")
61
+ self
62
+ end
63
+ end
64
+ include Syntax
65
+
66
+ def to_hash
67
+ @table
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,109 @@
1
+ module ProconBypassMan
2
+ module Web
3
+ class SettingParser
4
+ class TopLevelLayer
5
+ module Serializer
6
+ def to_hash
7
+ h = { prefix_keys_for_changing_layer: prefix_keys_for_changing_layer || [] }
8
+ h[:layers] ||= {}
9
+ @layers.each do |key, layer|
10
+ h[:layers][key] = layer&.to_hash
11
+ end
12
+ h
13
+ end
14
+
15
+ def to_hash_group_by_button
16
+ h = { prefix_keys_for_changing_layer: prefix_keys_for_changing_layer || [] }
17
+ h[:layers] ||= {}
18
+ @layers.each do |key, layer|
19
+ h[:layers][key] ||= {}
20
+ next if layer.nil?
21
+
22
+ if !@installed_plugin[:macros].empty?
23
+ h[:installed_macros] = @installed_plugin[:macros]
24
+ end
25
+ if !@installed_plugin[:modes].empty?
26
+ h[:installed_modes] = @installed_plugin[:modes]
27
+ end
28
+
29
+ layer.to_hash.dig(:flip)&.each do |button, value|
30
+ h[:layers][key][button] ||= {}
31
+ h[:layers][key][button][:open] = true
32
+ h[:layers][key][button][:flip] ||= {}
33
+ h[:layers][key][button][:flip][:enable] = true
34
+ if value
35
+ h[:layers][key][button][:flip].merge!(value)
36
+ end
37
+ end
38
+
39
+ if layer.to_hash.dig(:macro)
40
+ h[:layers][key][:macro] = []
41
+ if(macros = layer.to_hash.dig(:macro))
42
+ macros.transform_values! { |x| x[:if_pressed] }
43
+ h[:layers][key][:macro] = macros
44
+ end
45
+ end
46
+
47
+ if layer.to_hash.dig(:mode)
48
+ h[:layers][key][:mode] = { layer.to_hash.dig(:mode) => true }
49
+ end
50
+
51
+ layer.to_hash.dig(:remap)&.each do |button, value|
52
+ h[:layers][key][button] ||= {}
53
+ h[:layers][key][button][:remap] ||= {}
54
+ h[:layers][key][button][:open] = true
55
+ if value
56
+ h[:layers][key][button][:remap].merge!(value)
57
+ end
58
+ end
59
+ end
60
+ h
61
+ end
62
+ end
63
+
64
+ module Syntax
65
+ def initialize
66
+ @installed_plugin = { macros: [], modes: [] }
67
+ @layers = {}
68
+ end
69
+
70
+ def install_macro_plugin(name)
71
+ @installed_plugin[:macros] << name.to_s
72
+ end
73
+
74
+ def install_mode_plugin(name)
75
+ @installed_plugin[:modes] << name.to_s
76
+ end
77
+
78
+ def prefix_keys_for_changing_layer(value=nil)
79
+ if value
80
+ @prefix_keys_for_changing_layer = value
81
+ else
82
+ @prefix_keys_for_changing_layer
83
+ end
84
+ end
85
+
86
+ def layer(dir, mode: nil, &block)
87
+ if(mode == :manual || mode == 'manual')
88
+ mode = nil
89
+ end
90
+
91
+ if block_given?
92
+ @layers[dir] = Layer.new(mode: mode).instance_eval(&block) || Layer.new(mode: mode)
93
+ else
94
+ @layers[dir] = Layer.new(mode: mode)
95
+ end
96
+ end
97
+
98
+ def method_missing(name, *_args)
99
+ ProconBypassMan::Web.logger.info("unknown toplevel DSL #{name}")
100
+ self
101
+ end
102
+ end
103
+
104
+ include Syntax
105
+ include Serializer
106
+ end
107
+ end
108
+ end
109
+ end
@@ -1,4 +1,6 @@
1
1
  require "json"
2
+ require "procon_bypass_man/web/setting_parser/top_level_layer"
3
+ require "procon_bypass_man/web/setting_parser/layer"
2
4
 
3
5
  # pluginの定数を握りつぶす
4
6
  class Module
@@ -9,160 +11,10 @@ class Module
9
11
  end
10
12
  end
11
13
 
14
+ # PBM 0.1.8バージョンの構文に対応
12
15
  module ProconBypassMan
13
16
  module Web
14
17
  class SettingParser
15
- class Core
16
- class Layer
17
- def initialize(mode: )
18
- @table = {
19
- mode: mode&.to_s,
20
- }.compact
21
- end
22
-
23
- def flip(button, if_pressed: nil, force_neutral: nil)
24
- @table[:flip] ||= {}
25
- if if_pressed.nil? && force_neutral.nil?
26
- @table[:flip][button] = nil
27
- else
28
- if if_pressed
29
- if if_pressed.is_a?(Array)
30
- ifp = if_pressed
31
- else
32
- ifp = [if_pressed]
33
- end
34
- end
35
- if force_neutral
36
- if force_neutral.is_a?(Array)
37
- fn = force_neutral
38
- else
39
- fn = [force_neutral]
40
- end
41
- end
42
- @table[:flip][button] = { if_pressed: ifp, force_neutral: fn, enable: true }
43
- end
44
- self
45
- end
46
-
47
- def remap(button, to: nil)
48
- case to
49
- when Array
50
- @table[:remap] ||= {}
51
- @table[:remap][button] = { to: to }
52
- when String, Symbol
53
- @table[:remap] ||= {}
54
- @table[:remap][button] = { to: [to] }
55
- end
56
-
57
- self
58
- end
59
-
60
- def macro(name, if_pressed: nil)
61
- @table[:macro] ||= {}
62
- if if_pressed.nil?
63
- @table[:macro][name.to_s] = { if_pressed: [] }
64
- else
65
- @table[:macro][name.to_s] = { if_pressed: if_pressed }
66
- end
67
- self
68
- end
69
-
70
- def to_hash
71
- @table
72
- end
73
- end
74
-
75
- def install_macro_plugin(name)
76
- @installed_plugin[:macros] << name.to_s
77
- end
78
-
79
- def install_mode_plugin(name)
80
- @installed_plugin[:modes] << name.to_s
81
- end
82
-
83
- def initialize
84
- @installed_plugin = { macros: [], modes: [] }
85
- @layers = {}
86
- end
87
-
88
- def prefix_keys_for_changing_layer(value=nil)
89
- if value
90
- @prefix_keys_for_changing_layer = value
91
- else
92
- @prefix_keys_for_changing_layer
93
- end
94
- end
95
-
96
- def layer(dir, mode: nil, &block)
97
- if(mode == :manual || mode == 'manual')
98
- mode = nil
99
- end
100
-
101
- if block_given?
102
- @layers[dir] = Layer.new(mode: mode).instance_eval(&block) || Layer.new(mode: mode)
103
- else
104
- @layers[dir] = Layer.new(mode: mode)
105
- end
106
- end
107
-
108
- def to_hash
109
- h = { prefix_keys_for_changing_layer: prefix_keys_for_changing_layer || [] }
110
- h[:layers] ||= {}
111
- @layers.each do |key, layer|
112
- h[:layers][key] = layer&.to_hash
113
- end
114
- h
115
- end
116
-
117
- def to_hash_group_by_button
118
- h = { prefix_keys_for_changing_layer: prefix_keys_for_changing_layer || [] }
119
- h[:layers] ||= {}
120
- @layers.each do |key, layer|
121
- h[:layers][key] ||= {}
122
- next if layer.nil?
123
-
124
- if !@installed_plugin[:macros].empty?
125
- h[:installed_macros] = @installed_plugin[:macros]
126
- end
127
- if !@installed_plugin[:modes].empty?
128
- h[:installed_modes] = @installed_plugin[:modes]
129
- end
130
-
131
- layer.to_hash.dig(:flip)&.each do |button, value|
132
- h[:layers][key][button] ||= {}
133
- h[:layers][key][button][:open] = true
134
- h[:layers][key][button][:flip] ||= {}
135
- h[:layers][key][button][:flip][:enable] = true
136
- if value
137
- h[:layers][key][button][:flip].merge!(value)
138
- end
139
- end
140
-
141
- if layer.to_hash.dig(:macro)
142
- h[:layers][key][:macro] = []
143
- if(macros = layer.to_hash.dig(:macro))
144
- macros.transform_values! { |x| x[:if_pressed] }
145
- h[:layers][key][:macro] = macros
146
- end
147
- end
148
-
149
- if layer.to_hash.dig(:mode)
150
- h[:layers][key][:mode] = { layer.to_hash.dig(:mode) => true }
151
- end
152
-
153
- layer.to_hash.dig(:remap)&.each do |button, value|
154
- h[:layers][key][button] ||= {}
155
- h[:layers][key][button][:remap] ||= {}
156
- h[:layers][key][button][:open] = true
157
- if value
158
- h[:layers][key][button][:remap].merge!(value)
159
- end
160
- end
161
- end
162
- h
163
- end
164
- end
165
-
166
18
  def self.parse(text)
167
19
  new(text)
168
20
  end
@@ -182,7 +34,7 @@ module ProconBypassMan
182
34
  end
183
35
 
184
36
  def initialize(text)
185
- @parser = Core.new
37
+ @parser = TopLevelLayer.new
186
38
  @parser.instance_eval(text)
187
39
  end
188
40
  end
@@ -6,19 +6,19 @@ module ProconBypassMan
6
6
  end
7
7
 
8
8
  def root_path
9
- ProconBypassMan::Web::Setting.find_or_create_by&.root_path
9
+ ProconBypassMan::Web::Setting.find_or_create&.root_path
10
10
  end
11
11
 
12
12
  def root_path=(value)
13
- ProconBypassMan::Web::Setting.find_or_create_by&.update!(root_path: value)
13
+ ProconBypassMan::Web::Setting.find_or_create&.update!(root_path: value)
14
14
  end
15
15
 
16
16
  def setting_path
17
- ProconBypassMan::Web::Setting.find_or_create_by&.setting_path
17
+ ProconBypassMan::Web::Setting.find_or_create&.setting_path
18
18
  end
19
19
 
20
20
  def setting_path=(value)
21
- ProconBypassMan::Web::Setting.find_or_create_by&.update!(setting_path: value)
21
+ ProconBypassMan::Web::Setting.find_or_create&.update!(setting_path: value)
22
22
  end
23
23
  end
24
24
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ProconBypassMan
4
4
  module Web
5
- VERSION = "0.1.1"
5
+ VERSION = "0.1.2"
6
6
  end
7
7
  end
@@ -1,4 +1,6 @@
1
1
  require_relative "web/version"
2
+ require "logger"
3
+ require "procon_bypass_man/web/configuration"
2
4
  require "procon_bypass_man/web/server"
3
5
  require "procon_bypass_man/web/db"
4
6
  require "procon_bypass_man/web/models/setting"
@@ -8,13 +10,21 @@ module ProconBypassMan
8
10
  module Web
9
11
  class Error < StandardError; end
10
12
 
11
- def self.root
12
- File.expand_path('../..', File.dirname(__FILE__))
13
+ extend ProconBypassMan::Web::Configuration::ClassAttributes
14
+
15
+ def self.configure(&block)
16
+ @@configuration = ProconBypassMan::Web::Configuration.new
17
+ @@configuration.instance_eval(&block)
18
+ @@configuration
13
19
  end
14
20
 
15
21
  def self.config
16
- { db_path: ENV["DB_PATH"] ||= File.join(root, "pbm_web.db"),
17
- }
22
+ @@configuration ||= ProconBypassMan::Web::Configuration.new
23
+ end
24
+
25
+ # @return [String]
26
+ def self.gem_root
27
+ File.expand_path('../..', __dir__).freeze
18
28
  end
19
29
  end
20
30
  end
@@ -9,6 +9,8 @@ import { ButtonsSettingContext } from "./../contexts/buttons_setting";
9
9
  import { ButtonsSettingType, ButtonsInLayer, ButtonInLayer, Layers, Flip } from "../types/buttons_setting_type";
10
10
  import { LayerKey } from "../types/layer_key";
11
11
  import { disableFlipType, alwaysFlipType, flipIfPressedSelfType, flipIfPressedSomeButtonsType, ignoreButtonsInFlipingType, remapType, openMenuType, closeMenuType } from "../reducers/layer_reducer";
12
+ import { useModal, ModalSetting } from "../hooks/useModal";
13
+ import { ModalProps } from "../components/buttons_modal";
12
14
 
13
15
  type ButtonMenuProp = {
14
16
  name: Button;
@@ -19,27 +21,20 @@ type ButtonMenuProp = {
19
21
 
20
22
  const ButtonMenu = ({ name, layerKey, buttonValue, layersDispatch }: ButtonMenuProp) => {
21
23
  const buttonState = new ButtonState(name, buttonValue.flip, buttonValue.remap);
22
-
23
- // for modal
24
- const [isOpenModal, toggleModal] = useReducer((m) => { return !m; }, false);
25
-
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>>([])
24
+ const [modalProps, openModal] = useModal();
30
25
 
31
26
  // 無効
32
- const handleNullFlipValue = (e: React.ChangeEvent<HTMLInputElement>) => {
27
+ const handleNullFlipValue = (e: React.MouseEvent<HTMLInputElement>) => {
33
28
  layersDispatch({ type: disableFlipType, payload: { layerKey: layerKey, button: name }});
34
29
  };
35
30
 
36
31
  // 常に連打
37
- const handleFlipValue = (e: React.ChangeEvent<HTMLInputElement>) => {
32
+ const handleFlipValue = (e: React.MouseEvent<HTMLInputElement>) => {
38
33
  layersDispatch({ type: alwaysFlipType, payload: { layerKey: layerKey, button: name }});
39
34
  };
40
35
 
41
36
  // 自分自身への条件付き連打
42
- const openIfPressedRadioboxModal = (e: React.ChangeEvent<HTMLInputElement>) => {
37
+ const openIfPressedRadioboxModal = (e: React.MouseEvent<HTMLInputElement>) => {
43
38
  layersDispatch({ type: flipIfPressedSelfType, payload: { layerKey: layerKey, button: name }});
44
39
  };
45
40
 
@@ -48,12 +43,8 @@ const ButtonMenu = ({ name, layerKey, buttonValue, layersDispatch }: ButtonMenuP
48
43
  const setFlipIfPressedSomeButtonsWithPersistence = (bs: Array<Button>) => {
49
44
  layersDispatch({ type: flipIfPressedSomeButtonsType, payload: { layerKey: layerKey, button: name, targetButtons: bs }});
50
45
  }
51
- const openIfPressedSomeButtonsModal = (e: React.ChangeEvent<HTMLInputElement> | React.MouseEvent<HTMLInputElement>) => {
52
- toggleModal();
53
- setModalTitle("特定のキーを押したときだけ")
54
- setModalPrefillButtons(flipIfPressedSomeButtons);
55
- setModalCallbackOnSubmit(() => setFlipIfPressedSomeButtonsWithPersistence);
56
- setModalCloseCallback(() => toggleModal);
46
+ const openIfPressedSomeButtonsModal = (e: React.MouseEvent<HTMLInputElement>) => {
47
+ openModal({ title: "特定のキーを押したときだけ", prefill: flipIfPressedSomeButtons, callbackOnSubmit: setFlipIfPressedSomeButtonsWithPersistence });
57
48
  }
58
49
 
59
50
  // 無視
@@ -62,11 +53,7 @@ const ButtonMenu = ({ name, layerKey, buttonValue, layersDispatch }: ButtonMenuP
62
53
  layersDispatch({ type: ignoreButtonsInFlipingType, payload: { layerKey: layerKey, button: name, targetButtons: bs }});
63
54
  }
64
55
  const handleIgnoreButton = (e: React.ChangeEvent<HTMLInputElement>) => {
65
- toggleModal();
66
- setModalTitle("連打中は特定のボタンの入力を無視する")
67
- setModalPrefillButtons(buttonValue.flip?.force_neutral || [] as Array<Button>);
68
- setModalCallbackOnSubmit(() => setIgnoreButtonsOnFlipingWithPersistence);
69
- setModalCloseCallback(() => toggleModal);
56
+ openModal({ title: "連打中は特定のボタンの入力を無視する", prefill: buttonValue.flip?.force_neutral || [] as Array<Button>, callbackOnSubmit: setIgnoreButtonsOnFlipingWithPersistence });
70
57
  };
71
58
 
72
59
  // リマップ
@@ -74,21 +61,20 @@ const ButtonMenu = ({ name, layerKey, buttonValue, layersDispatch }: ButtonMenuP
74
61
  layersDispatch({ type: remapType, payload: { layerKey: layerKey, button: name, targetButtons: bs }});
75
62
  }
76
63
  const handleRemapButton = (e: React.ChangeEvent<HTMLInputElement>) => {
77
- toggleModal();
78
- setModalTitle("リマップ")
79
- setModalPrefillButtons(buttonValue.remap?.to || []);
80
- setModalCallbackOnSubmit(() => setRemapButtonsWithPersistence);
81
- setModalCloseCallback(() => toggleModal);
64
+ openModal({ title: "リマップ", prefill: buttonValue.remap?.to || [], callbackOnSubmit: setRemapButtonsWithPersistence });
82
65
  };
83
66
 
84
67
  return(
85
68
  <>
69
+ <div css={css`position: relative;`}>
70
+ {<ButtonsModal {...modalProps as ModalProps} />}
71
+ </div>
86
72
  <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 />
73
+ <label><input type="radio" onClick={handleNullFlipValue} checked={buttonState.isDisabledFlip()} readOnly={true} />無効</label><br />
74
+ <label><input type="radio" onClick={handleFlipValue} checked={buttonState.isAlwaysFlip()} readOnly={true} />常に連打する</label><br />
75
+ <label><input type="radio" onClick={openIfPressedRadioboxModal} checked={buttonState.isFlipIfPressedSelf()} readOnly={true} />このボタンを押している時だけ連打する({name})</label><br />
90
76
  <label>
91
- <input type="radio" onChange={openIfPressedSomeButtonsModal} onClick={openIfPressedSomeButtonsModal} checked={buttonState.isFlipIfPressedSomeButtons()}/>
77
+ <input type="radio" onClick={openIfPressedSomeButtonsModal} checked={buttonState.isFlipIfPressedSomeButtons()} readOnly={true} />
92
78
  特定のキーを押したときだけ連打する{flipIfPressedSomeButtons.length > 0 && `(${flipIfPressedSomeButtons.join(", ")})`}
93
79
  </label>
94
80
 
@@ -106,9 +92,6 @@ const ButtonMenu = ({ name, layerKey, buttonValue, layersDispatch }: ButtonMenuP
106
92
  別のボタンに置き換える{buttonState.isRemap() && `(${buttonValue.remap?.to?.join(", ")})`}
107
93
  </label>
108
94
  </fieldset>
109
- <div css={css`position: relative;`}>
110
- {isOpenModal && <ButtonsModal callbackOnSubmit={modalCallbackOnSubmit} callbackOnClose={modalCloseCallback} title={modalTitle} prefill={modalPrefillButtons} positionOnShown={"relative"} />}
111
- </div>
112
95
  </>
113
96
  )
114
97
  }
@@ -4,19 +4,21 @@ import { jsx, css } from '@emotion/react'
4
4
  import React, { useState } from "react";
5
5
  import { Button, buttons } from "../types/button";
6
6
 
7
- type Props = {
7
+ export type ModalProps = {
8
8
  callbackOnSubmit: any;
9
9
  callbackOnClose: any;
10
10
  prefill: Array<Button>;
11
11
  title: string;
12
- positionOnShown: string;
12
+ visible: boolean;
13
13
  };
14
14
 
15
15
  type CheckedButtons = {
16
16
  [key in Button] : boolean
17
17
  }
18
18
 
19
- export const ButtonsModal = ({ callbackOnSubmit, callbackOnClose, title, prefill, positionOnShown }: Props) => {
19
+ export const ButtonsModal = ({ callbackOnSubmit, callbackOnClose, title, prefill, visible }: ModalProps) => {
20
+ if(!visible) { return null };
21
+
20
22
  const [checkedButtonMap, setCheckedButtonMap] = useState(
21
23
  prefill.reduce((a, b) => { a[b] = true; return a },
22
24
  buttons.reduce((a, b) => { a[b] = false; return a }, {} as CheckedButtons)
@@ -45,28 +47,16 @@ export const ButtonsModal = ({ callbackOnSubmit, callbackOnClose, title, prefill
45
47
  font-weight: bold;
46
48
  `)
47
49
  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
- }
50
+ return css(`
51
+ position: absolute;
52
+ align: left;
53
+ top: 0px;
54
+ left: 20px;
55
+ width: 400px;
56
+ height: 400px;
57
+ border: solid;
58
+ background-color: white;
59
+ `);
70
60
  }
71
61
  const aStyle = css`
72
62
  background-color: #4669ff;
@@ -10,29 +10,23 @@ import { Plugin, PluginBody, AvailablePlugins, MacroNameMap } from "../types/plu
10
10
  import { ButtonsModal } from "./buttons_modal";
11
11
  import { applyMacroType } from "../reducers/layer_reducer";
12
12
 
13
+ import { useModal, ModalSetting } from "../hooks/useModal";
14
+ import { ModalProps } from "../components/buttons_modal";
15
+
13
16
  type MacroSettingProps = {
14
17
  layerKey: LayerKey;
15
18
  macro: StructMacro;
16
19
  };
17
20
  const MacroSetting = ({ macro, layerKey }: MacroSettingProps) => {
18
21
  const { layersDispatch } = useContext(ButtonsSettingContext);
19
- // for modal
20
- const [isOpenModal, toggleModal] = useReducer((m) => { return !m; }, false);
21
- const [modalCallbackOnSubmit, setModalCallbackOnSubmit] = useState(undefined as any)
22
- const [modalCloseCallback, setModalCloseCallback] = useState(undefined as any)
23
- const [modalTitle, setModalTitle] = useState("")
24
- const [modalPrefillButtons, setModalPrefillButtons] = useState<Array<Button>>([])
22
+ const [modalProps, openModal] = useModal();
25
23
 
26
24
  const setButtonsForModal = (bs: Array<Button>) => {
27
25
  macro.if_pressed = bs;
28
26
  layersDispatch({ type: applyMacroType, payload: { layerKey: layerKey, macro: macro }});
29
27
  }
30
28
  const handleClick = (e: React.ChangeEvent<HTMLInputElement>) => {
31
- toggleModal();
32
- setModalTitle("発動キーの設定")
33
- setModalPrefillButtons(macro.if_pressed);
34
- setModalCallbackOnSubmit(() => setButtonsForModal);
35
- setModalCloseCallback(() => toggleModal);
29
+ openModal({ title: "キープレフィックスの変更", prefill: macro.if_pressed, callbackOnSubmit: setButtonsForModal });
36
30
  }
37
31
  const isEnable = macro.if_pressed.length > 0;
38
32
 
@@ -47,7 +41,7 @@ const MacroSetting = ({ macro, layerKey }: MacroSettingProps) => {
47
41
  {isEnable && `${macro.if_pressed.join(", ")}で発動`}
48
42
  </li>
49
43
  <div css={css`position: relative;`}>
50
- {isOpenModal && <ButtonsModal callbackOnSubmit={modalCallbackOnSubmit} callbackOnClose={modalCloseCallback} title={modalTitle} prefill={macro.if_pressed} positionOnShown={"relative"} />}
44
+ {<ButtonsModal {...modalProps as ModalProps} />}
51
45
  </div>
52
46
  </>
53
47
  )