tokra 0.0.1.pre.1 → 0.0.1.pre.2

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.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSES/MIT-0.txt +16 -0
  3. data/REUSE.toml +6 -1
  4. data/Rakefile +2 -0
  5. data/Steepfile +2 -0
  6. data/clippy_exceptions.rb +75 -37
  7. data/doc/contributors/adr/004.md +63 -0
  8. data/doc/contributors/chats/002.md +177 -0
  9. data/doc/contributors/chats/003.md +2180 -0
  10. data/doc/contributors/chats/004.md +1992 -0
  11. data/doc/contributors/chats/005.md +1529 -0
  12. data/doc/contributors/plan/002.md +173 -0
  13. data/doc/contributors/plan/003.md +111 -0
  14. data/examples/verify_hello_world/index.html +15 -2
  15. data/examples/verify_ping_pong/app.rb +3 -1
  16. data/examples/verify_ping_pong/public/styles.css +36 -9
  17. data/examples/verify_ping_pong/views/layout.erb +1 -1
  18. data/examples/verify_rails_sqlite/.dockerignore +51 -0
  19. data/examples/verify_rails_sqlite/.gitattributes +9 -0
  20. data/examples/verify_rails_sqlite/.github/dependabot.yml +12 -0
  21. data/examples/verify_rails_sqlite/.github/workflows/ci.yml +124 -0
  22. data/examples/verify_rails_sqlite/.gitignore +35 -0
  23. data/examples/verify_rails_sqlite/.kamal/hooks/docker-setup.sample +3 -0
  24. data/examples/verify_rails_sqlite/.kamal/hooks/post-app-boot.sample +3 -0
  25. data/examples/verify_rails_sqlite/.kamal/hooks/post-deploy.sample +14 -0
  26. data/examples/verify_rails_sqlite/.kamal/hooks/post-proxy-reboot.sample +3 -0
  27. data/examples/verify_rails_sqlite/.kamal/hooks/pre-app-boot.sample +3 -0
  28. data/examples/verify_rails_sqlite/.kamal/hooks/pre-build.sample +51 -0
  29. data/examples/verify_rails_sqlite/.kamal/hooks/pre-connect.sample +47 -0
  30. data/examples/verify_rails_sqlite/.kamal/hooks/pre-deploy.sample +122 -0
  31. data/examples/verify_rails_sqlite/.kamal/hooks/pre-proxy-reboot.sample +3 -0
  32. data/examples/verify_rails_sqlite/.kamal/secrets +20 -0
  33. data/examples/verify_rails_sqlite/.rubocop.yml +2 -0
  34. data/examples/verify_rails_sqlite/.ruby-version +1 -0
  35. data/examples/verify_rails_sqlite/Dockerfile +77 -0
  36. data/examples/verify_rails_sqlite/Gemfile +66 -0
  37. data/examples/verify_rails_sqlite/Gemfile.lock +563 -0
  38. data/examples/verify_rails_sqlite/README.md +41 -0
  39. data/examples/verify_rails_sqlite/Rakefile +6 -0
  40. data/examples/verify_rails_sqlite/app/assets/images/.keep +0 -0
  41. data/examples/verify_rails_sqlite/app/assets/stylesheets/application.css +469 -0
  42. data/examples/verify_rails_sqlite/app/controllers/application_controller.rb +12 -0
  43. data/examples/verify_rails_sqlite/app/controllers/concerns/.keep +0 -0
  44. data/examples/verify_rails_sqlite/app/controllers/todos_controller.rb +70 -0
  45. data/examples/verify_rails_sqlite/app/helpers/application_helper.rb +2 -0
  46. data/examples/verify_rails_sqlite/app/helpers/todos_helper.rb +2 -0
  47. data/examples/verify_rails_sqlite/app/javascript/application.js +3 -0
  48. data/examples/verify_rails_sqlite/app/javascript/controllers/application.js +9 -0
  49. data/examples/verify_rails_sqlite/app/javascript/controllers/hello_controller.js +7 -0
  50. data/examples/verify_rails_sqlite/app/javascript/controllers/index.js +4 -0
  51. data/examples/verify_rails_sqlite/app/jobs/application_job.rb +7 -0
  52. data/examples/verify_rails_sqlite/app/mailers/application_mailer.rb +4 -0
  53. data/examples/verify_rails_sqlite/app/models/application_record.rb +3 -0
  54. data/examples/verify_rails_sqlite/app/models/concerns/.keep +0 -0
  55. data/examples/verify_rails_sqlite/app/models/todo.rb +10 -0
  56. data/examples/verify_rails_sqlite/app/views/layouts/application.html.erb +24 -0
  57. data/examples/verify_rails_sqlite/app/views/layouts/mailer.html.erb +13 -0
  58. data/examples/verify_rails_sqlite/app/views/layouts/mailer.text.erb +1 -0
  59. data/examples/verify_rails_sqlite/app/views/pwa/manifest.json.erb +22 -0
  60. data/examples/verify_rails_sqlite/app/views/pwa/service-worker.js +26 -0
  61. data/examples/verify_rails_sqlite/app/views/todos/_form.html.erb +27 -0
  62. data/examples/verify_rails_sqlite/app/views/todos/_todo.html.erb +18 -0
  63. data/examples/verify_rails_sqlite/app/views/todos/_todo.json.jbuilder +2 -0
  64. data/examples/verify_rails_sqlite/app/views/todos/edit.html.erb +7 -0
  65. data/examples/verify_rails_sqlite/app/views/todos/index.html.erb +22 -0
  66. data/examples/verify_rails_sqlite/app/views/todos/index.json.jbuilder +1 -0
  67. data/examples/verify_rails_sqlite/app/views/todos/new.html.erb +7 -0
  68. data/examples/verify_rails_sqlite/app/views/todos/show.html.erb +23 -0
  69. data/examples/verify_rails_sqlite/app/views/todos/show.json.jbuilder +1 -0
  70. data/examples/verify_rails_sqlite/bin/brakeman +7 -0
  71. data/examples/verify_rails_sqlite/bin/bundler-audit +6 -0
  72. data/examples/verify_rails_sqlite/bin/ci +6 -0
  73. data/examples/verify_rails_sqlite/bin/dev +2 -0
  74. data/examples/verify_rails_sqlite/bin/docker-entrypoint +8 -0
  75. data/examples/verify_rails_sqlite/bin/importmap +4 -0
  76. data/examples/verify_rails_sqlite/bin/jobs +6 -0
  77. data/examples/verify_rails_sqlite/bin/kamal +16 -0
  78. data/examples/verify_rails_sqlite/bin/rails +4 -0
  79. data/examples/verify_rails_sqlite/bin/rake +4 -0
  80. data/examples/verify_rails_sqlite/bin/rubocop +8 -0
  81. data/examples/verify_rails_sqlite/bin/setup +35 -0
  82. data/examples/verify_rails_sqlite/bin/thrust +5 -0
  83. data/examples/verify_rails_sqlite/config/application.rb +27 -0
  84. data/examples/verify_rails_sqlite/config/boot.rb +4 -0
  85. data/examples/verify_rails_sqlite/config/bundler-audit.yml +5 -0
  86. data/examples/verify_rails_sqlite/config/cable.yml +17 -0
  87. data/examples/verify_rails_sqlite/config/cache.yml +16 -0
  88. data/examples/verify_rails_sqlite/config/ci.rb +24 -0
  89. data/examples/verify_rails_sqlite/config/credentials.yml.enc +1 -0
  90. data/examples/verify_rails_sqlite/config/database.yml +40 -0
  91. data/examples/verify_rails_sqlite/config/deploy.yml +119 -0
  92. data/examples/verify_rails_sqlite/config/environment.rb +5 -0
  93. data/examples/verify_rails_sqlite/config/environments/development.rb +84 -0
  94. data/examples/verify_rails_sqlite/config/environments/production.rb +99 -0
  95. data/examples/verify_rails_sqlite/config/environments/test.rb +53 -0
  96. data/examples/verify_rails_sqlite/config/importmap.rb +7 -0
  97. data/examples/verify_rails_sqlite/config/initializers/assets.rb +7 -0
  98. data/examples/verify_rails_sqlite/config/initializers/content_security_policy.rb +29 -0
  99. data/examples/verify_rails_sqlite/config/initializers/filter_parameter_logging.rb +8 -0
  100. data/examples/verify_rails_sqlite/config/initializers/inflections.rb +16 -0
  101. data/examples/verify_rails_sqlite/config/locales/en.yml +31 -0
  102. data/examples/verify_rails_sqlite/config/puma.rb +42 -0
  103. data/examples/verify_rails_sqlite/config/queue.yml +18 -0
  104. data/examples/verify_rails_sqlite/config/recurring.yml +15 -0
  105. data/examples/verify_rails_sqlite/config/routes.rb +15 -0
  106. data/examples/verify_rails_sqlite/config/storage.yml +27 -0
  107. data/examples/verify_rails_sqlite/config.ru +6 -0
  108. data/examples/verify_rails_sqlite/db/cable_schema.rb +11 -0
  109. data/examples/verify_rails_sqlite/db/cache_schema.rb +12 -0
  110. data/examples/verify_rails_sqlite/db/migrate/20260130080933_create_todos.rb +10 -0
  111. data/examples/verify_rails_sqlite/db/queue_schema.rb +129 -0
  112. data/examples/verify_rails_sqlite/db/schema.rb +20 -0
  113. data/examples/verify_rails_sqlite/db/seeds.rb +9 -0
  114. data/examples/verify_rails_sqlite/lib/tasks/.keep +0 -0
  115. data/examples/verify_rails_sqlite/log/.keep +0 -0
  116. data/examples/verify_rails_sqlite/public/400.html +135 -0
  117. data/examples/verify_rails_sqlite/public/404.html +135 -0
  118. data/examples/verify_rails_sqlite/public/406-unsupported-browser.html +135 -0
  119. data/examples/verify_rails_sqlite/public/422.html +135 -0
  120. data/examples/verify_rails_sqlite/public/500.html +135 -0
  121. data/examples/verify_rails_sqlite/public/icon.png +0 -0
  122. data/examples/verify_rails_sqlite/public/icon.svg +3 -0
  123. data/examples/verify_rails_sqlite/public/robots.txt +1 -0
  124. data/examples/verify_rails_sqlite/public/styles.css +469 -0
  125. data/examples/verify_rails_sqlite/script/.keep +0 -0
  126. data/examples/verify_rails_sqlite/storage/.keep +0 -0
  127. data/examples/verify_rails_sqlite/test/controllers/.keep +0 -0
  128. data/examples/verify_rails_sqlite/test/controllers/todos_controller_test.rb +48 -0
  129. data/examples/verify_rails_sqlite/test/fixtures/files/.keep +0 -0
  130. data/examples/verify_rails_sqlite/test/fixtures/todos.yml +9 -0
  131. data/examples/verify_rails_sqlite/test/helpers/.keep +0 -0
  132. data/examples/verify_rails_sqlite/test/integration/.keep +0 -0
  133. data/examples/verify_rails_sqlite/test/mailers/.keep +0 -0
  134. data/examples/verify_rails_sqlite/test/models/.keep +0 -0
  135. data/examples/verify_rails_sqlite/test/models/todo_test.rb +7 -0
  136. data/examples/verify_rails_sqlite/test/test_helper.rb +15 -0
  137. data/examples/verify_rails_sqlite/tmp/.keep +0 -0
  138. data/examples/verify_rails_sqlite/tmp/pids/.keep +0 -0
  139. data/examples/verify_rails_sqlite/tmp/storage/.keep +0 -0
  140. data/examples/verify_rails_sqlite/tokra.rb +42 -0
  141. data/examples/verify_rails_sqlite/vendor/.keep +0 -0
  142. data/examples/verify_rails_sqlite/vendor/javascript/.keep +0 -0
  143. data/ext/tokra/src/event_loop.rs +206 -0
  144. data/ext/tokra/src/events.rs +430 -0
  145. data/ext/tokra/src/lib.rs +52 -664
  146. data/ext/tokra/src/proxy.rs +142 -0
  147. data/ext/tokra/src/responders.rs +86 -0
  148. data/ext/tokra/src/user_event.rs +313 -0
  149. data/ext/tokra/src/webview.rs +194 -0
  150. data/ext/tokra/src/window.rs +92 -0
  151. data/lib/tokra/rack/handler.rb +37 -14
  152. data/lib/tokra/version.rb +1 -1
  153. data/rbs_exceptions.rb +12 -0
  154. data/sig/tokra.rbs +95 -1
  155. data/tasks/lint.rake +2 -2
  156. data/tasks/lint.rb +49 -0
  157. data/tasks/rust.rake +6 -23
  158. data/tasks/steep.rake +25 -3
  159. data/tasks/test.rake +1 -1
  160. metadata +143 -1
