PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / tic-tac-toe / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/tic-tac-toe/index.js

195 lines 11.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ( function () {
2 var el = wp.element.createElement;
3 var useState = wp.element.useState;
4 var Fragment = wp.element.Fragment;
5 var registerBlockType = wp.blocks.registerBlockType;
6 var __ = wp.i18n.__;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
9 var useBlockProps = wp.blockEditor.useBlockProps;
10 var RichText = wp.blockEditor.RichText;
11 var PanelBody = wp.components.PanelBody;
12 var RangeControl = wp.components.RangeControl;
13 var ToggleControl = wp.components.ToggleControl;
14 var SelectControl = wp.components.SelectControl;
15 var TextControl = wp.components.TextControl;
16
17 var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
18 var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
19 var _tvf = function (typo, prefix) { var fn = getTypoCssVars(); return fn ? fn(typo, prefix) : {}; };
20
21 function EditorPreview(props) {
22 var a = props.attributes;
23 var set = props.setAttributes;
24
25 var cellStyle = function (sym) {
26 return {
27 background: a.cellBg, border: '2px solid ' + a.gridLine, borderRadius: '12px',
28 display: 'flex', alignItems: 'center', justifyContent: 'center',
29 fontSize: '38px', fontWeight: '900', cursor: 'pointer',
30 aspectRatio: '1', color: sym === 'X' ? a.xColor : (sym === 'O' ? a.oColor : 'transparent'),
31 transition: 'background 0.15s'
32 };
33 };
34
35 var DEMO = ['X', '', 'O', '', 'X', '', 'O', '', ''];
36
37 return el('div', {
38 style: {
39 background: a.sectionBg, borderRadius: '16px', padding: '28px 20px',
40 maxWidth: a.contentMaxWidth + 'px', margin: '0 auto', fontFamily: 'inherit',
41 boxSizing: 'border-box', textAlign: 'center'
42 }
43 },
44 a.showTitle && el(RichText, {
45 tagName: 'h3', value: a.title,
46 className: 'bkbg-ttt-title',
47 onChange: function (v) { set({ title: v }); },
48 style: { color: a.titleColor, margin: '0 0 4px' },
49 placeholder: 'Title…'
50 }),
51 a.showSubtitle && el(RichText, {
52 tagName: 'p', value: a.subtitle,
53 className: 'bkbg-ttt-subtitle',
54 onChange: function (v) { set({ subtitle: v }); },
55 style: { color: a.subtitleColor, margin: '0 0 16px' },
56 placeholder: 'Subtitle…'
57 }),
58
59 /* Score */
60 a.showScore && el('div', { style: { display: 'flex', justifyContent: 'center', gap: '12px', marginBottom: '18px' } },
61 [
62 { l: a.playerSymbol || 'X', v: 3, c: a.xColor },
63 { l: 'Draw', v: 1, c: a.subtitleColor },
64 { l: a.aiSymbol || 'O', v: 1, c: a.oColor }
65 ].map(function (s, i) {
66 return el('div', { key: i, style: { background: a.cardBg, borderRadius: '10px', padding: '8px 18px', textAlign: 'center', boxShadow: '0 1px 4px rgba(0,0,0,0.07)', minWidth: '70px' } },
67 el('div', { style: { fontSize: '22px', fontWeight: '900', color: s.c } }, s.v),
68 el('div', { style: { fontSize: '12px', color: a.subtitleColor } }, s.l)
69 );
70 })
71 ),
72
73 /* Status */
74 el('div', { style: { background: a.accentColor, color: '#fff', borderRadius: '10px', padding: '10px', marginBottom: '16px', fontWeight: '700', fontSize: '15px' } },
75 '🎮 Your turn (' + (a.playerSymbol || 'X') + ')'
76 ),
77
78 /* Board */
79 el('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(3,1fr)', gap: '8px', maxWidth: '280px', margin: '0 auto 18px' } },
80 DEMO.map(function (s, i) {
81 return el('div', { key: i, style: cellStyle(s) }, s || '\u00a0');
82 })
83 ),
84
85 /* Buttons */
86 el('div', { style: { display: 'flex', gap: '10px', justifyContent: 'center' } },
87 el('button', { style: { background: a.accentColor, color: '#fff', border: 'none', borderRadius: '9px', padding: '10px 24px', fontWeight: '700', cursor: 'pointer', fontSize: '14px' } }, '↺ New Game'),
88 el('button', { style: { background: 'transparent', border: '2px solid ' + a.accentColor, color: a.accentColor, borderRadius: '9px', padding: '9px 18px', fontWeight: '700', cursor: 'pointer', fontSize: '14px' } },
89 a.defaultMode === 'ai' ? '🤖 vs AI' : '👥 2 Players'
90 )
91 )
92 );
93 }
94
95 registerBlockType('blockenberg/tic-tac-toe', {
96 edit: function (props) {
97 var a = props.attributes;
98 var set = props.setAttributes;
99 var blockProps = useBlockProps((function () {
100 var tv = Object.assign({}, _tvf(a.titleTypo, '--bkttt-tt-'), _tvf(a.subtitleTypo, '--bkttt-st-'));
101 return { className: 'bkbg-ttt-root', style: tv };
102 })());
103
104 return el(Fragment, null,
105 el(InspectorControls, null,
106 el(PanelBody, { title: 'Content', initialOpen: true },
107 el(ToggleControl, { label: 'Show Title', checked: a.showTitle, onChange: function (v) { set({ showTitle: v }); }, __nextHasNoMarginBottom: true }),
108 el(ToggleControl, { label: 'Show Subtitle', checked: a.showSubtitle, onChange: function (v) { set({ showSubtitle: v }); }, __nextHasNoMarginBottom: true }),
109 el(ToggleControl, { label: 'Show Score', checked: a.showScore, onChange: function (v) { set({ showScore: v }); }, __nextHasNoMarginBottom: true })
110 ),
111 el(PanelBody, { title: 'Game Settings', initialOpen: false },
112 el(SelectControl, {
113 label: 'Default Mode',
114 value: a.defaultMode,
115 options: [
116 { label: '🤖 Player vs AI', value: 'ai' },
117 { label: '👥 Player vs Player', value: 'pvp' }
118 ],
119 onChange: function (v) { set({ defaultMode: v }); },
120 __nextHasNoMarginBottom: true
121 }),
122 el('div', { style: { marginBottom: '16px' } }),
123 a.defaultMode === 'ai' && el(SelectControl, {
124 label: 'AI Difficulty',
125 value: a.aiDifficulty,
126 options: [
127 { label: 'Easy (random)', value: 'easy' },
128 { label: 'Medium (smart)', value: 'medium' },
129 { label: 'Hard (minimax)', value: 'hard' }
130 ],
131 onChange: function (v) { set({ aiDifficulty: v }); },
132 __nextHasNoMarginBottom: true
133 }),
134 el('div', { style: { marginBottom: '16px' } }),
135 el(TextControl, {
136 label: 'Player Symbol',
137 value: a.playerSymbol,
138 onChange: function (v) { set({ playerSymbol: v.slice(0, 2) || 'X' }); },
139 __nextHasNoMarginBottom: true
140 }),
141 el('div', { style: { marginBottom: '16px' } }),
142 el(TextControl, {
143 label: 'AI / P2 Symbol',
144 value: a.aiSymbol,
145 onChange: function (v) { set({ aiSymbol: v.slice(0, 2) || 'O' }); },
146 __nextHasNoMarginBottom: true
147 })
148 ),
149 el(PanelBody, { title: 'Typography', initialOpen: false },
150 getTypoControl() && el(getTypoControl(), {
151 label: __('Title Typography', 'blockenberg'),
152 value: a.titleTypo || {},
153 onChange: function (v) { set({ titleTypo: v }); }
154 }),
155 getTypoControl() && el(getTypoControl(), {
156 label: __('Subtitle Typography', 'blockenberg'),
157 value: a.subtitleTypo || {},
158 onChange: function (v) { set({ subtitleTypo: v }); }
159 }),
160 el(RangeControl, {
161 label: 'Max Width (px)', value: a.contentMaxWidth, min: 300, max: 800, step: 10,
162 onChange: function (v) { set({ contentMaxWidth: v }); }, __nextHasNoMarginBottom: true
163 })
164 ),
165 el(PanelColorSettings, {
166 title: 'Colors', initialOpen: false,
167 colorSettings: [
168 { label: 'Accent Color', value: a.accentColor, onChange: function (v) { set({ accentColor: v || '#6366f1' }); } },
169 { label: 'X Symbol Color', value: a.xColor, onChange: function (v) { set({ xColor: v || '#ef4444' }); } },
170 { label: 'O Symbol Color', value: a.oColor, onChange: function (v) { set({ oColor: v || '#3b82f6' }); } },
171 { label: 'Cell Background', value: a.cellBg, onChange: function (v) { set({ cellBg: v || '#ffffff' }); } },
172 { label: 'Win Line Color', value: a.winLineBg, onChange: function (v) { set({ winLineBg: v || '#22c55e' }); } },
173 { label: 'Grid Lines', value: a.gridLine, onChange: function (v) { set({ gridLine: v || '#d1d5db' }); } },
174 { label: 'Section Background', value: a.sectionBg, onChange: function (v) { set({ sectionBg: v || '#eef2ff' }); } },
175 { label: 'Card Background', value: a.cardBg, onChange: function (v) { set({ cardBg: v || '#ffffff' }); } },
176 { label: 'Title Color', value: a.titleColor, onChange: function (v) { set({ titleColor: v || '#312e81' }); } }
177 ]
178 })
179 ),
180 el('div', blockProps, el(EditorPreview, { attributes: a, setAttributes: set }))
181 );
182 },
183 save: function (props) {
184 var a = props.attributes;
185 var bp = wp.blockEditor.useBlockProps.save((function () {
186 var tv = Object.assign({}, _tvf(a.titleTypo, '--bkttt-tt-'), _tvf(a.subtitleTypo, '--bkttt-st-'));
187 return { style: tv };
188 })());
189 return el('div', bp,
190 el('div', { className: 'bkbg-ttt-app', 'data-opts': JSON.stringify(a) })
191 );
192 }
193 });
194 }() );
195