telegem 3.3.0 → 3.4.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.
data/docs/keyboards.md ADDED
@@ -0,0 +1,446 @@
1
+ # Keyboard Markup
2
+
3
+ Telegem provides a clean DSL for creating inline and reply keyboards. Keyboards enable interactive buttons for better user experience.
4
+
5
+ ## Reply Keyboards
6
+
7
+ Reply keyboards appear at the bottom of the chat and replace the system keyboard.
8
+
9
+ ### Basic Reply Keyboard
10
+
11
+ ```ruby
12
+ keyboard = Telegem.keyboard do
13
+ row "Button 1", "Button 2"
14
+ row "Button 3"
15
+ end
16
+
17
+ ctx.reply("Choose an option:", reply_markup: keyboard)
18
+ ```
19
+
20
+ ### Keyboard Options
21
+
22
+ ```ruby
23
+ keyboard = Telegem.keyboard do
24
+ row "Yes", "No"
25
+ end.resize.one_time.selective
26
+
27
+ ctx.reply("Confirm?", reply_markup: keyboard)
28
+ ```
29
+
30
+ Available options:
31
+ - `resize` - Make keyboard smaller
32
+ - `one_time` - Hide keyboard after use
33
+ - `selective` - Show only to mentioned users
34
+
35
+ ### Special Button Types
36
+
37
+ ```ruby
38
+ keyboard = Telegem.keyboard do
39
+ row "📍 Location", "📞 Contact"
40
+ request_location "Share Location"
41
+ request_contact "Share Contact"
42
+ request_poll "Create Poll", poll_type: 'regular'
43
+ end
44
+
45
+ ctx.reply("What would you like to share?", reply_markup: keyboard)
46
+ ```
47
+
48
+ ## Inline Keyboards
49
+
50
+ Inline keyboards appear directly in messages and work with callback queries.
51
+
52
+ ### Basic Inline Keyboard
53
+
54
+ ```ruby
55
+ inline = Telegem.inline do
56
+ row callback("Yes", "yes"), callback("No", "no")
57
+ row url("Visit Site", "https://example.com")
58
+ end
59
+
60
+ ctx.reply("Do you agree?", reply_markup: inline)
61
+ ```
62
+
63
+ ### Button Types
64
+
65
+ #### Callback Buttons
66
+
67
+ ```ruby
68
+ callback("Button Text", "callback_data")
69
+ ```
70
+
71
+ - Text: Button label
72
+ - Data: String passed to callback handler (max 64 bytes)
73
+
74
+ #### URL Buttons
75
+
76
+ ```ruby
77
+ url("Visit Website", "https://example.com")
78
+ ```
79
+
80
+ Opens URL when pressed.
81
+
82
+ #### Login Buttons
83
+
84
+ ```ruby
85
+ login("Login", "https://example.com/login", forward_text: "Login to site")
86
+ ```
87
+
88
+ For web app authorization.
89
+
90
+ #### Web App Buttons
91
+
92
+ ```ruby
93
+ web_app("Open App", "https://example.com/app")
94
+ ```
95
+
96
+ Opens web app in Telegram interface.
97
+
98
+ #### Pay Buttons
99
+
100
+ ```ruby
101
+ pay("Pay $10")
102
+ ```
103
+
104
+ For payment integrations.
105
+
106
+ #### Game Buttons
107
+
108
+ ```ruby
109
+ callback_game("Play Game", "game_short_name")
110
+ ```
111
+
112
+ For HTML5 games.
113
+
114
+ ### Advanced Inline Keyboard
115
+
116
+ ```ruby
117
+ keyboard = Telegem.inline do
118
+ # First row
119
+ row callback("👍 Like", "like"), callback("👎 Dislike", "dislike")
120
+
121
+ # Second row
122
+ row url("📖 Read More", "https://example.com/article")
123
+
124
+ # Third row
125
+ row callback("🔔 Subscribe", "subscribe"), callback("🔕 Unsubscribe", "unsubscribe")
126
+
127
+ # Fourth row
128
+ row web_app("🎮 Play Game", "https://game.example.com")
129
+ end
130
+
131
+ ctx.reply("What do you think?", reply_markup: keyboard)
132
+ ```
133
+
134
+ ## Handling Button Presses
135
+
136
+ ### Callback Query Handlers
137
+
138
+ ```ruby
139
+ bot.callback_query do |ctx|
140
+ data = ctx.data
141
+ ctx.answer_callback_query("You pressed: #{data}")
142
+ end
143
+
144
+ # Specific data
145
+ bot.callback_query('like') do |ctx|
146
+ ctx.answer_callback_query("Thanks for liking!")
147
+ # Update message or database
148
+ end
149
+
150
+ # Pattern matching
151
+ bot.callback_query(/^action_/) do |ctx|
152
+ action = ctx.data.split('_').last
153
+ handle_action(ctx, action)
154
+ end
155
+ ```
156
+
157
+ ### Callback Query Methods
158
+
159
+ ```ruby
160
+ ctx.answer_callback_query(text: "Processing...")
161
+ ctx.answer_callback_query(text: "Done!", show_alert: true)
162
+ ctx.answer_callback_query(url: "https://example.com")
163
+ ctx.answer_callback_query(cache_time: 30)
164
+ ```
165
+
166
+ ## Dynamic Keyboards
167
+
168
+ ### Building from Data
169
+
170
+ ```ruby
171
+ def create_menu_keyboard(options)
172
+ Telegem.keyboard do
173
+ options.each_slice(2) do |row_buttons|
174
+ row(*row_buttons)
175
+ end
176
+ end.resize
177
+ end
178
+
179
+ options = ["Pizza", "Burger", "Salad", "Soup"]
180
+ keyboard = create_menu_keyboard(options)
181
+ ctx.reply("Choose food:", reply_markup: keyboard)
182
+ ```
183
+
184
+ ### Conditional Buttons
185
+
186
+ ```ruby
187
+ def create_user_keyboard(ctx)
188
+ Telegem.inline do
189
+ row callback("Profile", "profile")
190
+
191
+ if ctx.session[:admin]
192
+ row callback("Admin Panel", "admin")
193
+ end
194
+
195
+ if ctx.session[:premium]
196
+ row callback("Premium Features", "premium")
197
+ end
198
+
199
+ row callback("Settings", "settings")
200
+ end
201
+ end
202
+
203
+ keyboard = create_user_keyboard(ctx)
204
+ ctx.reply("Menu:", reply_markup: keyboard)
205
+ ```
206
+
207
+ ## Keyboard Management
208
+
209
+ ### Removing Keyboards
210
+
211
+ ```ruby
212
+ # Remove reply keyboard
213
+ ctx.remove_keyboard
214
+ ctx.remove_keyboard("Keyboard removed!")
215
+
216
+ # Remove inline keyboard
217
+ ctx.edit_message_reply_markup(reply_markup: nil)
218
+ ```
219
+
220
+ ### Updating Keyboards
221
+
222
+ ```ruby
223
+ # Edit inline keyboard
224
+ new_keyboard = Telegem.inline do
225
+ row callback("Updated Button", "updated")
226
+ end
227
+
228
+ ctx.edit_message_reply_markup(reply_markup: new_keyboard)
229
+ ```
230
+
231
+ ### Force Reply
232
+
233
+ ```ruby
234
+ # Force user to reply to message
235
+ ctx.reply("What's your name?", reply_markup: Telegem::Markup.force_reply)
236
+ ```
237
+
238
+ ## Advanced Patterns
239
+
240
+ ### Pagination
241
+
242
+ ```ruby
243
+ def create_pagination_keyboard(current_page, total_pages)
244
+ Telegem.inline do
245
+ row = []
246
+
247
+ if current_page > 1
248
+ row << callback("âŦ…ī¸ Previous", "page:#{current_page - 1}")
249
+ end
250
+
251
+ row << callback("#{current_page}/#{total_pages}", "current")
252
+
253
+ if current_page < total_pages
254
+ row << callback("Next âžĄī¸", "page:#{current_page + 1}")
255
+ end
256
+
257
+ row(*row)
258
+ end
259
+ end
260
+
261
+ bot.callback_query(/^page:/) do |ctx|
262
+ page = ctx.data.split(':').last.to_i
263
+ keyboard = create_pagination_keyboard(page, 10)
264
+ ctx.edit_message_reply_markup(reply_markup: keyboard)
265
+ end
266
+ ```
267
+
268
+ ### Multi-select Interface
269
+
270
+ ```ruby
271
+ def create_selection_keyboard(selected_items, all_items)
272
+ Telegem.inline do
273
+ all_items.each do |item|
274
+ status = selected_items.include?(item) ? "✅" : "âŦœ"
275
+ row callback("#{status} #{item}", "toggle:#{item}")
276
+ end
277
+
278
+ row callback("Done", "done")
279
+ end
280
+ end
281
+
282
+ bot.callback_query(/^toggle:/) do |ctx|
283
+ item = ctx.data.split(':', 2).last
284
+ selected = ctx.session[:selected] ||= []
285
+
286
+ if selected.include?(item)
287
+ selected.delete(item)
288
+ else
289
+ selected << item
290
+ end
291
+
292
+ keyboard = create_selection_keyboard(selected, ALL_ITEMS)
293
+ ctx.edit_message_reply_markup(reply_markup: keyboard)
294
+ end
295
+ ```
296
+
297
+ ### Inline Search
298
+
299
+ ```ruby
300
+ bot.inline_query do |ctx|
301
+ query = ctx.query
302
+
303
+ results = search_items(query).map do |item|
304
+ Telegem::Types::InlineQueryResultArticle.new(
305
+ id: item.id,
306
+ title: item.title,
307
+ description: item.description,
308
+ input_message_content: {
309
+ message_text: "Selected: #{item.title}"
310
+ },
311
+ reply_markup: Telegem.inline do
312
+ callback "More Info", "info:#{item.id}"
313
+ end
314
+ )
315
+ end
316
+
317
+ ctx.answer_inline_query(results)
318
+ end
319
+ ```
320
+
321
+ ## Keyboard Best Practices
322
+
323
+ ### Design Guidelines
324
+
325
+ 1. **Keep it Simple**: 3-5 buttons per row, 2-3 rows max
326
+ 2. **Clear Labels**: Use descriptive text and emojis
327
+ 3. **Consistent Style**: Same button style for similar actions
328
+ 4. **Progressive Disclosure**: Show more options as needed
329
+
330
+ ### User Experience
331
+
332
+ ```ruby
333
+ # Good: Clear, actionable buttons
334
+ keyboard = Telegem.inline do
335
+ row callback("📅 Book Now", "book"), callback("â„šī¸ More Info", "info")
336
+ row callback("📞 Call Us", "call")
337
+ end
338
+
339
+ # Bad: Confusing, too many options
340
+ keyboard = Telegem.inline do
341
+ row "Option A", "Option B", "Option C", "Option D", "Option E"
342
+ end
343
+ ```
344
+
345
+ ### Error Handling
346
+
347
+ ```ruby
348
+ bot.callback_query do |ctx|
349
+ begin
350
+ handle_callback(ctx)
351
+ rescue => e
352
+ ctx.logger.error("Callback error: #{e.message}")
353
+ ctx.answer_callback_query("Something went wrong", show_alert: true)
354
+ end
355
+ end
356
+ ```
357
+
358
+ ### Performance Considerations
359
+
360
+ ```ruby
361
+ # Cache keyboards for repeated use
362
+ KEYBOARDS = {
363
+ main_menu: Telegem.inline do
364
+ row callback("Home", "home"), callback("Settings", "settings")
365
+ end
366
+ }
367
+
368
+ ctx.reply("Menu:", reply_markup: KEYBOARDS[:main_menu])
369
+ ```
370
+
371
+ ## Keyboard Types Reference
372
+
373
+ ### Reply Keyboard Buttons
374
+
375
+ | Method | Description | Parameters |
376
+ |--------|-------------|------------|
377
+ | `text` | Regular text button | text, style, icon_custom_emoji_id |
378
+ | `request_contact` | Request phone number | text, style, icon_custom_emoji_id |
379
+ | `request_location` | Request location | text, style, icon_custom_emoji_id |
380
+ | `request_poll` | Request poll creation | text, poll_type, style, icon_custom_emoji_id |
381
+
382
+ ### Inline Keyboard Buttons
383
+
384
+ | Method | Description | Parameters |
385
+ |--------|-------------|------------|
386
+ | `callback` | Callback query button | text, data, style, icon_custom_emoji_id |
387
+ | `url` | URL button | text, url, style, icon_custom_emoji_id |
388
+ | `login` | Login button | text, url, style, icon_custom_emoji_id, **options |
389
+ | `web_app` | Web app button | text, url, style, icon_custom_emoji_id |
390
+ | `pay` | Payment button | text, style, icon_custom_emoji_id |
391
+ | `switch_inline` | Switch to inline query | text, query, style, icon_custom_emoji_id |
392
+ | `switch_inline_current_chat` | Switch inline in current chat | text, query, style, icon_custom_emoji_id |
393
+ | `callback_game` | Game button | text, game_short_name, style, icon_custom_emoji_id |
394
+
395
+ ## Testing Keyboards
396
+
397
+ ```ruby
398
+ # Test keyboard creation
399
+ def test_keyboard_creation
400
+ keyboard = Telegem.keyboard do
401
+ row "Yes", "No"
402
+ end
403
+
404
+ assert keyboard.to_h.key?(:keyboard)
405
+ assert_equal [["Yes", "No"]], keyboard.to_h[:keyboard]
406
+ end
407
+
408
+ # Test callback handling
409
+ def test_callback_handling
410
+ # Simulate callback query
411
+ simulate_callback_query(bot, "test_data")
412
+
413
+ # Assert expected behavior
414
+ end
415
+ ```
416
+
417
+ ## Common Issues
418
+
419
+ ### Callback Data Too Long
420
+
421
+ ```ruby
422
+ # Bad: too much data
423
+ callback("Button", "very_long_data_that_exceeds_64_bytes_limit_and_will_cause_errors")
424
+
425
+ # Good: use IDs
426
+ callback("Button", "action:123") # Reference by ID
427
+ ```
428
+
429
+ ### Keyboard Not Updating
430
+
431
+ ```ruby
432
+ # Force update
433
+ ctx.edit_message_reply_markup(reply_markup: new_keyboard, message_id: ctx.message.message_id)
434
+ ```
435
+
436
+ ### Buttons Not Working
437
+
438
+ ```ruby
439
+ # Check for typos in callback data
440
+ bot.callback_query('correct_data') do |ctx|
441
+ # Handle callback
442
+ end
443
+ ```
444
+
445
+ Keyboards are essential for creating interactive, user-friendly Telegram bots. Use them to guide users and collect input efficiently.</content>
446
+ <parameter name="filePath">/home/slick/telegem/docs/keyboards.md