From 22e5161b4cf905020f46557e1013cf000ceb29e1 Mon Sep 17 00:00:00 2001 From: Chris Cochrun Date: Wed, 24 Apr 2024 08:22:53 -0500 Subject: [PATCH] moving to using htmx and the lisp server on camp forms --- TODO.org | 3 + assets/css/compiled/main.css | 70 +++++++++++ layouts/shortcodes/camp-form.html | 19 +-- src/main.lisp | 20 ++++ tailwind.config.js | 193 ++++++++++++++++++++++++++++++ 5 files changed, 298 insertions(+), 7 deletions(-) create mode 100644 tailwind.config.js diff --git a/TODO.org b/TODO.org index e7335bd..456c72a 100644 --- a/TODO.org +++ b/TODO.org @@ -3,6 +3,9 @@ :CATEGORY: dev :END: +* TODO Move to the lisp server and htmx +SCHEDULED: <2024-04-24 Wed> +I want to move all validation and form processing to the lisp server and htmx. This way I'm not doing javascript which is sometimes complicated since I use it so infrequently, however, this will likely be a bit more involved, so I'll need to learn htmx, but I think it'll be better in the end, since htmx more akin to what the web was supposed to be like. * DONE Fix bug in accepting multipart/form-data on lisp server The multiline text options do not grab the entire entry. I'll need to fix that by ensuring that the entire section is grabbed for every entry. * DONE Make single newline show up diff --git a/assets/css/compiled/main.css b/assets/css/compiled/main.css index 6429f2e..21f382c 100644 --- a/assets/css/compiled/main.css +++ b/assets/css/compiled/main.css @@ -4726,6 +4726,66 @@ pre { color: rgba(var(--color-neutral-500), var(--tw-text-opacity)); } +.invalid\:border-secondary-100:invalid { + --tw-border-opacity: 1; + border-color: rgba(var(--color-secondary-100), var(--tw-border-opacity)); +} + +.invalid\:text-secondary-600:invalid { + --tw-text-opacity: 1; + color: rgba(var(--color-secondary-600), var(--tw-text-opacity)); +} + +.invalid\:text-primary-600:invalid { + --tw-text-opacity: 1; + color: rgba(var(--color-primary-600), var(--tw-text-opacity)); +} + +.invalid\:text-secondary-100:invalid { + --tw-text-opacity: 1; + color: rgba(var(--color-secondary-100), var(--tw-text-opacity)); +} + +.invalid\:text-secondary-900:invalid { + --tw-text-opacity: 1; + color: rgba(var(--color-secondary-900), var(--tw-text-opacity)); +} + +.invalid\:text-\[\#660000\]:invalid { + --tw-text-opacity: 1; + color: rgb(102 0 0 / var(--tw-text-opacity)); +} + +.invalid\:text-\[\#990000\]:invalid { + --tw-text-opacity: 1; + color: rgb(153 0 0 / var(--tw-text-opacity)); +} + +.invalid\:text-\[\#FF0000\]:invalid { + --tw-text-opacity: 1; + color: rgb(255 0 0 / var(--tw-text-opacity)); +} + +.invalid\:text-\[\#F39\]:invalid { + --tw-text-opacity: 1; + color: rgb(255 51 153 / var(--tw-text-opacity)); +} + +.invalid\:ring-secondary-100:invalid { + --tw-ring-opacity: 1; + --tw-ring-color: rgba(var(--color-secondary-100), var(--tw-ring-opacity)); +} + +.invalid\:ring-secondary-900:invalid { + --tw-ring-opacity: 1; + --tw-ring-color: rgba(var(--color-secondary-900), var(--tw-ring-opacity)); +} + +.invalid\:ring-\[\#f39\]:invalid { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(255 51 153 / var(--tw-ring-opacity)); +} + .hover\:border-transparent:hover { border-color: transparent; } @@ -4913,6 +4973,16 @@ pre { --tw-ring-offset-color: transparent; } +.focus\:invalid\:border-\[\#f39\]:invalid:focus { + --tw-border-opacity: 1; + border-color: rgb(255 51 153 / var(--tw-border-opacity)); +} + +.focus\:invalid\:ring-\[\#f39\]:invalid:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(255 51 153 / var(--tw-ring-opacity)); +} + .group:hover .group-hover\:text-primary-600 { --tw-text-opacity: 1; color: rgba(var(--color-primary-600), var(--tw-text-opacity)); diff --git a/layouts/shortcodes/camp-form.html b/layouts/shortcodes/camp-form.html index 245079c..c6cc17b 100644 --- a/layouts/shortcodes/camp-form.html +++ b/layouts/shortcodes/camp-form.html @@ -1,6 +1,8 @@ {{ $formClasses := "bg-neutral-500 text-neutral-50 placeholder-neutral-300 focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 focus:ring-offset-transparent m-2 p-3 rounded-lg hover:bg-neutral-500 checked:text-neutral-500" }} {{ $requiredField := "* required" }} + +
-
+

Camp Form

@@ -213,11 +215,14 @@ class="basis-full form-input {{ $formClasses }}" required> - - + diff --git a/src/main.lisp b/src/main.lisp index b267b2a..1ec16d9 100644 --- a/src/main.lisp +++ b/src/main.lisp @@ -381,6 +381,26 @@ with the image attached" (:th (car row)) (:td (cdr row)))))))))))) +(hunchentoot:define-easy-handler (respond :uri "/camp-api") () + (uiop:println "hey") + (setf (hunchentoot:content-type*) "plain/text") + (let* ((request-type (hunchentoot:request-method hunchentoot:*request*)) + (data (hunchentoot:post-parameters* hunchentoot:*request*))) + (uiop:println (assoc "registration" data :test 'string=)) + (uiop:println (tbnl:headers-out*)) + (if (string= (cdr (assoc "registration" data :test 'string=)) "now") + (progn (uiop:println "did it") + (setf (hunchentoot:header-out "HX-Redirect") "https://secure.myvanco.com/L-Z772/campaign/C-13JPJ") + (uiop:println (tbnl:headers-out*)) + (uiop:println (hunchentoot:return-code*)) + (with-html-string + (:div + (:p "Payment")))) + (progn + (with-html-string + (:div + (:p "Thank You"))))))) + (defun define-post-form-handler (uri mail-function) "Take a uri and a mailer function and define a handler in hunchentoot for forms to POST to." diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..9b7a572 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,193 @@ +module.exports = { + content: [ + "./layouts/**/*.html", + "./content/**/*.{html,md}", + "./themes/blowfish/layouts/**/*.html", + "./themes/blowfish/content/**/*.{html,md}", + "./node_modules/tw-elements/dist/js/**/*.js" + ], + darkMode: "class", + theme: { + screens: { + 'sm': '640px', + 'md': '853px', + 'lg': '1024px', + 'xl': '1280px', + '2xl': '1536px', + }, + colors: { + transparent: "transparent", + neutral: { + DEFAULT: "rgba(var(--color-neutral), )", + 50: "rgba(var(--color-neutral-50), )", + 100: "rgba(var(--color-neutral-100), )", + 200: "rgba(var(--color-neutral-200), )", + 300: "rgba(var(--color-neutral-300), )", + 400: "rgba(var(--color-neutral-400), )", + 500: "rgba(var(--color-neutral-500), )", + 600: "rgba(var(--color-neutral-600), )", + 700: "rgba(var(--color-neutral-700), )", + 800: "rgba(var(--color-neutral-800), )", + 900: "rgba(var(--color-neutral-900), )", + }, + primary: { + 50: "rgba(var(--color-primary-50), )", + 100: "rgba(var(--color-primary-100), )", + 200: "rgba(var(--color-primary-200), )", + 300: "rgba(var(--color-primary-300), )", + 400: "rgba(var(--color-primary-400), )", + 500: "rgba(var(--color-primary-500), )", + 600: "rgba(var(--color-primary-600), )", + 700: "rgba(var(--color-primary-700), )", + 800: "rgba(var(--color-primary-800), )", + 900: "rgba(var(--color-primary-900), )", + }, + red: { + 50: "rgba(var(--color-red-50), )", + 100: "rgba(var(--color-red-100), )", + 200: "rgba(var(--color-red-200), )", + 300: "rgba(var(--color-red-300), )", + 400: "rgba(var(--color-red-400), )", + 500: "rgba(var(--color-red-500), )", + 600: "rgba(var(--color-red-600), )", + 700: "rgba(var(--color-red-700), )", + 800: "rgba(var(--color-red-800), )", + 900: "rgba(var(--color-red-900), )", + }, + secondary: { + 50: "rgba(var(--color-secondary-50), )", + 100: "rgba(var(--color-secondary-100), )", + 200: "rgba(var(--color-secondary-200), )", + 300: "rgba(var(--color-secondary-300), )", + 400: "rgba(var(--color-secondary-400), )", + 500: "rgba(var(--color-secondary-500), )", + 600: "rgba(var(--color-secondary-600), )", + 700: "rgba(var(--color-secondary-700), )", + 800: "rgba(var(--color-secondary-800), )", + 900: "rgba(var(--color-secondary-900), )", + }, + }, + extend: { + typography: ({ theme }) => ({ + DEFAULT: { + css: { + "--tw-prose-body": theme("colors.neutral.700 / 1"), + "--tw-prose-headings": theme("colors.neutral.800 / 1"), + "--tw-prose-lead": theme("colors.neutral.500 / 1"), + "--tw-prose-links": theme("colors.primary.600 / 1"), + "--tw-prose-bold": theme("colors.neutral.900 / 1"), + "--tw-prose-counters": theme("colors.neutral.800 / 1"), + "--tw-prose-bullets": theme("colors.neutral.500 / 1"), + "--tw-prose-hr": theme("colors.neutral.200 / 1"), + "--tw-prose-quotes": theme("colors.neutral.700 / 1"), + "--tw-prose-quote-borders": theme("colors.primary.200 / 1"), + "--tw-prose-captions": theme("colors.neutral.500 / 1"), + "--tw-prose-code": theme("colors.secondary.700 / 1"), + "--tw-prose-pre-code": theme("colors.neutral.700 / 1"), + "--tw-prose-pre-bg": theme("colors.neutral.50 / 1"), + "--tw-prose-th-borders": theme("colors.neutral.500 / 1"), + "--tw-prose-td-borders": theme("colors.neutral.300 / 1"), + "--tw-prose-invert-body": theme("colors.neutral.300 / 1"), + "--tw-prose-invert-headings": theme("colors.neutral.50 / 1"), + "--tw-prose-invert-lead": theme("colors.neutral.500 / 1"), + "--tw-prose-invert-links": theme("colors.primary.400 / 1"), + "--tw-prose-invert-bold": theme("colors.neutral.DEFAULT / 1"), + "--tw-prose-invert-counters": theme("colors.neutral.400 / 1"), + "--tw-prose-invert-bullets": theme("colors.neutral.600 / 1"), + "--tw-prose-invert-hr": theme("colors.neutral.500 / 1"), + "--tw-prose-invert-quotes": theme("colors.neutral.200 / 1"), + "--tw-prose-invert-quote-borders": theme("colors.primary.900 / 1"), + "--tw-prose-invert-captions": theme("colors.neutral.400 / 1"), + "--tw-prose-invert-code": theme("colors.secondary.400 / 1"), + "--tw-prose-invert-pre-code": theme("colors.neutral.200 / 1"), + "--tw-prose-invert-pre-bg": theme("colors.neutral.700 / 1"), + "--tw-prose-invert-th-borders": theme("colors.neutral.500 / 1"), + "--tw-prose-invert-td-borders": theme("colors.neutral.700 / 1"), + a: { + textDecoration: "none", + textDecorationColor: theme("colors.primary.300 / 1"), + fontWeight: "500", + "&:hover": { + color: theme("colors.primary.600 / 1"), + textDecoration: "none", + borderRadius: "0.09rem", + }, + }, + "a code": { + color: "var(--tw-prose-code)", + }, + kbd: { + backgroundColor: theme("colors.neutral.200 / 1"), + padding: "0.1rem 0.4rem", + borderRadius: "0.25rem", + fontSize: "0.9rem", + fontWeight: "600", + }, + mark: { + color: theme("colors.neutral.800 / 1"), + backgroundColor: theme("colors.primary.600 / 1"), + padding: "0.1rem 0.2rem", + borderRadius: "0.25rem", + }, + code:{ + backgroundColor: theme("colors.neutral.50 / 1"), + paddingTop: "3px", + paddingBottom: "3px", + paddingLeft: "5px", + paddingRight: "5px", + borderRadius: "0.25rem", + }, + 'code::before': { + display: 'none' + }, + 'code::after': { + display: 'none' + }, + 'p::before': { + display: 'none' + }, + 'p::after': { + display: 'none' + }, + 'a.active': { + "text-decoration-color": theme("colors.primary.600 / 1"), + }, + 'p.active': { + "text-decoration-color": theme("colors.primary.600 / 1"), + } + }, + }, + invert: { + css: { + a: { + textDecorationColor: theme("colors.neutral.600 / 1"), + "&:hover": { + color: theme("colors.primary.400 / 1"), + }, + }, + kbd: { + color: theme("colors.neutral.200 / 1"), + backgroundColor: theme("colors.neutral.700 / 1"), + }, + mark: { + backgroundColor: theme("colors.primary.400 / 1"), + }, + code:{ + backgroundColor: theme("colors.neutral.700 / 1"), + }, + 'a.active': { + "text-decoration-color": theme("colors.primary.400 / 1") + }, + 'p.active': { + "text-decoration-color": theme("colors.primary.400 / 1") + } + }, + }, + }), + }, + }, + plugins: [ + require("@tailwindcss/typography"), + require('@tailwindcss/forms'), + ], +};