about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--Gemfile.lock15
-rw-r--r--app/assets/config/wittle_manifest.js1
-rw-r--r--app/assets/images/wittle/slider.pngbin0 -> 20100 bytes
-rw-r--r--app/assets/javascripts/wittle/application.js1
-rw-r--r--app/assets/javascripts/wittle/utilities.js.erb204
-rw-r--r--app/assets/javascripts/wittle/wittle.js5
-rw-r--r--app/assets/stylesheets/wittle/general.css.scss91
-rw-r--r--app/controllers/wittle/puzzles_controller.rb36
-rw-r--r--app/models/wittle/puzzle.rb4
-rw-r--r--app/views/layouts/wittle/application.html.haml3
-rw-r--r--app/views/wittle/puzzles/_handle_puzzle.html.erb33
-rw-r--r--app/views/wittle/puzzles/_submission.html.haml7
-rw-r--r--app/views/wittle/puzzles/about.html.haml3
-rw-r--r--app/views/wittle/puzzles/index.html.haml13
-rw-r--r--app/views/wittle/puzzles/show.html.haml25
-rw-r--r--app/views/wittle/puzzles/solve.js.erb1
-rw-r--r--config/routes.rb6
-rw-r--r--db/migrate/20231028210722_create_wittle_scores.rb2
-rw-r--r--lib/tasks/wittle_tasks.rake11
-rw-r--r--lib/wittle/engine.rb2
-rw-r--r--test/dummy/db/schema.rb1
-rw-r--r--wittle.gemspec2
22 files changed, 240 insertions, 226 deletions
diff --git a/Gemfile.lock b/Gemfile.lock index 86422fe..11ce5d5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock
@@ -4,8 +4,10 @@ PATH
4 wittle (0.1.0) 4 wittle (0.1.0)
5 enumerize 5 enumerize
6 haml 6 haml
7 jquery-rails
7 rails (>= 7.1.1) 8 rails (>= 7.1.1)
8 rice 9 rice
10 sassc-rails
9 11
10GEM 12GEM
11 remote: https://rubygems.org/ 13 remote: https://rubygems.org/
@@ -95,6 +97,7 @@ GEM
95 enumerize (2.7.0) 97 enumerize (2.7.0)
96 activesupport (>= 3.2) 98 activesupport (>= 3.2)
97 erubi (1.12.0) 99 erubi (1.12.0)
100 ffi (1.16.3)
98 globalid (1.2.1) 101 globalid (1.2.1)
99 activesupport (>= 6.1) 102 activesupport (>= 6.1)
100 haml (6.2.3) 103 haml (6.2.3)
@@ -107,6 +110,10 @@ GEM
107 irb (1.8.3) 110 irb (1.8.3)
108 rdoc 111 rdoc
109 reline (>= 0.3.8) 112 reline (>= 0.3.8)
113 jquery-rails (4.6.0)
114 rails-dom-testing (>= 1, < 3)
115 railties (>= 4.2.0)
116 thor (>= 0.14, < 2.0)
110 loofah (2.21.4) 117 loofah (2.21.4)
111 crass (~> 1.0.2) 118 crass (~> 1.0.2)
112 nokogiri (>= 1.12.0) 119 nokogiri (>= 1.12.0)
@@ -182,6 +189,14 @@ GEM
182 io-console (~> 0.5) 189 io-console (~> 0.5)
183 rice (4.1.0) 190 rice (4.1.0)
184 ruby2_keywords (0.0.5) 191 ruby2_keywords (0.0.5)
192 sassc (2.4.0)
193 ffi (~> 1.9)
194 sassc-rails (2.1.2)
195 railties (>= 4.0.0)
196 sassc (>= 2.0)
197 sprockets (> 3.0)
198 sprockets-rails
199 tilt
185 sprockets (4.2.1) 200 sprockets (4.2.1)
186 concurrent-ruby (~> 1.0) 201 concurrent-ruby (~> 1.0)
187 rack (>= 2.2.4, < 4) 202 rack (>= 2.2.4, < 4)
diff --git a/app/assets/config/wittle_manifest.js b/app/assets/config/wittle_manifest.js index 079ddad..46aea2a 100644 --- a/app/assets/config/wittle_manifest.js +++ b/app/assets/config/wittle_manifest.js
@@ -1,3 +1,4 @@
1//= link_directory ../stylesheets/wittle .css 1//= link_directory ../stylesheets/wittle .css
2//= link_directory ../javascripts/wittle .js 2//= link_directory ../javascripts/wittle .js
3//= link_directory ../audio/wittle .aac 3//= link_directory ../audio/wittle .aac
4//= link_directory ../images/wittle .png
diff --git a/app/assets/images/wittle/slider.png b/app/assets/images/wittle/slider.png new file mode 100644 index 0000000..f093f89 --- /dev/null +++ b/app/assets/images/wittle/slider.png
Binary files differ
diff --git a/app/assets/javascripts/wittle/application.js b/app/assets/javascripts/wittle/application.js index e54c646..52d2214 100644 --- a/app/assets/javascripts/wittle/application.js +++ b/app/assets/javascripts/wittle/application.js
@@ -10,4 +10,5 @@
10// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details 10// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11// about supported directives. 11// about supported directives.
12// 12//
13//= require jquery3
13//= require_tree . 14//= require_tree .
diff --git a/app/assets/javascripts/wittle/utilities.js.erb b/app/assets/javascripts/wittle/utilities.js.erb index 406adda..487af6e 100644 --- a/app/assets/javascripts/wittle/utilities.js.erb +++ b/app/assets/javascripts/wittle/utilities.js.erb
@@ -245,210 +245,6 @@ window.deleteElementsByClassName = function(rootElem, className) {
245 } 245 }
246} 246}
247 247
248window.loadHeader = function(titleText) {
249 document.body.style.marginLeft = '0px'
250
251 var navbar = document.createElement('div')
252 document.body.appendChild(navbar)
253 navbar.className = 'navbar'
254 navbar.style = 'min-width: 700px; position: absolute; top: 0; width: 100%; z-index: 1'
255 navbar.style.borderBottom = '2px solid ' + window.BORDER
256 navbar.style.background = window.PAGE_BACKGROUND
257
258 var navbarPadding = document.createElement('div')
259 document.body.appendChild(navbarPadding)
260 navbarPadding.className = 'navbar-padding'
261
262 var titleDiv = document.createElement('div')
263 navbar.appendChild(titleDiv)
264 titleDiv.style = 'position: absolute; width: 100%; pointer-events: none'
265
266 var titleLabel = document.createElement('label')
267 titleDiv.appendChild(titleLabel)
268 titleLabel.style = 'font-size: 48; pointer-events: auto'
269 titleLabel.id = 'title'
270 titleLabel.innerText = titleText
271
272 var link = document.createElement('label')
273 navbar.appendChild(link)
274 link.style = 'float: left; margin-left: 32px; cursor: pointer; line-height: 60px'
275 link.className = 'navbar-content'
276
277 if (window.location.href.endsWith('browse.html')) {
278 navbar.style.position = 'fixed' // When browsing, pin the navbar to the top so that it's visible during infinite scroll.
279
280 link.innerText = 'Create a puzzle'
281 link.onpointerdown = function() {window.location = 'editor.html'}
282
283 var link2 = document.createElement('label')
284 navbar.appendChild(link2)
285 link2.style = 'float: left; margin-left: 20px; cursor: pointer; line-height: 60px; display: none'
286 link2.className = 'navbar-content'
287 link2.innerText = 'Jump to top'
288 link2.id = 'scrollToTop'
289 link2.onpointerdown = function() {window.scrollTo(0, 0)}
290
291 } else if (window.location.href.includes('/play/')) {
292 link.innerText = 'Back to all puzzles'
293 link.onpointerdown = function() {window.location = '../browse.html'}
294 } else /* All other pages */ {
295 link.innerText = 'Browse all puzzles'
296 link.onpointerdown = function() {window.location = 'browse.html'}
297 }
298
299 var feedbackButton = document.createElement('label')
300 navbar.appendChild(feedbackButton)
301 feedbackButton.id = 'feedbackButton'
302 feedbackButton.style = 'float: right; margin-right: 8px; cursor: pointer; line-height: 60px'
303 feedbackButton.innerText = 'Send feedback'
304 feedbackButton.className = 'navbar-content'
305 feedbackButton.onpointerdown = function() {
306 var feedback = prompt('Provide feedback:')
307 if (feedback) {
308 sendFeedback(feedback)
309 }
310 }
311
312 var separator = document.createElement('label')
313 navbar.appendChild(separator)
314 separator.style = 'float: right; line-height: 60px; padding-left: 6px; padding-right: 6px'
315 separator.className = 'navbar-content'
316 separator.innerText = '|'
317
318 var sourceLink = document.createElement('label')
319 navbar.appendChild(sourceLink)
320 sourceLink.style = 'float: right; line-height: 60px; cursor: pointer'
321 sourceLink.innerText = 'Source code'
322 sourceLink.className = 'navbar-content'
323 sourceLink.onpointerdown = function() {window.open('https://github.com/jbzdarkid/jbzdarkid.github.io', '_blank')}
324
325 var collapsedSettings = drawSymbol({'type': 'plus', 'width':20, 'height':20})
326 navbar.appendChild(collapsedSettings)
327 collapsedSettings.style = 'width: 20px; height: 20px; position: absolute; left: 0; cursor: pointer'
328 collapsedSettings.style.border = '2px solid ' + window.BORDER
329 collapsedSettings.id = 'collapsedSettings'
330 collapsedSettings.onpointerdown = function() {
331 this.style.display = 'none'
332 var expandedSettings = document.getElementById('expandedSettings')
333 expandedSettings.style.display = null
334 window.settings.expanded = 'true'
335 }
336
337 var expandedSettings = document.createElement('div')
338 navbar.appendChild(expandedSettings)
339 expandedSettings.style = 'width: 300px; position: absolute; left: 0; display: none; padding: 10px'
340 expandedSettings.style.border = '2px solid ' + window.BORDER
341 expandedSettings.style.background = window.PAGE_BACKGROUND
342 expandedSettings.id = 'expandedSettings'
343
344 var minus = drawSymbol({'type':'minus', 'width':20, 'height':20})
345 minus.style = 'width: 20px; height: 20px; cursor: pointer; position: absolute; top: 0; left: 0'
346 expandedSettings.appendChild(minus)
347 minus.onpointerdown = function() {
348 this.parentElement.style.display = 'none'
349 var collapsedSettings = document.getElementById('collapsedSettings')
350 collapsedSettings.style.display = null
351 window.settings.expanded = 'false'
352 }
353
354 if (window.settings.expanded == 'true') {
355 collapsedSettings.onpointerdown()
356 }
357
358 // Now, for the contents of the settings
359 var settingsLabel = document.createElement('label')
360 expandedSettings.appendChild(settingsLabel)
361 settingsLabel.innerText = 'settings'
362 settingsLabel.style = 'line-height: 0px' // Attach to the top
363
364 expandedSettings.appendChild(document.createElement('br'))
365 expandedSettings.appendChild(document.createElement('br'))
366
367 // Theme
368 document.body.style.color = window.TEXT_COLOR
369 document.body.style.background = window.PAGE_BACKGROUND
370 var themeButton = document.createElement('button')
371 expandedSettings.appendChild(themeButton)
372 if (window.settings.theme == 'night') {
373 themeButton.innerText = 'Night theme'
374 themeButton.onpointerdown = function() {
375 window.settings.theme = 'light'
376 location.reload()
377 }
378 } else if (window.settings.theme == 'light') {
379 themeButton.innerText = 'Light theme'
380 themeButton.onpointerdown = function() {
381 window.settings.theme = 'night'
382 location.reload()
383 }
384 }
385
386 expandedSettings.appendChild(document.createElement('br'))
387
388 // Sensitivity
389 var sensLabel = document.createElement('label')
390 expandedSettings.appendChild(sensLabel)
391 sensLabel.htmlFor = 'sens'
392 sensLabel.innerText = 'Mouse Speed 2D'
393
394 var sens = document.createElement('input')
395 expandedSettings.appendChild(sens)
396 sens.type = 'range'
397 sens.id = 'sens'
398 sens.min = '0.1'
399 sens.max = '1.3'
400 sens.step = '0.1'
401 sens.value = window.settings.sensitivity
402 sens.onchange = function() {
403 window.settings.sensitivity = this.value
404 }
405 sens.style.backgroundImage = 'linear-gradient(to right, ' + window.ALT_BACKGROUND + ', ' + window.ACTIVE_COLOR + ')'
406
407 // Volume
408 var volumeLabel = document.createElement('label')
409 expandedSettings.appendChild(volumeLabel)
410 volumeLabel.htmlFor = 'volume'
411 volumeLabel.innerText = 'Volume'
412
413 var volume = document.createElement('input')
414 expandedSettings.appendChild(volume)
415 volume.type = 'range'
416 volume.id = 'volume'
417 volume.min = '0'
418 volume.max = '0.24'
419 volume.step = '0.02'
420 volume.value = parseFloat(window.settings.volume)
421 volume.onchange = function() {
422 window.settings.volume = this.value
423 }
424 volume.style.backgroundImage = 'linear-gradient(to right, ' + window.ALT_BACKGROUND + ', ' + window.ACTIVE_COLOR + ')'
425
426 // Custom mechanics -- disabled for now
427 window.settings.customMechanics = false
428 /*
429 var customMechanics = createCheckbox()
430 expandedSettings.appendChild(customMechanics)
431 customMechanics.id = 'customMechanics'
432 if (window.settings.customMechanics == 'true') {
433 customMechanics.style.background = window.BORDER
434 customMechanics.checked = true
435 }
436
437 customMechanics.onpointerdown = function() {
438 this.checked = !this.checked
439 this.style.background = (this.checked ? window.BORDER : window.PAGE_BACKGROUND)
440 window.settings.customMechanics = this.checked
441 window.location.reload()
442 }
443
444 var mechLabel = document.createElement('label')
445 expandedSettings.appendChild(mechLabel)
446 mechLabel.style.marginLeft = '6px'
447 mechLabel.htmlFor = 'customMechanics'
448 mechLabel.innerText = 'Custom mechanics'
449 */
450}
451
452// Automatically solve the puzzle 248// Automatically solve the puzzle
453window.solvePuzzle = function() { 249window.solvePuzzle = function() {
454 if (window.setSolveMode) window.setSolveMode(false) 250 if (window.setSolveMode) window.setSolveMode(false)
diff --git a/app/assets/javascripts/wittle/wittle.js b/app/assets/javascripts/wittle/wittle.js new file mode 100644 index 0000000..883a4b8 --- /dev/null +++ b/app/assets/javascripts/wittle/wittle.js
@@ -0,0 +1,5 @@
1$.ajaxSetup({
2 headers: {
3 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
4 }
5});
diff --git a/app/assets/stylesheets/wittle/general.css.scss b/app/assets/stylesheets/wittle/general.css.scss new file mode 100644 index 0000000..06a7a83 --- /dev/null +++ b/app/assets/stylesheets/wittle/general.css.scss
@@ -0,0 +1,91 @@
1#wrap {
2
3}
4
5h1 {
6 text-align: center;
7}
8
9#trace-settings {
10 margin: 1em auto;
11 width: 540px;
12
13 summary {
14 text-align: center;
15 }
16}
17
18#sens, #volume {
19 background-image: linear-gradient(to right, #EEE, #555);
20}
21
22/* Slider control main bar */
23input[type="range"] {
24 appearance: none;
25 -moz-appearance: none;
26 -webkit-appearance: none;
27 border-radius: 3px;
28 height: 15px;
29 margin-bottom: 5px;
30 margin-top: 5px;
31 outline: none;
32 width: 100%;
33}
34/* Slider control icon */
35input[type="range"]::-webkit-slider-thumb {
36 appearance: none;
37 -moz-appearance: none;
38 -webkit-appearance: none;
39 background: image-url('wittle/slider.png');
40 background-size: 17px 33px;
41 height: 33px;
42 width: 17px;
43}
44input[type="range"]::-moz-range-thumb {
45 appearance: none;
46 -moz-appearance: none;
47 -webkit-appearance: none;
48 background: image-url('wittle/slider.png');
49 background-size: 17px 33px;
50 height: 33px;
51 width: 17px;
52}
53input[type="range"]::-ms-thumb {
54 appearance: none;
55 -moz-appearance: none;
56 -webkit-appearance: none;
57 background: image-url('wittle/slider.png');
58 background-size: 17px 33px;
59 height: 33px;
60 width: 17px;
61}
62
63#submission-form {
64 margin: 1em auto;
65 width: 540px;
66 text-align: center;
67
68 form {
69 border: 1px solid black;
70 width: max-content;
71 padding: 0 2em;
72 margin: 0 auto;
73 }
74}
75
76#scores {
77 display: flex;
78
79 div {
80 flex: 0 0 48%;
81
82 h2 {
83 text-align: center;
84 }
85
86 ol {
87 width: max-content;
88 margin: 0 auto;
89 }
90 }
91}
diff --git a/app/controllers/wittle/puzzles_controller.rb b/app/controllers/wittle/puzzles_controller.rb index 09a2524..9599307 100644 --- a/app/controllers/wittle/puzzles_controller.rb +++ b/app/controllers/wittle/puzzles_controller.rb
@@ -1,7 +1,41 @@
1module Wittle 1module Wittle
2 class PuzzlesController < ApplicationController 2 class PuzzlesController < ApplicationController
3 def about
4 @normal_puzzle = Puzzle.normal.order(created_at: :desc).first
5 @hard_puzzle = Puzzle.hard.order(created_at: :desc).first
6 end
7
3 def index 8 def index
4 @puzzle = WittleGenerator.new.generate_medium 9 #@puzzle = WittleGenerator.new.generate_medium
10 end
11
12 def show
13 @puzzle = Puzzle.find(params[:id])
14 @playable = @puzzle.latest? && !((session[:played_puzzles] || []).include? @puzzle.id)
15 end
16
17 def solve
18 @puzzle = Puzzle.find(params[:id])
19
20 raise ActiveRecord::RecordNotFound unless @puzzle.latest?
21
22 if @puzzle.solved_data.nil?
23 @puzzle.solved_data = params[:solved]
24 @puzzle.save!
25 end
26
27 session[:played_puzzles] ||= []
28 session[:played_puzzles] << @puzzle.id
29 end
30
31 def submit
32 @puzzle = Puzzle.find(params[:id])
33
34 raise ActiveRecord::RecordNotFound unless @puzzle.latest?
35
36 @puzzle.scores.create!(name: params[:name], ip: request.ip)
37
38 redirect_to @puzzle
5 end 39 end
6 end 40 end
7end 41end
diff --git a/app/models/wittle/puzzle.rb b/app/models/wittle/puzzle.rb index e118d8a..f9009bc 100644 --- a/app/models/wittle/puzzle.rb +++ b/app/models/wittle/puzzle.rb
@@ -8,5 +8,9 @@ module Wittle
8 8
9 validates :category, presence: true 9 validates :category, presence: true
10 enumerize :category, in: [:normal, :hard, :expert], scope: :shallow 10 enumerize :category, in: [:normal, :hard, :expert], scope: :shallow
11
12 def latest?
13 Puzzle.where(category: category).order(created_at: :desc).first.id == id
14 end
11 end 15 end
12end 16end
diff --git a/app/views/layouts/wittle/application.html.haml b/app/views/layouts/wittle/application.html.haml index 945ffc0..80519f4 100644 --- a/app/views/layouts/wittle/application.html.haml +++ b/app/views/layouts/wittle/application.html.haml
@@ -6,4 +6,5 @@
6 = csp_meta_tag 6 = csp_meta_tag
7 = stylesheet_link_tag "wittle/application", media: "all" 7 = stylesheet_link_tag "wittle/application", media: "all"
8 = javascript_include_tag "wittle/application" 8 = javascript_include_tag "wittle/application"
9 %body= yield 9 %body
10 #wrap= yield
diff --git a/app/views/wittle/puzzles/_handle_puzzle.html.erb b/app/views/wittle/puzzles/_handle_puzzle.html.erb new file mode 100644 index 0000000..3ac868e --- /dev/null +++ b/app/views/wittle/puzzles/_handle_puzzle.html.erb
@@ -0,0 +1,33 @@
1<script type="text/javascript">
2window.onload = function() {
3 <% if @playable %>
4 $("#sens").val(window.settings.sensitivity)
5 $("#sens").on("change", function() {
6 window.settings.sensitivity = this.value
7 })
8 $("#volume").val(parseFloat(window.settings.volume))
9 $("#volume").on("change", function() {
10 window.settings.volume = this.value
11 })
12 <% end %>
13
14 var puzzle = window.deserializePuzzle("<%= @puzzle.data %>")
15 draw(puzzle)
16
17 <% unless @playable %>
18 drawPath(puzzle, JSON.parse("<%= escape_javascript(sanitize @puzzle.solved_data) %>"))
19 window.trace = function() {}
20 <% end %>
21}
22
23<% if @playable %>
24window.TRACE_COMPLETION_FUNC = function(puzzle, rawPath) {
25 $.ajax({
26 type: "POST",
27 url: "<%= solve_puzzle_path(@puzzle, format: :js) %>",
28 data: { solved: JSON.stringify(rawPath) }
29 })
30}
31
32<% end %>
33</script>
diff --git a/app/views/wittle/puzzles/_submission.html.haml b/app/views/wittle/puzzles/_submission.html.haml new file mode 100644 index 0000000..744372a --- /dev/null +++ b/app/views/wittle/puzzles/_submission.html.haml
@@ -0,0 +1,7 @@
1%h3 Congrats!
2%p Would you like to submit your time?
3= form_with url: submit_puzzle_path(@puzzle) do |form|
4 %p
5 = form.label :name, "Name:"
6 = form.text_field :name
7 %p= form.submit "Submit"
diff --git a/app/views/wittle/puzzles/about.html.haml b/app/views/wittle/puzzles/about.html.haml new file mode 100644 index 0000000..628ba0b --- /dev/null +++ b/app/views/wittle/puzzles/about.html.haml
@@ -0,0 +1,3 @@
1%p by Hatkirby, with help from Sigma144 and jbzdarkid
2%p= link_to "Normal", @normal_puzzle
3%p= link_to "Hard", @hard_puzzle
diff --git a/app/views/wittle/puzzles/index.html.haml b/app/views/wittle/puzzles/index.html.haml index 9e12e8b..e69de29 100644 --- a/app/views/wittle/puzzles/index.html.haml +++ b/app/views/wittle/puzzles/index.html.haml
@@ -1,13 +0,0 @@
1%h1 Puzzles#index
2%p Find me in app/views/wittle/puzzles/index.html.haml
3:javascript
4 loadHeader("Unnamed Puzzle")
5%div{ style: "display: flex; justify-content: center; align-items: center"}
6 %svg#puzzle{ style: "pointer-events: auto"}
7:javascript
8 window.onload = function() {
9 //var puzzle = window.deserializePuzzle("_AAAAAA8PCQAAAEdlbmVyYXRlZAABAAAACAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAgAAQAAAAACAAAA/wABAAAAAAgAAQAAAAAIAAEAAAAACAABAAAAAAgAAQAAAAAIAAEAAQAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQABAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAAIAAEAAAAACAABAAAAAAgAAQAAAAAIAAEAAAAAAv////8AAQAAAAAIAAEAAAAAAv////8AAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAQEAAAAAAQAAAAABAAAAAAEAAQAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAIAAAD/AAEAAAAACAABAAAAAAgAAQAAAAAIAAEAAAAACAABAAAAAAgAAQAAAAAIAAEAAAAAAQAAAAEBAAAAAAEAAAAAAQAAAAABAAAAAQEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAAIAAEAAQAAAv////8AAQAAAAAIAAEAAAAAAv////8AAQAAAAACAAAA/wABAAAAAAIAAAD/AAEAAAAAAgAAAP8AAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAL/////AAEAAAAAAv////8AAQAAAAAIAAEAAAAACAABAAAAAAgAAQAAAAACAAAA/wABAAAAAAgAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAQAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAABAQAAAAABAAEAAAEAAAAAAQAAAAABAAAAAAL/////AAEAAAAAAgAAAP8AAQAAAAAIAAEAAAAAAv////8AAQAAAAACAAAA/wABAAAAAAIAAAD/AAEAAAAACAABAAEAAAEAAAAAAQABAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAgAAAP8AAQAAAAAIAAEAAAAAAv////8AAQAAAAAIAAEAAAAAAv////8AAQAAAAAIAAEAAAAACAABAAAAAAEAAAAIAQAAAAABAAAAAAEAAAAAAQABAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAAAAAQAAAAABAAAAAAEAAQAAAQAAAAABAAAAEAAAAAAN")
10 var puzzle = window.deserializePuzzle("#{@puzzle}")
11 draw(puzzle)
12 }
13
diff --git a/app/views/wittle/puzzles/show.html.haml b/app/views/wittle/puzzles/show.html.haml new file mode 100644 index 0000000..d5d8b00 --- /dev/null +++ b/app/views/wittle/puzzles/show.html.haml
@@ -0,0 +1,25 @@
1%h1 Wittle ##{@puzzle.id}
2#puzzle-container{ style: "display: flex; justify-content: center; align-items: center" }
3 %svg#puzzle{ style: "pointer-events: auto"}
4#submission-form
5- if @playable
6 %details#trace-settings
7 %summary Settings
8 .things
9 %label{ for: "sens" } Mouse Speed 2D
10 %input#sens{ type: "range", min: "0.1", max: "1.3", step: "0.1" }
11 %label{ for: "volume" } Volume
12 %input#volume{ type: "range", min: "0", max: "0.24", step: "0.02" }
13- else
14 #scores
15 #by-time
16 %h2 Fastest Solves
17 %ol
18 - @puzzle.scores.where("seconds_taken IS NOT NULL").order(seconds_taken: :asc).each do |score|
19 %li= score.name
20 #by-when
21 %h2 Completion Order
22 %ol
23 - @puzzle.scores.order(created_at: :desc).each do |score|
24 %li= score.name
25= render partial: "handle_puzzle"
diff --git a/app/views/wittle/puzzles/solve.js.erb b/app/views/wittle/puzzles/solve.js.erb new file mode 100644 index 0000000..12c2350 --- /dev/null +++ b/app/views/wittle/puzzles/solve.js.erb
@@ -0,0 +1 @@
$("#submission-form").html('<%= escape_javascript(render partial: "submission") %>');
diff --git a/config/routes.rb b/config/routes.rb index 6cf2832..8cae7ec 100644 --- a/config/routes.rb +++ b/config/routes.rb
@@ -1,3 +1,7 @@
1Wittle::Engine.routes.draw do 1Wittle::Engine.routes.draw do
2 get 'puzzles/index' 2 root to: 'puzzles#about'
3 get 'archive' => 'puzzles#index'
4 get ':id' => 'puzzles#show', as: 'puzzle'
5 post ':id/solve' => 'puzzles#solve', as: 'solve_puzzle'
6 post ':id/submit' => 'puzzles#submit', as: 'submit_puzzle'
3end 7end
diff --git a/db/migrate/20231028210722_create_wittle_scores.rb b/db/migrate/20231028210722_create_wittle_scores.rb index 9ae6413..aa49a13 100644 --- a/db/migrate/20231028210722_create_wittle_scores.rb +++ b/db/migrate/20231028210722_create_wittle_scores.rb
@@ -1,7 +1,7 @@
1class CreateWittleScores < ActiveRecord::Migration[7.1] 1class CreateWittleScores < ActiveRecord::Migration[7.1]
2 def change 2 def change
3 create_table :wittle_scores do |t| 3 create_table :wittle_scores do |t|
4 t.references :puzzle, null: false, foreign_key: true 4 t.references :puzzle, null: false
5 t.string :name 5 t.string :name
6 t.string :ip 6 t.string :ip
7 t.integer :seconds_taken 7 t.integer :seconds_taken
diff --git a/lib/tasks/wittle_tasks.rake b/lib/tasks/wittle_tasks.rake index 854e5c9..debf249 100644 --- a/lib/tasks/wittle_tasks.rake +++ b/lib/tasks/wittle_tasks.rake
@@ -1,4 +1,7 @@
1# desc "Explaining what the task does" 1namespace :wittle do
2# task :wittle do 2 desc "Generate new puzzles for the day"
3# # Task goes here 3 task :generate_puzzles => :environment do
4# end 4 Wittle::Puzzle.create(data: WittleGenerator.new.generate_easy, category: :normal)
5 Wittle::Puzzle.create(data: WittleGenerator.new.generate_medium, category: :hard)
6 end
7end
diff --git a/lib/wittle/engine.rb b/lib/wittle/engine.rb index 6b4feca..d42ea1a 100644 --- a/lib/wittle/engine.rb +++ b/lib/wittle/engine.rb
@@ -1,5 +1,7 @@
1require "enumerize" 1require "enumerize"
2require "haml" 2require "haml"
3require "jquery-rails"
4require "sassc-rails"
3require "wittle_generator/wittle_generator" 5require "wittle_generator/wittle_generator"
4 6
5module Wittle 7module Wittle
diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index 928cc3c..3b8bd7f 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb
@@ -29,5 +29,4 @@ ActiveRecord::Schema[7.1].define(version: 2023_10_28_210722) do
29 t.index ["puzzle_id"], name: "index_wittle_scores_on_puzzle_id" 29 t.index ["puzzle_id"], name: "index_wittle_scores_on_puzzle_id"
30 end 30 end
31 31
32 add_foreign_key "wittle_scores", "puzzles"
33end 32end
diff --git a/wittle.gemspec b/wittle.gemspec index 0c467e3..38741ba 100644 --- a/wittle.gemspec +++ b/wittle.gemspec
@@ -19,4 +19,6 @@ Gem::Specification.new do |s|
19 s.add_dependency "rice" 19 s.add_dependency "rice"
20 s.add_dependency "haml" 20 s.add_dependency "haml"
21 s.add_dependency "enumerize" 21 s.add_dependency "enumerize"
22 s.add_dependency 'sassc-rails'
23 s.add_dependency 'jquery-rails'
22end 24end