diff --git a/cmd/tailscale/cli/web.css b/cmd/tailscale/cli/web.css new file mode 100644 index 000000000..64672224d --- /dev/null +++ b/cmd/tailscale/cli/web.css @@ -0,0 +1,1337 @@ +*, +::before, +::after { + box-sizing: border-box; + border-width: 0; + border-style: solid; + border-color: #e5e7eb; +} + +html { + 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"; + line-height: 1.5; + -webkit-text-size-adjust: 100%; +} + +::selection { + background-color: rgba(97, 122, 255, 0.2); +} + +body { + margin: 0; + font-family: inherit; + line-height: inherit; +} + +hr { + height: 0; + color: inherit; + border-top-width: 1px; +} + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo, + monospace; + font-size: 1em; +} + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + vertical-align: middle; +} + +img, +video { + max-width: 100%; + height: auto; +} + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + font-size: 100%; + line-height: 1.15; + margin: 0; +} + +button, +select { + text-transform: none; +} + +button, +[type="button"], +[type="submit"] { + -webkit-appearance: button; +} + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +button, +input, +optgroup, +select, +textarea { + padding: 0; + line-height: inherit; + color: inherit; +} + +button { + cursor: pointer; + background-color: transparent; + background-image: none; +} + +button:focus { + outline: 1px dotted; + outline: 5px auto -webkit-focus-ring-color; +} + +fieldset { + margin: 0; + padding: 0; +} + +ol, +ul { + list-style: none; + margin: 0; + padding: 0; +} + +textarea { + resize: vertical; +} + +input::-moz-placeholder, +textarea::-moz-placeholder { + opacity: 1; + color: #9ca3af; +} + +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + opacity: 1; + color: #9ca3af; +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + color: #9ca3af; +} + +table { + border-collapse: collapse; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +a { + color: inherit; + text-decoration: inherit; +} + +.container { + width: 100%; +} + +@media (min-width: 640px) { + .container { + max-width: 640px; + } +} + +@media (min-width: 768px) { + .container { + max-width: 768px; + } +} + +@media (min-width: 1024px) { + .container { + max-width: 1024px; + } +} + +@media (min-width: 1280px) { + .container { + max-width: 1280px; + } +} + +@media (min-width: 1536px) { + .container { + max-width: 1536px; + } +} + +.space-x-2 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(0.5rem * var(--tw-space-x-reverse)); + margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); +} + +.bg-white { + --tw-bg-opacity: 1; + background-color: rgba(255, 255, 255, var(--tw-bg-opacity)); +} + +.bg-gray-0 { + --tw-bg-opacity: 1; + background-color: rgba(250, 249, 248, var(--tw-bg-opacity)); +} + +.bg-gray-50 { + --tw-bg-opacity: 1; + background-color: rgba(249, 247, 246, var(--tw-bg-opacity)); +} + +.border-gray-200 { + --tw-border-opacity: 1; + border-color: rgba(238, 235, 234, var(--tw-border-opacity)); +} + +.border-gray-400 { + --tw-border-opacity: 1; + border-color: rgba(175, 172, 171, var(--tw-border-opacity)); +} + +.rounded-md { + border-radius: 0.375rem; +} + +.rounded-lg { + border-radius: 0.5rem; +} + +.rounded-full { + border-radius: 9999px; +} + +.border-dashed { + border-style: dashed; +} + +.border { + border-width: 1px; +} + +.flex { + display: flex; +} + +.table { + display: table; +} + +.items-center { + align-items: center; +} + +.justify-start { + justify-content: flex-start; +} + +.justify-end { + justify-content: flex-end; +} + +.justify-center { + justify-content: center; +} + +.justify-between { + justify-content: space-between; +} + +.justify-around { + justify-content: space-around; +} + +.justify-evenly { + justify-content: space-evenly; +} + +.flex-shrink-0 { + flex-shrink: 0; +} + +.font-medium { + font-weight: 500; +} + +.font-semibold { + font-weight: 600; +} + +.h-8 { + height: 2rem; +} + +.mx-auto { + margin-left: auto; + margin-right: auto; +} + +.mt-0 { + margin-top: 0px; +} + +.mr-0 { + margin-right: 0px; +} + +.mb-0 { + margin-bottom: 0px; +} + +.ml-0 { + margin-left: 0px; +} + +.mt-1 { + margin-top: 0.25rem; +} + +.mr-1 { + margin-right: 0.25rem; +} + +.mb-1 { + margin-bottom: 0.25rem; +} + +.ml-1 { + margin-left: 0.25rem; +} + +.mt-2 { + margin-top: 0.5rem; +} + +.mr-2 { + margin-right: 0.5rem; +} + +.mb-2 { + margin-bottom: 0.5rem; +} + +.ml-2 { + margin-left: 0.5rem; +} + +.mt-3 { + margin-top: 0.75rem; +} + +.mr-3 { + margin-right: 0.75rem; +} + +.mb-3 { + margin-bottom: 0.75rem; +} + +.ml-3 { + margin-left: 0.75rem; +} + +.mt-4 { + margin-top: 1rem; +} + +.mr-4 { + margin-right: 1rem; +} + +.mb-4 { + margin-bottom: 1rem; +} + +.ml-4 { + margin-left: 1rem; +} + +.mt-5 { + margin-top: 1.25rem; +} + +.mr-5 { + margin-right: 1.25rem; +} + +.mb-5 { + margin-bottom: 1.25rem; +} + +.ml-5 { + margin-left: 1.25rem; +} + +.mt-6 { + margin-top: 1.5rem; +} + +.mr-6 { + margin-right: 1.5rem; +} + +.mb-6 { + margin-bottom: 1.5rem; +} + +.ml-6 { + margin-left: 1.5rem; +} + +.mt-7 { + margin-top: 1.75rem; +} + +.mr-7 { + margin-right: 1.75rem; +} + +.mb-7 { + margin-bottom: 1.75rem; +} + +.ml-7 { + margin-left: 1.75rem; +} + +.mt-8 { + margin-top: 2rem; +} + +.mr-8 { + margin-right: 2rem; +} + +.mb-8 { + margin-bottom: 2rem; +} + +.ml-8 { + margin-left: 2rem; +} + +.mt-9 { + margin-top: 2.25rem; +} + +.mr-9 { + margin-right: 2.25rem; +} + +.mb-9 { + margin-bottom: 2.25rem; +} + +.ml-9 { + margin-left: 2.25rem; +} + +.mt-10 { + margin-top: 2.5rem; +} + +.mr-10 { + margin-right: 2.5rem; +} + +.mb-10 { + margin-bottom: 2.5rem; +} + +.ml-10 { + margin-left: 2.5rem; +} + +.mt-11 { + margin-top: 2.75rem; +} + +.mr-11 { + margin-right: 2.75rem; +} + +.mb-11 { + margin-bottom: 2.75rem; +} + +.ml-11 { + margin-left: 2.75rem; +} + +.mt-12 { + margin-top: 3rem; +} + +.mr-12 { + margin-right: 3rem; +} + +.mb-12 { + margin-bottom: 3rem; +} + +.ml-12 { + margin-left: 3rem; +} + +.mt-14 { + margin-top: 3.5rem; +} + +.mr-14 { + margin-right: 3.5rem; +} + +.mb-14 { + margin-bottom: 3.5rem; +} + +.ml-14 { + margin-left: 3.5rem; +} + +.mt-16 { + margin-top: 4rem; +} + +.mr-16 { + margin-right: 4rem; +} + +.mb-16 { + margin-bottom: 4rem; +} + +.ml-16 { + margin-left: 4rem; +} + +.mt-20 { + margin-top: 5rem; +} + +.mr-20 { + margin-right: 5rem; +} + +.mb-20 { + margin-bottom: 5rem; +} + +.ml-20 { + margin-left: 5rem; +} + +.mt-24 { + margin-top: 6rem; +} + +.mr-24 { + margin-right: 6rem; +} + +.mb-24 { + margin-bottom: 6rem; +} + +.ml-24 { + margin-left: 6rem; +} + +.mt-28 { + margin-top: 7rem; +} + +.mr-28 { + margin-right: 7rem; +} + +.mb-28 { + margin-bottom: 7rem; +} + +.ml-28 { + margin-left: 7rem; +} + +.mt-32 { + margin-top: 8rem; +} + +.mr-32 { + margin-right: 8rem; +} + +.mb-32 { + margin-bottom: 8rem; +} + +.ml-32 { + margin-left: 8rem; +} + +.mt-36 { + margin-top: 9rem; +} + +.mr-36 { + margin-right: 9rem; +} + +.mb-36 { + margin-bottom: 9rem; +} + +.ml-36 { + margin-left: 9rem; +} + +.mt-40 { + margin-top: 10rem; +} + +.mr-40 { + margin-right: 10rem; +} + +.mb-40 { + margin-bottom: 10rem; +} + +.ml-40 { + margin-left: 10rem; +} + +.mt-44 { + margin-top: 11rem; +} + +.mr-44 { + margin-right: 11rem; +} + +.mb-44 { + margin-bottom: 11rem; +} + +.ml-44 { + margin-left: 11rem; +} + +.mt-48 { + margin-top: 12rem; +} + +.mr-48 { + margin-right: 12rem; +} + +.mb-48 { + margin-bottom: 12rem; +} + +.ml-48 { + margin-left: 12rem; +} + +.mt-52 { + margin-top: 13rem; +} + +.mr-52 { + margin-right: 13rem; +} + +.mb-52 { + margin-bottom: 13rem; +} + +.ml-52 { + margin-left: 13rem; +} + +.mt-56 { + margin-top: 14rem; +} + +.mr-56 { + margin-right: 14rem; +} + +.mb-56 { + margin-bottom: 14rem; +} + +.ml-56 { + margin-left: 14rem; +} + +.mt-60 { + margin-top: 15rem; +} + +.mr-60 { + margin-right: 15rem; +} + +.mb-60 { + margin-bottom: 15rem; +} + +.ml-60 { + margin-left: 15rem; +} + +.mt-64 { + margin-top: 16rem; +} + +.mr-64 { + margin-right: 16rem; +} + +.mb-64 { + margin-bottom: 16rem; +} + +.ml-64 { + margin-left: 16rem; +} + +.mt-72 { + margin-top: 18rem; +} + +.mr-72 { + margin-right: 18rem; +} + +.mb-72 { + margin-bottom: 18rem; +} + +.ml-72 { + margin-left: 18rem; +} + +.mt-80 { + margin-top: 20rem; +} + +.mr-80 { + margin-right: 20rem; +} + +.mb-80 { + margin-bottom: 20rem; +} + +.ml-80 { + margin-left: 20rem; +} + +.mt-96 { + margin-top: 24rem; +} + +.mr-96 { + margin-right: 24rem; +} + +.mb-96 { + margin-bottom: 24rem; +} + +.ml-96 { + margin-left: 24rem; +} + +.max-w-lg { + max-width: 32rem; +} + +.max-w-xl { + max-width: 36rem; +} + +.overflow-hidden { + overflow: hidden; +} + +.p-2 { + padding: 0.5rem; +} + +.py-0 { + padding-top: 0px; + padding-bottom: 0px; +} + +.px-0 { + padding-left: 0px; + padding-right: 0px; +} + +.py-1 { + padding-top: 0.25rem; + padding-bottom: 0.25rem; +} + +.px-1 { + padding-left: 0.25rem; + padding-right: 0.25rem; +} + +.py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.px-2 { + padding-left: 0.5rem; + padding-right: 0.5rem; +} + +.py-3 { + padding-top: 0.75rem; + padding-bottom: 0.75rem; +} + +.px-3 { + padding-left: 0.75rem; + padding-right: 0.75rem; +} + +.py-4 { + padding-top: 1rem; + padding-bottom: 1rem; +} + +.px-4 { + padding-left: 1rem; + padding-right: 1rem; +} + +.py-5 { + padding-top: 1.25rem; + padding-bottom: 1.25rem; +} + +.px-5 { + padding-left: 1.25rem; + padding-right: 1.25rem; +} + +.py-6 { + padding-top: 1.5rem; + padding-bottom: 1.5rem; +} + +.px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; +} + +.py-7 { + padding-top: 1.75rem; + padding-bottom: 1.75rem; +} + +.px-7 { + padding-left: 1.75rem; + padding-right: 1.75rem; +} + +.py-8 { + padding-top: 2rem; + padding-bottom: 2rem; +} + +.px-8 { + padding-left: 2rem; + padding-right: 2rem; +} + +.py-9 { + padding-top: 2.25rem; + padding-bottom: 2.25rem; +} + +.px-9 { + padding-left: 2.25rem; + padding-right: 2.25rem; +} + +.py-10 { + padding-top: 2.5rem; + padding-bottom: 2.5rem; +} + +.px-10 { + padding-left: 2.5rem; + padding-right: 2.5rem; +} + +.py-11 { + padding-top: 2.75rem; + padding-bottom: 2.75rem; +} + +.px-11 { + padding-left: 2.75rem; + padding-right: 2.75rem; +} + +.py-12 { + padding-top: 3rem; + padding-bottom: 3rem; +} + +.px-12 { + padding-left: 3rem; + padding-right: 3rem; +} + +.py-14 { + padding-top: 3.5rem; + padding-bottom: 3.5rem; +} + +.px-14 { + padding-left: 3.5rem; + padding-right: 3.5rem; +} + +.py-16 { + padding-top: 4rem; + padding-bottom: 4rem; +} + +.px-16 { + padding-left: 4rem; + padding-right: 4rem; +} + +.py-20 { + padding-top: 5rem; + padding-bottom: 5rem; +} + +.px-20 { + padding-left: 5rem; + padding-right: 5rem; +} + +.py-24 { + padding-top: 6rem; + padding-bottom: 6rem; +} + +.px-24 { + padding-left: 6rem; + padding-right: 6rem; +} + +.py-28 { + padding-top: 7rem; + padding-bottom: 7rem; +} + +.px-28 { + padding-left: 7rem; + padding-right: 7rem; +} + +.py-32 { + padding-top: 8rem; + padding-bottom: 8rem; +} + +.px-32 { + padding-left: 8rem; + padding-right: 8rem; +} + +.py-36 { + padding-top: 9rem; + padding-bottom: 9rem; +} + +.px-36 { + padding-left: 9rem; + padding-right: 9rem; +} + +.pr-3 { + padding-right: 0.75rem; +} + +.pl-3 { + padding-left: 0.75rem; +} + +.pointer-events-none { + pointer-events: none; +} + +.relative { + position: relative; +} + +* { + --tw-shadow: 0 0 #0000; +} + +.shadow-2xl { + --tw-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), + var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +* { + --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgba(75, 112, 204, 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; +} + +.text-xs { + font-size: 0.75rem; + line-height: 1rem; +} + +.text-sm { + font-size: 0.875rem; + line-height: 1.25rem; +} + +.text-base { + font-size: 1rem; + line-height: 1.5rem; +} + +.text-lg { + font-size: 1.125rem; + line-height: 1.75rem; +} + +.text-xl { + font-size: 1.25rem; + line-height: 1.75rem; +} + +.text-2xl { + font-size: 1.5rem; + line-height: 2rem; +} + +.text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; +} + +.text-4xl { + font-size: 2.25rem; + line-height: 2.5rem; +} + +.text-left { + text-align: left; +} + +.text-center { + text-align: center; +} + +.text-right { + text-align: right; +} + +.text-justify { + text-align: justify; +} + +.text-gray-500 { + --tw-text-opacity: 1; + color: rgba(112, 110, 109, var(--tw-text-opacity)); +} + +.text-gray-600 { + --tw-text-opacity: 1; + color: rgba(68, 67, 66, var(--tw-text-opacity)); +} + +.text-gray-700 { + --tw-text-opacity: 1; + color: rgba(46, 45, 45, var(--tw-text-opacity)); +} + +.text-gray-800 { + --tw-text-opacity: 1; + color: rgba(35, 34, 34, var(--tw-text-opacity)); +} + +.leading-3 { + line-height: 0.75rem; +} + +.leading-4 { + line-height: 1rem; +} + +.leading-5 { + line-height: 1.25rem; +} + +.leading-6 { + line-height: 1.5rem; +} + +.leading-7 { + line-height: 1.75rem; +} + +.leading-8 { + line-height: 2rem; +} + +.leading-9 { + line-height: 2.25rem; +} + +.leading-10 { + line-height: 2.5rem; +} + +.leading-none { + line-height: 1; +} + +.leading-tight { + line-height: 1.25; +} + +.leading-snug { + line-height: 1.375; +} + +.leading-normal { + line-height: 1.5; +} + +.leading-relaxed { + line-height: 1.625; +} + +.leading-loose { + line-height: 2; +} + +.truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.w-8 { + width: 2rem; +} + +.w-1\/2 { + width: 50%; +} + +.w-2\/3 { + width: 66.666667%; +} + +.w-full { + width: 100%; +} + +.hover\:text-gray-0:hover { + --tw-text-opacity: 1; + color: rgba(250, 249, 248, var(--tw-text-opacity)); +} + +.hover\:text-gray-50:hover { + --tw-text-opacity: 1; + color: rgba(249, 247, 246, var(--tw-text-opacity)); +} + +.hover\:text-gray-100:hover { + --tw-text-opacity: 1; + color: rgba(247, 245, 244, var(--tw-text-opacity)); +} + +.hover\:text-gray-200:hover { + --tw-text-opacity: 1; + color: rgba(238, 235, 234, var(--tw-text-opacity)); +} + +.hover\:text-gray-300:hover { + --tw-text-opacity: 1; + color: rgba(218, 214, 213, var(--tw-text-opacity)); +} + +.hover\:text-gray-400:hover { + --tw-text-opacity: 1; + color: rgba(175, 172, 171, var(--tw-text-opacity)); +} + +.hover\:text-gray-500:hover { + --tw-text-opacity: 1; + color: rgba(112, 110, 109, var(--tw-text-opacity)); +} + +.hover\:text-gray-600:hover { + --tw-text-opacity: 1; + color: rgba(68, 67, 66, var(--tw-text-opacity)); +} + +.hover\:text-gray-700:hover { + --tw-text-opacity: 1; + color: rgba(46, 45, 45, var(--tw-text-opacity)); +} + +.hover\:text-gray-800:hover { + --tw-text-opacity: 1; + color: rgba(35, 34, 34, var(--tw-text-opacity)); +} + +.hover\:text-gray-900:hover { + --tw-text-opacity: 1; + color: rgba(31, 30, 30, var(--tw-text-opacity)); +} + +/** + * Non-Tailwind styles begin here. + */ + +html { + letter-spacing: -0.015em; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.link { + --text-opacity: 1; + color: #4b70cc; + color: rgba(75, 112, 204, var(--text-opacity)); +} + +.link:hover, +.link:active { + --text-opacity: 1; + color: #19224a; + color: rgba(25, 34, 74, var(--text-opacity)); +} + +.button { + font-weight: 500; + padding-top: 0.45rem; + padding-bottom: 0.45rem; + padding-left: 1rem; + padding-right: 1rem; + border-radius: 0.375rem; + border-width: 1px; + border-color: transparent; + transition-property: background-color, border-color, color, box-shadow; + transition-duration: 120ms; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); + min-width: 80px; +} + +.button:focus { + outline: 0; + box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5); +} + +.button:disabled { + cursor: not-allowed; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.button-blue { + --bg-opacity: 1; + background-color: #4b70cc; + background-color: rgba(75, 112, 204, var(--bg-opacity)); + --border-opacity: 1; + border-color: #4b70cc; + border-color: rgba(75, 112, 204, var(--border-opacity)); + --text-opacity: 1; + color: #fff; + color: rgba(255, 255, 255, var(--text-opacity)); +} + +.button-blue:enabled:hover { + --bg-opacity: 1; + background-color: #3f5db3; + background-color: rgba(63, 93, 179, var(--bg-opacity)); + --border-opacity: 1; + border-color: #3f5db3; + border-color: rgba(63, 93, 179, var(--border-opacity)); +} + +.button-blue:disabled { + --text-opacity: 1; + color: #cedefd; + color: rgba(206, 222, 253, var(--text-opacity)); + --bg-opacity: 1; + background-color: #6c94ec; + background-color: rgba(108, 148, 236, var(--bg-opacity)); + --border-opacity: 1; + border-color: #6c94ec; + border-color: rgba(108, 148, 236, var(--border-opacity)); +} diff --git a/cmd/tailscale/cli/web.go b/cmd/tailscale/cli/web.go index 94e4ca343..96aab1553 100644 --- a/cmd/tailscale/cli/web.go +++ b/cmd/tailscale/cli/web.go @@ -30,7 +30,15 @@ import ( //go:embed web.html var webHTML string -var tmpl = template.Must(template.New("html").Parse(webHTML)) +//go:embed web.css +var webCSS string + +var tmpl *template.Template + +func init() { + tmpl = template.Must(template.New("web.html").Parse(webHTML)) + template.Must(tmpl.New("web.css").Parse(webCSS)) +} type tmplData struct { Profile tailcfg.UserProfile diff --git a/cmd/tailscale/cli/web.html b/cmd/tailscale/cli/web.html index 59c254643..39375758d 100644 --- a/cmd/tailscale/cli/web.html +++ b/cmd/tailscale/cli/web.html @@ -7,1345 +7,7 @@