@@ -0,0 +1,135 @@
1
+ <!doctype html>
2
+
3
+ <html lang="en">
4
+
5
+ <head>
6
+
7
+ <title>We're sorry, but something went wrong (500 Internal Server Error)</title>
8
+
9
+ <meta charset="utf-8">
10
+ <meta name="viewport" content="initial-scale=1, width=device-width">
11
+ <meta name="robots" content="noindex, nofollow">
12
+
13
+ <style>
14
+
15
+ *, *::before, *::after {
16
+ box-sizing: border-box;
17
+ }
18
+
19
+ * {
20
+ margin: 0;
21
+ }
22
+
23
+ html {
24
+ font-size: 16px;
25
+ }
26
+
27
+ body {
28
+ background: #FFF;
29
+ color: #261B23;
30
+ display: grid;
31
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Aptos, Roboto, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
32
+ font-size: clamp(1rem, 2.5vw, 2rem);
33
+ -webkit-font-smoothing: antialiased;
34
+ font-style: normal;
35
+ font-weight: 400;
36
+ letter-spacing: -0.0025em;
37
+ line-height: 1.4;
38
+ min-height: 100dvh;
39
+ place-items: center;
40
+ text-rendering: optimizeLegibility;
41
+ -webkit-text-size-adjust: 100%;
42
+ }
43
+
44
+ #error-description {
45
+ fill: #d30001;
46
+ }
47
+
48
+ #error-id {
49
+ fill: #f0eff0;
50
+ }
51
+
52
+ @media (prefers-color-scheme: dark) {
53
+ body {
54
+ background: #101010;
55
+ color: #e0e0e0;
56
+ }
57
+
58
+ #error-description {
59
+ fill: #FF6161;
60
+ }
61
+
62
+ #error-id {
63
+ fill: #2c2c2c;
64
+ }
65
+ }
66
+
67
+ a {
68
+ color: inherit;
69
+ font-weight: 700;
70
+ text-decoration: underline;
71
+ text-underline-offset: 0.0925em;
72
+ }
73
+
74
+ b, strong {
75
+ font-weight: 700;
76
+ }
77
+
78
+ i, em {
79
+ font-style: italic;
80
+ }
81
+
82
+ main {
83
+ display: grid;
84
+ gap: 1em;
85
+ padding: 2em;
86
+ place-items: center;
87
+ text-align: center;
88
+ }
89
+
90
+ main header {
91
+ width: min(100%, 12em);
92
+ }
93
+
94
+ main header svg {
95
+ height: auto;
96
+ max-width: 100%;
97
+ width: 100%;
98
+ }
99
+
100
+ main article {
101
+ width: min(100%, 30em);
102
+ }
103
+
104
+ main article p {
105
+ font-size: 75%;
106
+ }
107
+
108
+ main article br {
109
+ display: none;
110
+
111
+ @media(min-width: 48em) {
112
+ display: inline;
113
+ }
114
+ }
115
+
116
+ </style>
117
+
118
+ </head>
119
+
120
+ <body>
121
+
122
+ <!-- This file lives in public/500.html -->
123
+
124
+ <main>
125
+ <header>
126
+ <svg height="172" viewBox="0 0 480 172" width="480" xmlns="http://www.w3.org/2000/svg"><path d="m101.23 93.8427c-8.1103 0-15.4098 3.7849-19.7354 8.3813h-36.2269v-99.21891h103.8143v37.03791h-68.3984v24.8722c5.1366-2.7035 15.1396-5.9477 24.6014-5.9477 35.146 0 56.233 22.7094 56.233 55.4215 0 34.605-23.791 57.315-60.558 57.315-37.8492 0-61.64-22.169-63.8028-55.963h42.9857c1.0814 10.814 9.1919 19.195 21.6281 19.195 11.355 0 19.465-8.381 19.465-20.547 0-11.625-7.299-20.5463-20.006-20.5463zm138.833 77.8613c-40.822 0-64.884-35.146-64.884-85.7015 0-50.5554 24.062-85.700907 64.884-85.700907 40.823 0 64.884 35.145507 64.884 85.700907 0 50.5555-24.061 85.7015-64.884 85.7015zm0-133.2831c-17.572 0-22.709 21.8984-22.709 47.5816 0 25.6835 5.137 47.5815 22.709 47.5815 17.303 0 22.71-21.898 22.71-47.5815 0-25.6832-5.407-47.5816-22.71-47.5816zm140.456 133.2831c-40.823 0-64.884-35.146-64.884-85.7015 0-50.5554 24.061-85.700907 64.884-85.700907 40.822 0 64.884 35.145507 64.884 85.700907 0 50.5555-24.062 85.7015-64.884 85.7015zm0-133.2831c-17.573 0-22.71 21.8984-22.71 47.5816 0 25.6835 5.137 47.5815 22.71 47.5815 17.302 0 22.709-21.898 22.709-47.5815 0-25.6832-5.407-47.5816-22.709-47.5816z" id="error-id"/><path d="m23.1377 68.9967v34.0033h-8.9162v-34.0033zm4.3157 34.0033v-24.921h8.6947v2.1598c1.3845-1.5506 3.8212-2.7136 6.701-2.7136 5.538 0 8.8054 3.5997 8.8054 9.1377v16.3371h-8.6393v-14.2327c0-2.049-1.0522-3.5443-3.2674-3.5443-1.7168 0-3.1567.9969-3.5997 2.7136v15.0634zm29.9913-8.5839v-9.5807h-3.655v-6.7564h3.655v-6.8671h8.5839v6.8671h5.2058v6.7564h-5.2058v8.307c0 1.9383.9415 2.769 2.6583 2.769.9414 0 1.9937-.2216 2.769-.5538v7.3654c-.9969.443-2.8798.775-4.8181.775-5.8703 0-9.1931-2.769-9.1931-9.0819zm32.3666-.1108h8.0301c-.8861 5.7597-5.2057 9.2487-11.6852 9.2487-7.6424 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.3165-13.0143 12.5159-13.0143 7.6424 0 11.9621 5.095 11.9621 12.5159v2.1598h-16.1156c.2769 2.9905 1.8275 4.5965 4.3196 4.5965 1.7722 0 3.1567-.7753 3.6551-2.4921zm-3.8212-10.0237c-2.0491 0-3.4336 1.2737-3.9874 3.5997h7.5317c-.1107-2.0491-1.3845-3.5997-3.5443-3.5997zm31.4299-6.3134v8.3624c-1.052-.5538-2.215-.7753-3.599-.7753-2.382 0-3.988 1.0522-4.431 2.8244v14.6203h-8.694v-24.921h8.694v2.2152c1.219-1.6614 3.157-2.769 5.649-2.769 1.108 0 1.994.2215 2.381.443zm2.949 25.0318v-24.921h8.694v2.1598c1.385-1.5506 3.821-2.7136 6.701-2.7136 5.538 0 8.806 3.5997 8.806 9.1377v16.3371h-8.64v-14.2327c0-2.049-1.052-3.5443-3.267-3.5443-1.717 0-3.157.9969-3.6 2.7136v15.0634zm50.371 0h-8.363v-1.274c-.83.831-3.323 1.717-5.981 1.717-4.929 0-9.082-2.769-9.082-8.0301 0-4.818 4.153-7.9193 9.581-7.9193 2.049 0 4.485.6646 5.482 1.3845v-1.606c0-1.606-.941-2.9905-3.046-2.9905-1.606 0-2.547.7199-2.935 1.8275h-8.196c.72-4.8181 4.984-8.6393 11.408-8.6393 7.089 0 11.132 3.7659 11.132 10.2453zm-8.363-6.9779v-1.4399c-.554-1.0522-2.049-1.7167-3.655-1.7167-1.717 0-3.433.7199-3.433 2.3813 0 1.7168 1.716 2.4367 3.433 2.4367 1.606 0 3.101-.6645 3.655-1.6614zm20.742-29.0191v35.997h-8.694v-35.997zm13.036 25.9178h9.248c.72 2.326 2.714 3.489 5.483 3.489 2.713 0 4.596-1.163 4.596-3.2674 0-1.6061-1.052-2.326-3.212-2.8244l-6.534-1.3845c-4.985-1.1076-8.751-3.7105-8.751-9.47 0-6.6456 5.538-11.0206 13.07-11.0206 8.307 0 13.014 4.5411 13.956 10.4114h-8.695c-.72-1.8829-2.27-3.3228-5.205-3.3228-2.548 0-4.265 1.1076-4.265 2.9905 0 1.4953 1.052 2.326 2.825 2.7137l6.645 1.5506c5.815 1.3845 9.027 4.5412 9.027 9.8023 0 6.9778-5.87 10.9654-13.291 10.9654-8.141 0-13.679-3.9322-14.897-10.6332zm46.509 1.3845h8.031c-.887 5.7597-5.206 9.2487-11.686 9.2487-7.642 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.317-13.0143 12.516-13.0143 7.643 0 11.962 5.095 11.962 12.5159v2.1598h-16.115c.277 2.9905 1.827 4.5965 4.319 4.5965 1.773 0 3.157-.7753 3.655-2.4921zm-3.821-10.0237c-2.049 0-3.433 1.2737-3.987 3.5997h7.532c-.111-2.0491-1.385-3.5997-3.545-3.5997zm31.431-6.3134v8.3624c-1.053-.5538-2.216-.7753-3.6-.7753-2.381 0-3.988 1.0522-4.431 2.8244v14.6203h-8.694v-24.921h8.694v2.2152c1.219-1.6614 3.157-2.769 5.649-2.769 1.108 0 1.994.2215 2.382.443zm18.288 25.0318h-7.809l-9.47-24.921h8.861l4.763 14.288 4.652-14.288h8.528zm25.614-8.6947h8.03c-.886 5.7597-5.206 9.2487-11.685 9.2487-7.642 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.316-13.0143 12.516-13.0143 7.642 0 11.962 5.095 11.962 12.5159v2.1598h-16.116c.277 2.9905 1.828 4.5965 4.32 4.5965 1.772 0 3.157-.7753 3.655-2.4921zm-3.821-10.0237c-2.049 0-3.434 1.2737-3.988 3.5997h7.532c-.111-2.0491-1.384-3.5997-3.544-3.5997zm31.43-6.3134v8.3624c-1.052-.5538-2.215-.7753-3.6-.7753-2.381 0-3.987 1.0522-4.43 2.8244v14.6203h-8.695v-24.921h8.695v2.2152c1.218-1.6614 3.157-2.769 5.649-2.769 1.107 0 1.993.2215 2.381.443zm13.703-8.9715h24.312v7.6424h-15.562v5.3165h14.232v7.4763h-14.232v5.8703h15.562v7.6978h-24.312zm44.667 8.9715v8.3624c-1.052-.5538-2.215-.7753-3.6-.7753-2.381 0-3.987 1.0522-4.43 2.8244v14.6203h-8.695v-24.921h8.695v2.2152c1.218-1.6614 3.156-2.769 5.648-2.769 1.108 0 1.994.2215 2.382.443zm19.673 0v8.3624c-1.053-.5538-2.216-.7753-3.6-.7753-2.381 0-3.987 1.0522-4.43 2.8244v14.6203h-8.695v-24.921h8.695v2.2152c1.218-1.6614 3.156-2.769 5.648-2.769 1.108 0 1.994.2215 2.382.443zm26.769 12.5713c0 7.6978-5.15 13.0145-12.737 13.0145-7.532 0-12.738-5.3167-12.738-13.0145s5.206-13.0143 12.738-13.0143c7.587 0 12.737 5.3165 12.737 13.0143zm-8.529 0c0-3.4336-1.495-5.8703-4.208-5.8703-2.659 0-4.154 2.4367-4.154 5.8703s1.495 5.8149 4.154 5.8149c2.713 0 4.208-2.3813 4.208-5.8149zm28.082-12.5713v8.3624c-1.052-.5538-2.215-.7753-3.6-.7753-2.381 0-3.987 1.0522-4.43 2.8244v14.6203h-8.695v-24.921h8.695v2.2152c1.218-1.6614 3.157-2.769 5.649-2.769 1.107 0 1.993.2215 2.381.443z" id="error-description"/></svg>
127
+ </header>
128
+ <article>
129
+ <p><strong>We're sorry, but something went wrong.</strong><br> If you're the application owner check the logs for more information.</p>
130
+ </article>
131
+ </main>
132
+
133
+ </body>
134
+
135
+ </html>
@@ -0,0 +1,3 @@
1
+ <svg width="512" height="512" xmlns="http://www.w3.org/2000/svg">
2
+ <circle cx="256" cy="256" r="256" fill="red"/>
3
+ </svg>
@@ -0,0 +1 @@
1
+ # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
@@ -0,0 +1,469 @@
1
+ /*
2
+ SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
+
4
+ SPDX-License-Identifier: AGPL-3.0-or-later
5
+ */
6
+
7
+ /*
8
+ * Tokra Tasks — "Refined Paper" aesthetic
9
+ * Warm cream palette, editorial serif typography, asymmetric layout
10
+ * NOTE: Using hex colors instead of OKLCH for WebView compatibiliy
11
+ */
12
+
13
+ *, *::before, *::after {
14
+ box-sizing: border-box;
15
+ margin: 0;
16
+ }
17
+
18
+ :root {
19
+ /* Typography - fall back to system fonts for desktop app */
20
+ --font-display: Georgia, 'Times New Roman', serif;
21
+ --font-body: system-ui, -apple-system, sans-serif;
22
+
23
+ /* Light mode: warm paper (hex equivalents of OKLCH values) */
24
+ --surface: #f5f3ed;
25
+ --surface-elevated: #fdfcfa;
26
+ --text: #3d3530;
27
+ --text-muted: #6b635b;
28
+ --accent: #8b4513;
29
+ --accent-hover: #6b3410;
30
+ --border: #ddd8d0;
31
+ --success: #2d6a4f;
32
+ --success-bg: #d8f3dc;
33
+ --strike: #a89f93;
34
+ --checkbox-bg: #e8e5de;
35
+ --focus-ring: #a0522d;
36
+ }
37
+
38
+ @media (prefers-color-scheme: dark) {
39
+ :root {
40
+ --surface: #1a1816;
41
+ --surface-elevated: #252220;
42
+ --text: #e8e5e0;
43
+ --text-muted: #9a958e;
44
+ --accent: #d4a574;
45
+ --accent-hover: #e5c09a;
46
+ --border: #3d3835;
47
+ --success: #74c69d;
48
+ --success-bg: #1e3a2a;
49
+ --strike: #6b655c;
50
+ --checkbox-bg: #353230;
51
+ --focus-ring: #cd9a6d;
52
+ }
53
+ }
54
+
55
+ html {
56
+ font-family: var(--font-body);
57
+ font-size: clamp(1rem, 0.95rem + 0.25vw, 1.0625rem);
58
+ line-height: 1.55;
59
+ color: var(--text);
60
+ background: var(--surface);
61
+ -webkit-font-smoothing: antialiased;
62
+ }
63
+
64
+ body {
65
+ min-height: 100dvh;
66
+ padding: clamp(1.5rem, 5vw, 4rem);
67
+ padding-block-start: clamp(2rem, 6vw, 5rem);
68
+ }
69
+
70
+ /* ═══════════════════════════════════════════════════════
71
+ NOTICE BANNER
72
+ ═══════════════════════════════════════════════════════ */
73
+
74
+ .notice {
75
+ position: fixed;
76
+ inset-block-start: 0;
77
+ inset-inline: 0;
78
+ padding: 0.75rem 1.5rem;
79
+ font-size: 0.875rem;
80
+ font-weight: 500;
81
+ text-align: center;
82
+ color: var(--success);
83
+ background: var(--success-bg);
84
+ border-block-end: 1px solid rgba(45, 106, 79, 0.2);
85
+ animation: notice-enter 0.3s ease-out;
86
+ }
87
+
88
+ @keyframes notice-enter {
89
+ from {
90
+ opacity: 0;
91
+ transform: translateY(-100%);
92
+ }
93
+ }
94
+
95
+ /* ═══════════════════════════════════════════════════════
96
+ PAGE HEADER
97
+ ═══════════════════════════════════════════════════════ */
98
+
99
+ .page-header {
100
+ max-width: 36rem;
101
+ margin-block-end: clamp(2rem, 4vw, 3rem);
102
+ }
103
+
104
+ .page-title {
105
+ font-family: var(--font-display);
106
+ font-size: clamp(2.25rem, 1.8rem + 2.25vw, 3.5rem);
107
+ font-weight: 400;
108
+ letter-spacing: -0.02em;
109
+ line-height: 1.1;
110
+ }
111
+
112
+ .page-subtitle {
113
+ margin-block-start: 0.5rem;
114
+ font-size: 1rem;
115
+ color: var(--text-muted);
116
+ }
117
+
118
+ /* ═══════════════════════════════════════════════════════
119
+ TODO LIST
120
+ ═══════════════════════════════════════════════════════ */
121
+
122
+ .todo-list {
123
+ list-style: none;
124
+ padding: 0;
125
+ max-width: 36rem;
126
+ }
127
+
128
+ .todo-item {
129
+ display: grid;
130
+ grid-template-columns: auto 1fr auto;
131
+ align-items: start;
132
+ gap: 1rem;
133
+ padding-block: 1rem;
134
+ border-block-end: 1px solid var(--border);
135
+ }
136
+
137
+ .todo-item:first-child {
138
+ padding-block-start: 0;
139
+ }
140
+
141
+ .todo-checkbox {
142
+ appearance: none;
143
+ width: 1.375rem;
144
+ height: 1.375rem;
145
+ margin-block-start: 0.1rem;
146
+ background: var(--checkbox-bg);
147
+ border: 1.5px solid var(--border);
148
+ border-radius: 4px;
149
+ cursor: pointer;
150
+ transition: border-color 0.15s, background 0.15s;
151
+ }
152
+
153
+ .todo-checkbox:hover {
154
+ border-color: var(--accent);
155
+ }
156
+
157
+ .todo-checkbox:checked {
158
+ background: var(--accent);
159
+ border-color: var(--accent);
160
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2.5-2.5a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E");
161
+ background-position: center;
162
+ background-repeat: no-repeat;
163
+ }
164
+
165
+ .todo-checkbox:focus-visible {
166
+ outline: 2px solid var(--focus-ring);
167
+ outline-offset: 2px;
168
+ }
169
+
170
+ .todo-content {
171
+ min-width: 0;
172
+ }
173
+
174
+ .todo-title {
175
+ font-family: var(--font-display);
176
+ font-size: 1.25rem;
177
+ font-weight: 400;
178
+ line-height: 1.35;
179
+ transition: color 0.2s;
180
+ }
181
+
182
+ .todo-title a {
183
+ color: inherit;
184
+ text-decoration: none;
185
+ }
186
+
187
+ .todo-title a:hover {
188
+ color: var(--accent);
189
+ }
190
+
191
+ .todo-item[data-completed="true"] .todo-title {
192
+ color: var(--strike);
193
+ text-decoration: line-through;
194
+ text-decoration-color: var(--strike);
195
+ }
196
+
197
+ .todo-actions {
198
+ display: flex;
199
+ gap: 0.5rem;
200
+ opacity: 0;
201
+ transition: opacity 0.15s;
202
+ }
203
+
204
+ .todo-item:hover .todo-actions,
205
+ .todo-item:focus-within .todo-actions {
206
+ opacity: 1;
207
+ }
208
+
209
+ /* ═══════════════════════════════════════════════════════
210
+ EMPTY STATE
211
+ ═══════════════════════════════════════════════════════ */
212
+
213
+ .empty-state {
214
+ max-width: 24rem;
215
+ padding-block: 3rem;
216
+ text-align: left;
217
+ }
218
+
219
+ .empty-state p {
220
+ color: var(--text-muted);
221
+ font-style: italic;
222
+ }
223
+
224
+ /* ═══════════════════════════════════════════════════════
225
+ BUTTONS & LINKS
226
+ ═══════════════════════════════════════════════════════ */
227
+
228
+ .btn {
229
+ display: inline-flex;
230
+ align-items: center;
231
+ gap: 0.375rem;
232
+ padding: 0.5rem 1rem;
233
+ font-family: var(--font-body);
234
+ font-size: 0.875rem;
235
+ font-weight: 500;
236
+ color: var(--surface-elevated);
237
+ background: var(--accent);
238
+ border: none;
239
+ border-radius: 6px;
240
+ cursor: pointer;
241
+ text-decoration: none;
242
+ transition: background 0.15s, transform 0.1s;
243
+ }
244
+
245
+ .btn:hover {
246
+ background: var(--accent-hover);
247
+ }
248
+
249
+ .btn:active {
250
+ transform: scale(0.98);
251
+ }
252
+
253
+ .btn:focus-visible {
254
+ outline: 2px solid var(--focus-ring);
255
+ outline-offset: 2px;
256
+ }
257
+
258
+ .btn--ghost {
259
+ padding: 0.375rem 0.625rem;
260
+ font-size: 0.8125rem;
261
+ color: var(--text-muted);
262
+ background: transparent;
263
+ border: 1px solid var(--border);
264
+ }
265
+
266
+ .btn--ghost:hover {
267
+ color: var(--text);
268
+ background: var(--surface-elevated);
269
+ border-color: var(--text-muted);
270
+ }
271
+
272
+ .btn--danger {
273
+ background: #b53d3d;
274
+ }
275
+
276
+ .btn--danger:hover {
277
+ background: #943030;
278
+ }
279
+
280
+ .link {
281
+ color: var(--accent);
282
+ text-decoration: underline;
283
+ text-decoration-color: rgba(139, 69, 19, 0.3);
284
+ text-underline-offset: 2px;
285
+ transition: text-decoration-color 0.15s;
286
+ }
287
+
288
+ .link:hover {
289
+ text-decoration-color: var(--accent);
290
+ }
291
+
292
+ .link--muted {
293
+ color: var(--text-muted);
294
+ text-decoration-color: var(--border);
295
+ }
296
+
297
+ .link--muted:hover {
298
+ color: var(--text);
299
+ }
300
+
301
+ /* ═══════════════════════════════════════════════════════
302
+ FORMS
303
+ ═══════════════════════════════════════════════════════ */
304
+
305
+ .form {
306
+ max-width: 28rem;
307
+ }
308
+
309
+ .field {
310
+ margin-block-end: 1.5rem;
311
+ }
312
+
313
+ .field label {
314
+ display: block;
315
+ margin-block-end: 0.375rem;
316
+ font-size: 0.875rem;
317
+ font-weight: 500;
318
+ color: var(--text-muted);
319
+ }
320
+
321
+ .field input[type="text"],
322
+ .field textarea {
323
+ width: 100%;
324
+ padding: 0.625rem 0.875rem;
325
+ font-family: var(--font-display);
326
+ font-size: 1.125rem;
327
+ color: var(--text);
328
+ background: var(--surface-elevated);
329
+ border: 1.5px solid var(--border);
330
+ border-radius: 6px;
331
+ transition: border-color 0.15s, box-shadow 0.15s;
332
+ }
333
+
334
+ .field input[type="text"]:focus,
335
+ .field textarea:focus {
336
+ outline: none;
337
+ border-color: var(--accent);
338
+ box-shadow: 0 0 0 3px rgba(139, 69, 19, 0.15);
339
+ }
340
+
341
+ .field input[type="text"]::placeholder {
342
+ color: var(--text-muted);
343
+ opacity: 0.6;
344
+ }
345
+
346
+ .field-checkbox {
347
+ display: flex;
348
+ align-items: center;
349
+ gap: 0.625rem;
350
+ }
351
+
352
+ .field-checkbox label {
353
+ margin: 0;
354
+ font-size: 0.9375rem;
355
+ color: var(--text);
356
+ cursor: pointer;
357
+ }
358
+
359
+ .field-checkbox input[type="checkbox"] {
360
+ appearance: none;
361
+ width: 1.25rem;
362
+ height: 1.25rem;
363
+ background: var(--checkbox-bg);
364
+ border: 1.5px solid var(--border);
365
+ border-radius: 4px;
366
+ cursor: pointer;
367
+ transition: border-color 0.15s, background 0.15s;
368
+ }
369
+
370
+ .field-checkbox input[type="checkbox"]:checked {
371
+ background: var(--accent);
372
+ border-color: var(--accent);
373
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2.5-2.5a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E");
374
+ background-position: center;
375
+ background-repeat: no-repeat;
376
+ }
377
+
378
+ .form-actions {
379
+ display: flex;
380
+ gap: 1rem;
381
+ align-items: center;
382
+ margin-block-start: 2rem;
383
+ }
384
+
385
+ .error-list {
386
+ margin-block-end: 1.5rem;
387
+ padding: 1rem;
388
+ background: #f8e8e8;
389
+ border-inline-start: 3px solid #b53d3d;
390
+ border-radius: 0 6px 6px 0;
391
+ }
392
+
393
+ @media (prefers-color-scheme: dark) {
394
+ .error-list {
395
+ background: #2d1f1f;
396
+ }
397
+ }
398
+
399
+ .error-list h2 {
400
+ font-size: 0.875rem;
401
+ font-weight: 600;
402
+ color: #b53d3d;
403
+ margin-block-end: 0.5rem;
404
+ }
405
+
406
+ @media (prefers-color-scheme: dark) {
407
+ .error-list h2 {
408
+ color: #e57575;
409
+ }
410
+ }
411
+
412
+ .error-list ul {
413
+ margin: 0;
414
+ padding-inline-start: 1.25rem;
415
+ font-size: 0.875rem;
416
+ }
417
+
418
+ /* ═══════════════════════════════════════════════════════
419
+ DETAIL VIEW
420
+ ═══════════════════════════════════════════════════════ */
421
+
422
+ .detail {
423
+ max-width: 36rem;
424
+ }
425
+
426
+ .detail-title {
427
+ font-family: var(--font-display);
428
+ font-size: clamp(1.75rem, 1.4rem + 1.75vw, 2.5rem);
429
+ font-weight: 400;
430
+ letter-spacing: -0.015em;
431
+ line-height: 1.2;
432
+ margin-block-end: 0.75rem;
433
+ }
434
+
435
+ .detail-status {
436
+ display: inline-flex;
437
+ align-items: center;
438
+ gap: 0.375rem;
439
+ padding: 0.25rem 0.625rem;
440
+ font-size: 0.8125rem;
441
+ font-weight: 500;
442
+ border-radius: 100px;
443
+ }
444
+
445
+ .detail-status--pending {
446
+ color: var(--accent);
447
+ background: rgba(139, 69, 19, 0.12);
448
+ }
449
+
450
+ .detail-status--complete {
451
+ color: var(--success);
452
+ background: var(--success-bg);
453
+ }
454
+
455
+ .detail-actions {
456
+ display: flex;
457
+ gap: 0.75rem;
458
+ margin-block-start: 2.5rem;
459
+ padding-block-start: 1.5rem;
460
+ border-block-start: 1px solid var(--border);
461
+ }
462
+
463
+ /* ═══════════════════════════════════════════════════════
464
+ UTILITIES
465
+ ═══════════════════════════════════════════════════════ */
466
+
467
+ .mt-4 { margin-block-start: 1rem; }
468
+ .mt-6 { margin-block-start: 1.5rem; }
469
+ .mt-8 { margin-block-start: 2rem; }
File without changes
File without changes
@@ -0,0 +1,48 @@
1
+ require "test_helper"
2
+
3
+ class TodosControllerTest < ActionDispatch::IntegrationTest
4
+ setup do
5
+ @todo = todos(:one)
6
+ end
7
+
8
+ test "should get index" do
9
+ get todos_url
10
+ assert_response :success
11
+ end
12
+
13
+ test "should get new" do
14
+ get new_todo_url
15
+ assert_response :success
16
+ end
17
+
18
+ test "should create todo" do
19
+ assert_difference("Todo.count") do
20
+ post todos_url, params: { todo: { completed: @todo.completed, title: @todo.title } }
21
+ end
22
+
23
+ assert_redirected_to todo_url(Todo.last)
24
+ end
25
+
26
+ test "should show todo" do
27
+ get todo_url(@todo)
28
+ assert_response :success
29
+ end
30
+
31
+ test "should get edit" do
32
+ get edit_todo_url(@todo)
33
+ assert_response :success
34
+ end
35
+
36
+ test "should update todo" do
37
+ patch todo_url(@todo), params: { todo: { completed: @todo.completed, title: @todo.title } }
38
+ assert_redirected_to todo_url(@todo)
39
+ end
40
+
41
+ test "should destroy todo" do
42
+ assert_difference("Todo.count", -1) do
43
+ delete todo_url(@todo)
44
+ end
45
+
46
+ assert_redirected_to todos_url
47
+ end
48
+ end
@@ -0,0 +1,9 @@
1
+ # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2
+
3
+ one:
4
+ title: MyString
5
+ completed: false
6
+
7
+ two:
8
+ title: MyString
9
+ completed: false
File without changes
File without changes
File without changes
@@ -0,0 +1,7 @@
1
+ require "test_helper"
2
+
3
+ class TodoTest < ActiveSupport::TestCase
4
+ # test "the truth" do
5
+ # assert true
6
+ # end
7
+ end