diff --git a/.air.toml b/.air.toml index fa8d9aa..65789a7 100644 --- a/.air.toml +++ b/.air.toml @@ -12,16 +12,16 @@ tmp_dir = "tmp" exclude_regex = ["_test.go"] exclude_unchanged = false follow_symlink = false - full_bin = "RULESET=./ruleset.yaml ./tmp/main" + full_bin = "./tmp/main --ruleset ./ruleset.yaml" include_dir = [] - include_ext = ["go", "tpl", "tmpl", "yaml", "html"] + include_ext = ["go", "tpl", "tmpl", "yaml", "html", "js"] include_file = [] kill_delay = "0s" log = "build-errors.log" poll = false poll_interval = 0 post_cmd = [] - pre_cmd = ["echo 'dev' > handlers/VERSION"] + pre_cmd = ["git rev-parse --short HEAD > handlers/VERSION; git rev-parse --short HEAD > cmd/VERSION"] rerun = false rerun_delay = 500 send_interrupt = false diff --git a/.github/workflows/build-css.yaml b/.github/workflows/build-css.yaml index 47a3365..9800ca9 100644 --- a/.github/workflows/build-css.yaml +++ b/.github/workflows/build-css.yaml @@ -4,6 +4,7 @@ on: push: paths: - "handlers/form.html" + - "proxychain/responsemodifiers/generate_readable_outline.html" workflow_dispatch: jobs: diff --git a/cmd/main.go b/cmd/main.go index 5e43605..32b468d 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -210,12 +210,12 @@ func main() { RulesetPath: *ruleset, } - app.Get("api/content/*", handlers.NewAPIOutlineHandler("api/outline/*", proxyOpts)) + app.Get("api/content/*", handlers.NewAPIContentHandler("api/outline/*", proxyOpts)) app.Get("outline/*", handlers.NewOutlineHandler("outline/*", proxyOpts)) app.All("/*", handlers.NewProxySiteHandler(proxyOpts)) - fmt.Println(cli.StartupMessage("1.0.0", *port, *ruleset)) + fmt.Println(cli.StartupMessage(version, *port, *ruleset)) log.Fatal(app.Listen(":" + *port)) } diff --git a/cmd/script.js b/cmd/script.js index ce87a46..c430c4e 100644 --- a/cmd/script.js +++ b/cmd/script.js @@ -159,13 +159,17 @@ const handleFontChange = () => { if (mainElement === null) { return; } - const font = localStorage.getItem("font"); - if (font === "sans-serif") { - mainElement.classList.add("font-sans"); - mainElement.classList.remove("font-serif"); - } else { + let font = localStorage.getItem("font"); + if (font === null) { + localStorage.setItem("font", "sans-serif"); + font = "sans-serif"; + } + if (font === "serif") { mainElement.classList.add("font-serif"); mainElement.classList.remove("font-sans"); + } else { + mainElement.classList.add("font-sans"); + mainElement.classList.remove("font-serif"); } }; @@ -179,9 +183,10 @@ const changeFontSize = (node, classes) => { "text-2xl", "text-3xl", "text-4xl", - "sm:text-3xl", - "sm:text-4xl", - "sm:text-5xl", + "text-5xl", + "lg:text-4xl", + "lg:text-5xl", + "lg:text-6xl", ]; const currentClasses = sizes.filter((size) => node.classList.contains(size)); node.classList.remove(...currentClasses); @@ -192,9 +197,21 @@ const handleFontSizeChange = () => { if (mainElement === null) { return; } - const fontSize = localStorage.getItem("fontsize"); + let fontSize = localStorage.getItem("fontsize"); + if (fontSize === null) { + localStorage.setItem("fontsize", "text-base"); + fontSize = "text-base"; + } + if (fontSize === "text-sm") { + changeFontSize(document.querySelector("body"), ["text-sm"]); + } else if (fontSize === "text-lg") { + changeFontSize(document.querySelector("body"), ["text-lg"]); + } else { + changeFontSize(document.querySelector("body"), ["text-base"]); + } + const nodes = document.querySelectorAll( - "h1, h2, h3, h4, code, pre, kbd, table" + "h1, h2, h3, h4, h5, h6, code, pre, kbd, table" ); if (fontSize === "text-sm") { changeFontSize(mainElement, ["text-sm"]); @@ -208,12 +225,13 @@ const handleFontSizeChange = () => { switch (node.tagName) { case "H1": { if (fontSize === "text-sm") { - classes = ["text-2xl", "sm:text-3xl"]; + classes = ["text-3xl", "lg:text-4xl"]; } else if (fontSize === "text-lg") { - classes = ["text-4xl", "sm:text-5xl"]; + classes = ["text-5xl", "lg:text-6xl"]; } else { - classes = ["text-3xl", "sm:text-4xl"]; + classes = ["text-4xl", "lg:text-5xl"]; } + break; } case "H2": { if (fontSize === "text-sm") { @@ -235,7 +253,9 @@ const handleFontSizeChange = () => { } break; } - case "H4": { + case "H4": + case "H5": + case "H6": { if (fontSize === "text-sm") { classes = ["text-lg"]; } else if (fontSize === "text-lg") { @@ -259,6 +279,13 @@ const handleFontSizeChange = () => { break; } default: { + if (fontSize === "text-sm") { + classes = ["text-sm"]; + } else if (fontSize === "text-lg") { + classes = ["text-lg"]; + } else { + classes = ["text-base"]; + } break; } } diff --git a/cmd/styles.css b/cmd/styles.css index 14fcb71..5923f13 100644 --- a/cmd/styles.css +++ b/cmd/styles.css @@ -1 +1 @@ -*,::after,::before{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}::after,::before{--tw-content:''}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}a{--tw-text-opacity:1;color:rgb(71 85 105 / var(--tw-text-opacity));text-underline-offset:2px;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(0.4,0,0.2,1);transition-duration:.3s}a:hover{--tw-text-opacity:1;color:rgb(59 130 246 / var(--tw-text-opacity));text-decoration-line:underline}:is(.dark a){--tw-text-opacity:1;color:rgb(148 163 184 / var(--tw-text-opacity))}:is(.dark a:hover){--tw-text-opacity:1;color:rgb(59 130 246 / var(--tw-text-opacity))}h1{font-size:1.875rem;line-height:2.25rem;font-weight:800;letter-spacing:-.025em;--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark h1){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}@media (min-width:640px){h1{font-size:2.25rem;line-height:2.5rem}}h2{scroll-margin:5rem;border-bottom-width:1px;padding-bottom:.5rem;font-size:1.875rem;line-height:2.25rem;font-weight:600;letter-spacing:-.025em;--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}h2:first-child{margin-top:0}:is(.dark h2){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}h3{scroll-margin:5rem;font-size:1.5rem;line-height:2rem;font-weight:600;letter-spacing:-.025em;--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark h3){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}h4,h5,h6{scroll-margin:5rem;font-size:1.25rem;line-height:1.75rem;font-weight:600;letter-spacing:-.025em;--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark h4),:is(.dark h5),:is(.dark h6){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}p{line-height:1.75rem;--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark p){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}p:not(:first-child){margin-top:1.5rem}code,kbd{position:relative;border-radius:.25rem;--tw-bg-opacity:1;background-color:rgb(226 232 240 / var(--tw-bg-opacity));padding-left:.3rem;padding-right:.3rem;padding-top:.2rem;padding-bottom:.2rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:.875rem;line-height:1.25rem;font-weight:600}:is(.dark code),:is(.dark kbd){--tw-bg-opacity:1;background-color:rgb(30 41 59 / var(--tw-bg-opacity))}blockquote{margin-top:1.5rem;border-left-width:2px;padding-left:1.5rem;font-style:italic}ul{margin-top:1.5rem;margin-bottom:1.5rem;margin-left:1.5rem;list-style-type:disc;--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark ul){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}ul>li{margin-top:.5rem}ol{margin-top:1.5rem;margin-bottom:1.5rem;margin-left:1.5rem;list-style-type:decimal;--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark ol){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}ol>li{margin-top:.5rem}dl{margin-top:1.5rem;margin-bottom:1.5rem;font-weight:700;--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark dl){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}dl>dd{margin-left:1.5rem;font-weight:400}dl>dt{margin-top:.75rem}li{--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark li){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}table{width:100%;caption-side:bottom;font-size:.875rem;line-height:1.25rem}thead tr{border-bottom-width:1px}tbody tr:last-child{border-width:0}tfoot{border-top-width:1px;--tw-border-opacity:1;border-color:rgb(148 163 184 / var(--tw-border-opacity));background-color:rgb(51 65 85 / .5);font-weight:500}:is(.dark tfoot){--tw-border-opacity:1;border-color:rgb(51 65 85 / var(--tw-border-opacity));background-color:rgb(226 232 240 / .5)}tfoot:last-child>tr{border-bottom-width:0}tr{border-bottom-width:1px;--tw-border-opacity:1;border-color:rgb(148 163 184 / var(--tw-border-opacity));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(0.4,0,0.2,1);transition-duration:150ms}tr:hover{background-color:rgb(226 232 240 / .5)}tr[data-state=selected]{--tw-bg-opacity:1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}:is(.dark tr){--tw-border-opacity:1;border-color:rgb(51 65 85 / var(--tw-border-opacity))}:is(.dark tr:hover){background-color:rgb(51 65 85 / .5)}:is(.dark tr[data-state=selected]){--tw-bg-opacity:1;background-color:rgb(226 232 240 / var(--tw-bg-opacity))}th{height:3rem;padding-left:1rem;padding-right:1rem;text-align:left;vertical-align:middle;font-weight:500;--tw-text-opacity:1;color:rgb(71 85 105 / var(--tw-text-opacity))}:is(.dark th){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}th:has([role=checkbox]){padding-right:0}td{padding:1rem;vertical-align:middle}td:has([role=checkbox]){padding-right:0}caption{margin-top:1rem;font-size:.875rem;line-height:1.25rem;--tw-text-opacity:1;color:rgb(71 85 105 / var(--tw-text-opacity))}:is(.dark caption){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}img{margin-left:auto;margin-right:auto;height:auto;width:auto;max-width:100%;border-radius:.375rem;-o-object-fit:cover;object-fit:cover;--tw-shadow:0 4px 6px -1px rgb(0 0 0 / 0.1),0 2px 4px -2px rgb(0 0 0 / 0.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}:is(.dark img){--tw-shadow-color:#334155;--tw-shadow:var(--tw-shadow-colored)}figcaption{margin-top:.5rem;font-size:.875rem;line-height:1.25rem;--tw-text-opacity:1;color:rgb(71 85 105 / var(--tw-text-opacity))}:is(.dark figcaption){--tw-text-opacity:1;color:rgb(148 163 184 / var(--tw-text-opacity))}hr{height:1px;width:100%;flex-shrink:0;--tw-bg-opacity:1;background-color:rgb(226 232 240 / var(--tw-bg-opacity))}:is(.dark hr){--tw-bg-opacity:1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}*,::after,::before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.absolute{position:absolute}.relative{position:relative}.inset-y-0{top:0;bottom:0}.right-0{right:0}.z-10{z-index:10}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.-mt-12{margin-top:-3rem}.ml-2{margin-left:.5rem}.mt-2{margin-top:.5rem}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-12{height:3rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-\[250px\]{height:250px}.w-10{width:2.5rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-52{width:13rem}.w-full{width:100%}.max-w-3xl{max-width:48rem}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap-reverse{flex-wrap:wrap-reverse}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-x-10{-moz-column-gap:2.5rem;column-gap:2.5rem}.gap-y-4{row-gap:1rem}.place-self-end{place-self:end}.whitespace-nowrap{white-space:nowrap}.rounded-full{border-radius:9999px}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184 / var(--tw-border-opacity))}.bg-slate-200{--tw-bg-opacity:1;background-color:rgb(226 232 240 / var(--tw-bg-opacity))}.bg-slate-800{--tw-bg-opacity:1;background-color:rgb(30 41 59 / var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.p-2{padding:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.px-8{padding-left:2rem;padding-right:2rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.pl-2{padding-left:.5rem}.pr-2{padding-right:.5rem}.pr-3{padding-right:.75rem}.pt-10{padding-top:2.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.leading-6{line-height:1.5rem}.tracking-tight{letter-spacing:-.025em}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28 / var(--tw-text-opacity))}.text-slate-200{--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}.text-slate-400{--tw-text-opacity:1;color:rgb(148 163 184 / var(--tw-text-opacity))}.text-slate-600{--tw-text-opacity:1;color:rgb(71 85 105 / var(--tw-text-opacity))}.text-slate-900{--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}.underline-offset-2{text-underline-offset:2px}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.shadow-md{--tw-shadow:0 4px 6px -1px rgb(0 0 0 / 0.1),0 2px 4px -2px rgb(0 0 0 / 0.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgb(0 0 0 / 0.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-slate-900\/10{--tw-ring-color:rgb(15 23 42 / 0.1)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(0.4,0,0.2,1);transition-duration:150ms}.duration-300{transition-duration:.3s}.first-of-type\:rounded-t-md:first-of-type{border-top-left-radius:.375rem;border-top-right-radius:.375rem}.last-of-type\:rounded-b-md:last-of-type{border-bottom-right-radius:.375rem;border-bottom-left-radius:.375rem}.hover\:bg-slate-200:hover{--tw-bg-opacity:1;background-color:rgb(226 232 240 / var(--tw-bg-opacity))}.hover\:bg-slate-200\/90:hover{background-color:rgb(226 232 240 / .9)}.hover\:bg-slate-800\/90:hover{background-color:rgb(30 41 59 / .9)}.hover\:text-blue-500:hover{--tw-text-opacity:1;color:rgb(59 130 246 / var(--tw-text-opacity))}.hover\:text-slate-400:hover{--tw-text-opacity:1;color:rgb(148 163 184 / var(--tw-text-opacity))}.hover\:text-slate-500:hover{--tw-text-opacity:1;color:rgb(100 116 139 / var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.hover\:ring-slate-300:hover{--tw-ring-opacity:1;--tw-ring-color:rgb(203 213 225 / var(--tw-ring-opacity))}.hover\:drop-shadow-\[0_0px_10px_rgba\(122\2c 167\2c 209\2c \.3\)\]:hover{--tw-drop-shadow:drop-shadow(0 0px 10px rgba(122,167,209,.3));filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}.peer:checked~.peer-checked\:bg-slate-200{--tw-bg-opacity:1;background-color:rgb(226 232 240 / var(--tw-bg-opacity))}:is(.dark .dark\:border-slate-700){--tw-border-opacity:1;border-color:rgb(51 65 85 / var(--tw-border-opacity))}:is(.dark .dark\:bg-slate-200){--tw-bg-opacity:1;background-color:rgb(226 232 240 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-slate-800){--tw-bg-opacity:1;background-color:rgb(30 41 59 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-slate-900){--tw-bg-opacity:1;background-color:rgb(15 23 42 / var(--tw-bg-opacity))}:is(.dark .dark\:text-red-400){--tw-text-opacity:1;color:rgb(248 113 113 / var(--tw-text-opacity))}:is(.dark .dark\:text-slate-200){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}:is(.dark .dark\:text-slate-400){--tw-text-opacity:1;color:rgb(148 163 184 / var(--tw-text-opacity))}:is(.dark .dark\:text-slate-900){--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark .dark\:hover\:bg-slate-200\/90:hover){background-color:rgb(226 232 240 / .9)}:is(.dark .dark\:hover\:bg-slate-700:hover){--tw-bg-opacity:1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-slate-800\/90:hover){background-color:rgb(30 41 59 / .9)}:is(.dark .dark\:hover\:text-blue-500:hover){--tw-text-opacity:1;color:rgb(59 130 246 / var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-slate-200:hover){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}:is(.dark .hover\:dark\:text-slate-300):hover{--tw-text-opacity:1;color:rgb(203 213 225 / var(--tw-text-opacity))}:is(.dark .peer:checked ~ .dark\:peer-checked\:bg-slate-700){--tw-bg-opacity:1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}@media (min-width:640px){.sm\:text-4xl{font-size:2.25rem;line-height:2.5rem}}.\[\&\:not\(\:first-child\)\]\:mt-0:not(:first-child){margin-top:0} +*,::after,::before{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}::after,::before{--tw-content:''}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}a{--tw-text-opacity:1;color:rgb(71 85 105 / var(--tw-text-opacity));text-underline-offset:2px;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(0.4,0,0.2,1);transition-duration:.3s}a:hover{--tw-text-opacity:1;color:rgb(59 130 246 / var(--tw-text-opacity));text-decoration-line:underline}:is(.dark a){--tw-text-opacity:1;color:rgb(148 163 184 / var(--tw-text-opacity))}:is(.dark a:hover){--tw-text-opacity:1;color:rgb(59 130 246 / var(--tw-text-opacity))}h1{font-size:1.875rem;line-height:2.25rem;font-weight:800;letter-spacing:-.025em;--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark h1){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}@media (min-width:640px){h1{font-size:2.25rem;line-height:2.5rem}}h2{scroll-margin:5rem;border-bottom-width:1px;padding-bottom:.5rem;font-size:1.875rem;line-height:2.25rem;font-weight:600;letter-spacing:-.025em;--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}h2:first-child{margin-top:0}:is(.dark h2){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}h3{scroll-margin:5rem;font-size:1.5rem;line-height:2rem;font-weight:600;letter-spacing:-.025em;--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark h3){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}h4,h5,h6{scroll-margin:5rem;font-size:1.25rem;line-height:1.75rem;font-weight:600;letter-spacing:-.025em;--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark h4),:is(.dark h5),:is(.dark h6){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}p{line-height:1.75rem;--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark p){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}p:not(:first-child){margin-top:1.5rem}code,kbd{position:relative;border-radius:.25rem;--tw-bg-opacity:1;background-color:rgb(226 232 240 / var(--tw-bg-opacity));padding-left:.3rem;padding-right:.3rem;padding-top:.2rem;padding-bottom:.2rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:.875rem;line-height:1.25rem;font-weight:600}:is(.dark code),:is(.dark kbd){--tw-bg-opacity:1;background-color:rgb(30 41 59 / var(--tw-bg-opacity))}blockquote{margin-top:1.5rem;border-left-width:2px;padding-left:1.5rem;font-style:italic}ul{margin-top:1.5rem;margin-bottom:1.5rem;margin-left:1.5rem;list-style-type:disc;--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark ul){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}ul>li{margin-top:.5rem}ol{margin-top:1.5rem;margin-bottom:1.5rem;margin-left:1.5rem;list-style-type:decimal;--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark ol){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}ol>li{margin-top:.5rem}dl{margin-top:1.5rem;margin-bottom:1.5rem;font-weight:700;--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark dl){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}dl>dd{margin-left:1.5rem;font-weight:400}dl>dt{margin-top:.75rem}li{--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark li){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}table{width:100%;caption-side:bottom;font-size:.875rem;line-height:1.25rem}thead tr{border-bottom-width:1px}tbody tr:last-child{border-width:0}tfoot{border-top-width:1px;--tw-border-opacity:1;border-color:rgb(148 163 184 / var(--tw-border-opacity));background-color:rgb(51 65 85 / .5);font-weight:500}:is(.dark tfoot){--tw-border-opacity:1;border-color:rgb(51 65 85 / var(--tw-border-opacity));background-color:rgb(226 232 240 / .5)}tfoot:last-child>tr{border-bottom-width:0}tr{border-bottom-width:1px;--tw-border-opacity:1;border-color:rgb(148 163 184 / var(--tw-border-opacity));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(0.4,0,0.2,1);transition-duration:150ms}tr:hover{background-color:rgb(226 232 240 / .5)}tr[data-state=selected]{--tw-bg-opacity:1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}:is(.dark tr){--tw-border-opacity:1;border-color:rgb(51 65 85 / var(--tw-border-opacity))}:is(.dark tr:hover){background-color:rgb(51 65 85 / .5)}:is(.dark tr[data-state=selected]){--tw-bg-opacity:1;background-color:rgb(226 232 240 / var(--tw-bg-opacity))}th{height:3rem;padding-left:1rem;padding-right:1rem;text-align:left;vertical-align:middle;font-weight:500;--tw-text-opacity:1;color:rgb(71 85 105 / var(--tw-text-opacity))}:is(.dark th){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}th:has([role=checkbox]){padding-right:0}td{padding:1rem;vertical-align:middle}td:has([role=checkbox]){padding-right:0}caption{margin-top:1rem;font-size:.875rem;line-height:1.25rem;--tw-text-opacity:1;color:rgb(71 85 105 / var(--tw-text-opacity))}:is(.dark caption){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}img{margin-left:auto;margin-right:auto;height:auto;width:auto;max-width:100%;border-radius:.375rem;-o-object-fit:cover;object-fit:cover;--tw-shadow:0 4px 6px -1px rgb(0 0 0 / 0.1),0 2px 4px -2px rgb(0 0 0 / 0.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}:is(.dark img){--tw-shadow-color:#334155;--tw-shadow:var(--tw-shadow-colored)}figcaption{margin-top:.5rem;font-size:.875rem;line-height:1.25rem;--tw-text-opacity:1;color:rgb(71 85 105 / var(--tw-text-opacity))}:is(.dark figcaption){--tw-text-opacity:1;color:rgb(148 163 184 / var(--tw-text-opacity))}hr{height:1px;width:100%;flex-shrink:0;--tw-bg-opacity:1;background-color:rgb(226 232 240 / var(--tw-bg-opacity))}:is(.dark hr){--tw-bg-opacity:1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}*,::after,::before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.absolute{position:absolute}.relative{position:relative}.inset-y-0{top:0;bottom:0}.right-0{right:0}.z-10{z-index:10}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.-mt-12{margin-top:-3rem}.ml-2{margin-left:.5rem}.mt-2{margin-top:.5rem}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-12{height:3rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-\[250px\]{height:250px}.w-10{width:2.5rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-52{width:13rem}.w-full{width:100%}.max-w-3xl{max-width:48rem}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap-reverse{flex-wrap:wrap-reverse}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-x-10{-moz-column-gap:2.5rem;column-gap:2.5rem}.gap-y-4{row-gap:1rem}.place-self-end{place-self:end}.whitespace-nowrap{white-space:nowrap}.rounded-full{border-radius:9999px}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184 / var(--tw-border-opacity))}.bg-slate-200{--tw-bg-opacity:1;background-color:rgb(226 232 240 / var(--tw-bg-opacity))}.bg-slate-800{--tw-bg-opacity:1;background-color:rgb(30 41 59 / var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.p-2{padding:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.px-8{padding-left:2rem;padding-right:2rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.pl-2{padding-left:.5rem}.pr-2{padding-right:.5rem}.pr-3{padding-right:.75rem}.pt-10{padding-top:2.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.leading-6{line-height:1.5rem}.tracking-tight{letter-spacing:-.025em}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28 / var(--tw-text-opacity))}.text-slate-200{--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}.text-slate-400{--tw-text-opacity:1;color:rgb(148 163 184 / var(--tw-text-opacity))}.text-slate-600{--tw-text-opacity:1;color:rgb(71 85 105 / var(--tw-text-opacity))}.text-slate-900{--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}.underline-offset-2{text-underline-offset:2px}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.shadow-md{--tw-shadow:0 4px 6px -1px rgb(0 0 0 / 0.1),0 2px 4px -2px rgb(0 0 0 / 0.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgb(0 0 0 / 0.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-slate-900\/10{--tw-ring-color:rgb(15 23 42 / 0.1)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(0.4,0,0.2,1);transition-duration:150ms}.duration-300{transition-duration:.3s}.first-of-type\:rounded-t-md:first-of-type{border-top-left-radius:.375rem;border-top-right-radius:.375rem}.last-of-type\:rounded-b-md:last-of-type{border-bottom-right-radius:.375rem;border-bottom-left-radius:.375rem}.hover\:bg-slate-200:hover{--tw-bg-opacity:1;background-color:rgb(226 232 240 / var(--tw-bg-opacity))}.hover\:bg-slate-200\/90:hover{background-color:rgb(226 232 240 / .9)}.hover\:bg-slate-800\/90:hover{background-color:rgb(30 41 59 / .9)}.hover\:text-blue-500:hover{--tw-text-opacity:1;color:rgb(59 130 246 / var(--tw-text-opacity))}.hover\:text-slate-400:hover{--tw-text-opacity:1;color:rgb(148 163 184 / var(--tw-text-opacity))}.hover\:text-slate-500:hover{--tw-text-opacity:1;color:rgb(100 116 139 / var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.hover\:ring-slate-300:hover{--tw-ring-opacity:1;--tw-ring-color:rgb(203 213 225 / var(--tw-ring-opacity))}.hover\:drop-shadow-\[0_0px_10px_rgba\(122\2c 167\2c 209\2c \.3\)\]:hover{--tw-drop-shadow:drop-shadow(0 0px 10px rgba(122,167,209,.3));filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}.peer:checked~.peer-checked\:bg-slate-200{--tw-bg-opacity:1;background-color:rgb(226 232 240 / var(--tw-bg-opacity))}:is(.dark .dark\:border-slate-700){--tw-border-opacity:1;border-color:rgb(51 65 85 / var(--tw-border-opacity))}:is(.dark .dark\:bg-slate-200){--tw-bg-opacity:1;background-color:rgb(226 232 240 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-slate-800){--tw-bg-opacity:1;background-color:rgb(30 41 59 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-slate-900){--tw-bg-opacity:1;background-color:rgb(15 23 42 / var(--tw-bg-opacity))}:is(.dark .dark\:text-red-400){--tw-text-opacity:1;color:rgb(248 113 113 / var(--tw-text-opacity))}:is(.dark .dark\:text-slate-200){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}:is(.dark .dark\:text-slate-400){--tw-text-opacity:1;color:rgb(148 163 184 / var(--tw-text-opacity))}:is(.dark .dark\:text-slate-900){--tw-text-opacity:1;color:rgb(15 23 42 / var(--tw-text-opacity))}:is(.dark .dark\:hover\:bg-slate-200\/90:hover){background-color:rgb(226 232 240 / .9)}:is(.dark .dark\:hover\:bg-slate-700:hover){--tw-bg-opacity:1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-slate-800\/90:hover){background-color:rgb(30 41 59 / .9)}:is(.dark .dark\:hover\:text-blue-500:hover){--tw-text-opacity:1;color:rgb(59 130 246 / var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-slate-200:hover){--tw-text-opacity:1;color:rgb(226 232 240 / var(--tw-text-opacity))}:is(.dark .hover\:dark\:text-slate-300):hover{--tw-text-opacity:1;color:rgb(203 213 225 / var(--tw-text-opacity))}:is(.dark .peer:checked ~ .dark\:peer-checked\:bg-slate-700){--tw-bg-opacity:1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}@media (min-width:640px){.sm\:text-4xl{font-size:2.25rem;line-height:2.5rem}}.\[\&\:not\(\:first-child\)\]\:mt-0:not(:first-child){margin-top:0} \ No newline at end of file diff --git a/handlers/api_outline.go b/handlers/api_content.go similarity index 92% rename from handlers/api_outline.go rename to handlers/api_content.go index acb4095..71608e5 100644 --- a/handlers/api_outline.go +++ b/handlers/api_content.go @@ -8,7 +8,7 @@ import ( "github.com/gofiber/fiber/v2" ) -func NewAPIOutlineHandler(path string, opts *ProxyOptions) fiber.Handler { +func NewAPIContentHandler(path string, opts *ProxyOptions) fiber.Handler { // TODO: implement ruleset logic /* var rs ruleset.RuleSet diff --git a/handlers/form.html b/handlers/form.html index edf915d..92bded4 100644 --- a/handlers/form.html +++ b/handlers/form.html @@ -5,9 +5,14 @@ ladder + - diff --git a/internal/cli/art.go b/internal/cli/art.go index f3eeb29..ccae8e7 100644 --- a/internal/cli/art.go +++ b/internal/cli/art.go @@ -1,6 +1,9 @@ package cli -import "fmt" +import ( + "fmt" + "strings" +) var art string = ` _____╬═╬____________________________________________ @@ -10,21 +13,30 @@ var art string = ` |___|╬═╬|___██▪ ▄█▀▀█ ▐█· ▐█▌▐█· ▐█▌▐▀▀▪▄▐▀▀▄ __|_| |_|__╬═╬___|▐█▌▐▌▐█ ▪▐▌██. ██ ██. ██ ▐█▄▄▌▐█•█▌|___| |___|╬═╬|___.▀▀▀ ▀ ▀ ▀▀▀▀▀• ▀▀▀▀▀• ▀▀▀ .▀ ▀__|_| - |_|__╬═╬___|___|___|__ VERSION %s __|___|___|___| + |_|__╬═╬___|___|___|_ VERSION %-7s__|___|___|___| |___|╬═╬|____|___|___|___|___|___|___|___|___|___|_| + ╬═╬ + ╬═╬ %s ` func StartupMessage(version string, port string, ruleset string) string { - buf := fmt.Sprintf(art, version) - buf += fmt.Sprintf("\n > listening on http://localhost:%s\n", port) + version = strings.Trim(version, " ") + version = strings.Trim(version, "\n") + link := createHyperlink("http://localhost:" + port) + buf := fmt.Sprintf(art, version, link) if ruleset == "" { - buf += " ! no ruleset specified.\n > for better performance, use a ruleset using --ruleset\n" + buf += "\n ! no ruleset specified.\n > for better performance, use a ruleset using --ruleset\n" } else { - buf += fmt.Sprintf(" > using ruleset: %s\n", ruleset) + buf += fmt.Sprintf("\n > using ruleset: %s\n", ruleset) } return colorizeNonASCII(buf) } +func createHyperlink(url string) string { + //return fmt.Sprintf("\033]8;;%s\a%s\033]8;;\a", url, url) + return fmt.Sprintf("\033[4m%s\033[0m", url) +} + func colorizeNonASCII(input string) string { result := "" for _, r := range input { diff --git a/proxychain/responsemodifers/api/outline_api.go b/proxychain/responsemodifers/api/outline_api.go index d96b05f..f17f42e 100644 --- a/proxychain/responsemodifers/api/outline_api.go +++ b/proxychain/responsemodifers/api/outline_api.go @@ -27,6 +27,15 @@ type TextContent struct { Data string `json:"data"` } +type ListContent struct { + Type string `json:"type"` + ListItems []ListItemContent `json:"listItems"` +} + +type ListItemContent struct { + Data string `json:"data"` +} + type JSONDocument struct { Success bool `json:"success"` Error ErrorDetails `json:"error"` @@ -35,6 +44,7 @@ type JSONDocument struct { Author string `json:"author"` URL string `json:"url"` Hostname string `json:"hostname"` + Image string `json:"image"` Description string `json:"description"` Sitename string `json:"sitename"` Date string `json:"date"` @@ -58,11 +68,13 @@ func ExtractResultToAPIResponse(extract *trafilatura.ExtractResult) *JSONDocumen jsonDoc.Metadata.URL = extract.Metadata.URL jsonDoc.Metadata.Hostname = extract.Metadata.Hostname jsonDoc.Metadata.Description = extract.Metadata.Description + jsonDoc.Metadata.Image = extract.Metadata.Image jsonDoc.Metadata.Sitename = extract.Metadata.Sitename jsonDoc.Metadata.Date = extract.Metadata.Date.Format("2006-01-02") jsonDoc.Metadata.Categories = extract.Metadata.Categories jsonDoc.Metadata.Tags = extract.Metadata.Tags jsonDoc.Metadata.License = extract.Metadata.License + jsonDoc.Metadata.Hostname = extract.Metadata.Hostname // Populate content if extract.ContentNode != nil { @@ -120,7 +132,34 @@ func parseContent(node *html.Node) []interface{} { } content = append(content, text) - // continue with other tags + case "h4": + text := TextContent{ + Type: "h4", + Data: dom.InnerText(child), + } + content = append(content, text) + + case "h5": + text := TextContent{ + Type: "h5", + Data: dom.InnerText(child), + } + content = append(content, text) + + case "ul", "ol": + list := ListContent{ + Type: child.Data, + ListItems: []ListItemContent{}, + } + for listItem := child.FirstChild; listItem != nil; listItem = listItem.NextSibling { + if listItem.Data == "li" { + listItemContent := ListItemContent{ + Data: dom.InnerText(listItem), + } + list.ListItems = append(list.ListItems, listItemContent) + } + } + content = append(content, list) default: text := TextContent{ diff --git a/proxychain/responsemodifers/generate_readable_outline.go b/proxychain/responsemodifers/generate_readable_outline.go index a73e963..05e29b1 100644 --- a/proxychain/responsemodifers/generate_readable_outline.go +++ b/proxychain/responsemodifers/generate_readable_outline.go @@ -69,12 +69,14 @@ func GenerateReadableOutline() proxychain.ResponseModification { "Success": true, "Image": extract.Metadata.Image, "Description": extract.Metadata.Description, + "Sitename": extract.Metadata.Sitename, "Hostname": extract.Metadata.Hostname, "Url": "/" + chain.Request.URL.String(), "Title": extract.Metadata.Title, // todo: modify CreateReadableDocument so we don't have

titles duplicated? "Date": extract.Metadata.Date.String(), - "Author": extract.Metadata.Author, - "Body": distilledHTML, + "Author": createWikipediaSearchLinks(extract.Metadata.Author), + //"Author": extract.Metadata.Author, + "Body": distilledHTML, } // ============================================================================ @@ -157,3 +159,34 @@ func rewriteHrefLinks(n *html.Node, baseURL string, apiPath string) { } recurse(n) } + +// createWikipediaSearchLinks takes in comma or semicolon separated terms, +// then turns them into links searching for the term. +func createWikipediaSearchLinks(searchTerms string) string { + semiColonSplit := strings.Split(searchTerms, ";") + + var links []string + for i, termGroup := range semiColonSplit { + commaSplit := strings.Split(termGroup, ",") + for _, term := range commaSplit { + trimmedTerm := strings.TrimSpace(term) + if trimmedTerm == "" { + continue + } + + encodedTerm := url.QueryEscape(trimmedTerm) + + wikiURL := fmt.Sprintf("https://en.wikipedia.org/w/index.php?search=%s", encodedTerm) + + link := fmt.Sprintf("%s", wikiURL, trimmedTerm) + links = append(links, link) + } + + // If it's not the last element in semiColonSplit, add a comma to the last link + if i < len(semiColonSplit)-1 { + links[len(links)-1] = links[len(links)-1] + "," + } + } + + return strings.Join(links, " ") +} diff --git a/proxychain/responsemodifers/generate_readable_outline.html b/proxychain/responsemodifers/generate_readable_outline.html index c849c9c..0f0d251 100644 --- a/proxychain/responsemodifers/generate_readable_outline.html +++ b/proxychain/responsemodifers/generate_readable_outline.html @@ -7,7 +7,11 @@ - ladder | {{ .Title }} + ladder | {{.Title}} + +
- ladder | {{.Hostname}} + + {{.Sitename}} + +
+
@@ -303,61 +314,46 @@
- {{ if not .Success}} -

+ {{if not .Success}} +

Error

-

+

There was a problem querying - {{ .Params }} + {{.Params}}

- - {{ .Type }}: {{ .Message }} -
Cause:
- {{ .Cause }} + + {{.Error}} {{else}}
-

- {{.Title}} +

+ {{.Title}}

- {{ if ne .Date "" }} + {{if ne .Date ""}} {{.date}}{{.Date}} - {{ end }} {{ if ne .Author "" }} + {{end}} + {{if ne .Author ""}} {{.Author}} - {{ end }} + {{end}}
-
-
{{.Description}}
+
{{.Description}}
+
{{.Description}}
-
{{ .Body }}
- {{ end }} - - +
{{.Body}}
+ {{end}}
diff --git a/styles/input.css b/styles/input.css index 9930f95..365e65d 100644 --- a/styles/input.css +++ b/styles/input.css @@ -7,7 +7,7 @@ @apply text-slate-600 dark:text-slate-400 hover:text-blue-500 dark:hover:text-blue-500 hover:underline underline-offset-2 transition-colors duration-300; } h1 { - @apply text-3xl sm:text-4xl font-extrabold tracking-tight text-slate-900 dark:text-slate-200; + @apply scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl text-slate-900 dark:text-slate-200; } h2 { @apply scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight first:mt-0 text-slate-900 dark:text-slate-200; @@ -24,8 +24,9 @@ @apply leading-7 [&:not(:first-child)]:mt-6 text-slate-900 dark:text-slate-200; } kbd, + pre, code { - @apply relative rounded bg-slate-200 dark:bg-slate-800 px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold; + @apply relative whitespace-break-spaces rounded bg-slate-200 dark:bg-slate-800 py-[0.2rem] font-mono text-sm font-semibold; } blockquote { @apply mt-6 border-l-2 pl-6 italic; diff --git a/tailwind.config.js b/tailwind.config.js index 99a01a1..1e40435 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,6 +1,10 @@ /** @type {import('tailwindcss').Config} */ module.exports = { - content: ["./handlers/**/*.html"], + content: [ + "./cmd/**/*.{html,js}", + "./handlers/**/*.{html,js}", + "./proxychain/**/*.{html,js}", + ], darkMode: "class", theme: { extend: {},