mirror of https://github.com/tailscale/tailscale/
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
465 lines
11 KiB
CSS
465 lines
11 KiB
CSS
@tailwind base;
|
|
@tailwind components;
|
|
@tailwind utilities;
|
|
|
|
@layer base {
|
|
@font-face {
|
|
font-family: "Inter";
|
|
font-weight: 100 900;
|
|
font-style: normal;
|
|
font-display: swap;
|
|
src: url("./assets/fonts/Inter.var.latin.woff2") format("woff2-variations");
|
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC,
|
|
U+02BB-02BC, U+2000-206F, U+2122, U+2190-2199, U+2212, U+2215, U+FEFF,
|
|
U+FFFD, U+E06B-E080, U+02E2, U+02E2, U+02B0, U+1D34, U+1D57, U+1D40,
|
|
U+207F, U+1D3A, U+1D48, U+1D30, U+02B3, U+1D3F;
|
|
}
|
|
|
|
html {
|
|
/**
|
|
* These lines force the page to occupy the full width of the browser,
|
|
* ignoring the scrollbar, and prevent horizontal scrolling. This eliminates
|
|
* shifting when moving between pages with a scrollbar and those without, by
|
|
* ignoring the width of the scrollbar.
|
|
*
|
|
* It also disables horizontal scrolling of the body wholesale, so, as always
|
|
* avoid content flowing off the page.
|
|
*/
|
|
width: 100vw;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
:root {
|
|
--color-white: 255 255 255;
|
|
|
|
--color-gray-0: 250 249 248;
|
|
--color-gray-50: 249 247 246;
|
|
--color-gray-100: 247 245 244;
|
|
--color-gray-200: 238 235 234;
|
|
--color-gray-300: 218 214 213;
|
|
--color-gray-400: 175 172 171;
|
|
--color-gray-500: 112 110 109;
|
|
--color-gray-600: 68 67 66;
|
|
--color-gray-700: 46 45 45;
|
|
--color-gray-800: 35 34 34;
|
|
--color-gray-900: 31 30 30;
|
|
|
|
--color-red-0: 255 246 244;
|
|
--color-red-50: 255 211 207;
|
|
--color-red-100: 255 177 171;
|
|
--color-red-200: 246 143 135;
|
|
--color-red-300: 228 108 99;
|
|
--color-red-400: 208 72 65;
|
|
--color-red-500: 178 45 48;
|
|
--color-red-600: 148 8 33;
|
|
--color-red-700: 118 0 18;
|
|
--color-red-800: 90 0 0;
|
|
--color-red-900: 66 0 0;
|
|
|
|
--color-yellow-0: 252 249 233;
|
|
--color-yellow-50: 248 229 185;
|
|
--color-yellow-100: 239 192 120;
|
|
--color-yellow-200: 229 153 62;
|
|
--color-yellow-300: 217 121 23;
|
|
--color-yellow-400: 187 85 4;
|
|
--color-yellow-500: 152 55 5;
|
|
--color-yellow-600: 118 43 11;
|
|
--color-yellow-700: 87 31 13;
|
|
--color-yellow-800: 58 22 7;
|
|
--color-yellow-900: 58 22 7;
|
|
|
|
--color-orange-0: 255 250 238;
|
|
--color-orange-50: 254 227 192;
|
|
--color-orange-100: 248 184 134;
|
|
--color-orange-200: 245 146 94;
|
|
--color-orange-300: 229 111 74;
|
|
--color-orange-400: 196 76 52;
|
|
--color-orange-500: 158 47 40;
|
|
--color-orange-600: 126 30 35;
|
|
--color-orange-700: 93 22 27;
|
|
--color-orange-800: 66 14 17;
|
|
--color-orange-900: 66 14 17;
|
|
|
|
--color-green-0: 239 255 237;
|
|
--color-green-50: 203 244 201;
|
|
--color-green-100: 133 217 150;
|
|
--color-green-200: 51 194 127;
|
|
--color-green-300: 30 166 114;
|
|
--color-green-400: 9 130 93;
|
|
--color-green-500: 14 98 69;
|
|
--color-green-600: 13 75 59;
|
|
--color-green-700: 11 55 51;
|
|
--color-green-800: 8 36 41;
|
|
--color-green-900: 8 36 41;
|
|
|
|
--color-blue-0: 240 245 255;
|
|
--color-blue-50: 206 222 253;
|
|
--color-blue-100: 173 199 252;
|
|
--color-blue-200: 133 170 245;
|
|
--color-blue-300: 108 148 236;
|
|
--color-blue-400: 90 130 222;
|
|
--color-blue-500: 75 112 204;
|
|
--color-blue-600: 63 93 179;
|
|
--color-blue-700: 50 73 148;
|
|
--color-blue-800: 37 53 112;
|
|
--color-blue-900: 25 34 74;
|
|
|
|
--color-text-base: rgb(var(--color-gray-800) / 1);
|
|
--color-text-muted: rgb(var(--color-gray-500) / 1);
|
|
--color-text-disabled: rgb(var(--color-gray-400) / 1);
|
|
--color-text-primary: rgb(var(--color-blue-600) / 1);
|
|
--color-text-warning: rgb(var(--color-orange-600) / 1);
|
|
--color-text-danger: rgb(var(--color-red-600) / 1);
|
|
|
|
--color-bg-app: rgb(var(--color-gray-100) / 1);
|
|
--color-bg-menu-item-hover: rgb(var(--color-gray-100) / 1);
|
|
|
|
--color-border-base: rgb(var(--color-gray-200) / 1);
|
|
}
|
|
|
|
html,
|
|
body,
|
|
#app-root {
|
|
min-height: 100vh;
|
|
}
|
|
|
|
body {
|
|
@apply text-text-base font-sans w-full antialiased;
|
|
font-size: 16px;
|
|
line-height: 1.4;
|
|
letter-spacing: -0.015em; /* Inter is a little loose by default */
|
|
text-rendering: optimizeLegibility;
|
|
-webkit-text-size-adjust: 100%;
|
|
-webkit-tap-highlight-color: transparent;
|
|
}
|
|
|
|
::selection {
|
|
background-color: rgba(97, 122, 255, 0.2);
|
|
}
|
|
|
|
strong {
|
|
@apply font-semibold;
|
|
}
|
|
|
|
button {
|
|
text-align: inherit; /* don't center buttons by default */
|
|
letter-spacing: inherit; /* inherit existing letter spacing, rather than using browser defaults */
|
|
vertical-align: top; /* fix alignment of display: inline-block buttons */
|
|
}
|
|
|
|
a:focus,
|
|
button:focus {
|
|
outline: none;
|
|
}
|
|
a:focus-visible,
|
|
button:focus-visible {
|
|
outline: auto;
|
|
}
|
|
|
|
h1 {
|
|
@apply text-gray-800 text-[22px] font-medium leading-[30.80px];
|
|
}
|
|
|
|
h2 {
|
|
@apply text-gray-500 text-sm font-medium uppercase leading-tight tracking-wide;
|
|
}
|
|
}
|
|
|
|
@layer components {
|
|
.details-card h1 {
|
|
@apply text-gray-800 text-lg font-medium leading-snug;
|
|
}
|
|
.details-card h2 {
|
|
@apply text-gray-500 text-xs font-semibold uppercase tracking-wide;
|
|
}
|
|
.details-card table {
|
|
@apply w-full;
|
|
}
|
|
.details-card tbody {
|
|
@apply flex flex-col gap-2;
|
|
}
|
|
.details-card tr {
|
|
@apply grid grid-flow-col grid-cols-3 gap-2;
|
|
}
|
|
.details-card td:first-child {
|
|
@apply text-gray-500 text-sm leading-tight truncate;
|
|
}
|
|
.details-card td:last-child {
|
|
@apply col-span-2 text-gray-800 text-sm leading-tight;
|
|
}
|
|
|
|
.description {
|
|
@apply text-gray-500 leading-snug;
|
|
}
|
|
|
|
/**
|
|
* .toggle applies "Toggle" UI styles to input[type="checkbox"] form elements.
|
|
* You can use the -large and -small modifiers for size variants.
|
|
*/
|
|
.toggle {
|
|
@apply appearance-none relative w-10 h-5 rounded-full bg-gray-300 cursor-pointer;
|
|
transition: background-color 200ms ease-in-out;
|
|
}
|
|
|
|
.toggle:disabled {
|
|
@apply bg-gray-200;
|
|
@apply cursor-not-allowed;
|
|
}
|
|
|
|
.toggle:checked {
|
|
@apply bg-blue-500;
|
|
}
|
|
|
|
.toggle:checked:disabled {
|
|
@apply bg-blue-300;
|
|
}
|
|
|
|
.toggle:focus {
|
|
@apply outline-none ring;
|
|
}
|
|
|
|
.toggle::after {
|
|
@apply absolute bg-white rounded-full will-change-[width];
|
|
@apply w-3.5 h-3.5 m-[0.1875rem] translate-x-0;
|
|
content: " ";
|
|
transition: width 200ms ease, transform 200ms ease;
|
|
}
|
|
|
|
.toggle:checked::after {
|
|
@apply translate-x-5;
|
|
}
|
|
|
|
.toggle:checked:disabled::after {
|
|
@apply bg-blue-50;
|
|
}
|
|
|
|
.toggle:enabled:active::after {
|
|
@apply w-[1.125rem];
|
|
}
|
|
|
|
.toggle:checked:enabled:active::after {
|
|
@apply w-[1.125rem] translate-x-3.5;
|
|
}
|
|
|
|
.toggle-large {
|
|
@apply w-12 h-6;
|
|
}
|
|
|
|
.toggle-large::after {
|
|
@apply m-1 w-4 h-4;
|
|
}
|
|
|
|
.toggle-large:checked::after {
|
|
@apply translate-x-6;
|
|
}
|
|
|
|
.toggle-large:enabled:active::after {
|
|
@apply w-6;
|
|
}
|
|
|
|
.toggle-large:checked:enabled:active::after {
|
|
@apply w-6 translate-x-4;
|
|
}
|
|
|
|
.toggle-small {
|
|
@apply w-6 h-3;
|
|
}
|
|
|
|
.toggle-small:focus {
|
|
/**
|
|
* We disable ring for .toggle-small because it is a
|
|
* small, inline element.
|
|
*/
|
|
@apply outline-none shadow-none;
|
|
}
|
|
|
|
.toggle-small::after {
|
|
@apply w-2 h-2 m-0.5;
|
|
}
|
|
|
|
.toggle-small:checked::after {
|
|
@apply translate-x-3;
|
|
}
|
|
|
|
.toggle-small:enabled:active::after {
|
|
@apply w-[0.675rem];
|
|
}
|
|
|
|
.toggle-small:checked:enabled:active::after {
|
|
@apply w-[0.675rem] translate-x-[0.55rem];
|
|
}
|
|
|
|
/**
|
|
* .button encapsulates all the base button styles we use across the app.
|
|
*/
|
|
|
|
.button {
|
|
@apply relative inline-flex flex-nowrap items-center justify-center font-medium py-2 px-4 rounded-md border border-transparent text-center whitespace-nowrap;
|
|
transition-property: background-color, border-color, color, box-shadow;
|
|
transition-duration: 120ms;
|
|
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
|
|
}
|
|
.button:focus-visible {
|
|
@apply outline-none ring;
|
|
}
|
|
.button:disabled {
|
|
@apply pointer-events-none select-none;
|
|
}
|
|
|
|
.button-group {
|
|
@apply whitespace-nowrap;
|
|
}
|
|
|
|
.button-group .button {
|
|
@apply min-w-[60px];
|
|
}
|
|
|
|
.button-group .button:not(:first-child) {
|
|
@apply rounded-l-none;
|
|
}
|
|
|
|
.button-group .button:not(:last-child) {
|
|
@apply rounded-r-none border-r-0;
|
|
}
|
|
|
|
/**
|
|
* .input defines default text input field styling. These styles should
|
|
* correspond to .button, sharing a similar height and rounding, since .input
|
|
* and .button are commonly used together.
|
|
*/
|
|
|
|
.input,
|
|
.input-wrapper {
|
|
@apply appearance-none leading-tight rounded-md bg-white border border-gray-300 hover:border-gray-400 transition-colors w-full h-input;
|
|
}
|
|
|
|
.input {
|
|
@apply px-3;
|
|
}
|
|
|
|
.input::placeholder,
|
|
.input-wrapper::placeholder {
|
|
@apply text-gray-400;
|
|
}
|
|
|
|
.input:disabled,
|
|
.input-wrapper:disabled {
|
|
@apply border-gray-300;
|
|
@apply bg-gray-0;
|
|
@apply cursor-not-allowed;
|
|
}
|
|
|
|
.input:focus,
|
|
.input-wrapper:focus-within {
|
|
@apply outline-none ring border-gray-400;
|
|
}
|
|
|
|
.input-error {
|
|
@apply border-red-200;
|
|
}
|
|
|
|
/**
|
|
* .loading-dots creates a set of three dots that pulse for indicating loading
|
|
* states where a more horizontal appearance is helpful.
|
|
*/
|
|
|
|
.loading-dots {
|
|
@apply inline-flex items-center;
|
|
}
|
|
|
|
.loading-dots span {
|
|
@apply inline-block w-[0.35rem] h-[0.35rem] rounded-full bg-current mx-[0.15em];
|
|
animation-name: loading-dots-blink;
|
|
animation-duration: 1.4s;
|
|
animation-iteration-count: infinite;
|
|
animation-fill-mode: both;
|
|
}
|
|
|
|
.loading-dots span:nth-child(2) {
|
|
animation-delay: 200ms;
|
|
}
|
|
|
|
.loading-dots span:nth-child(3) {
|
|
animation-delay: 400ms;
|
|
}
|
|
|
|
@keyframes loading-dots-blink {
|
|
0% {
|
|
opacity: 0.2;
|
|
}
|
|
20% {
|
|
opacity: 1;
|
|
}
|
|
100% {
|
|
opacity: 0.2;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* .spinner creates a circular animated spinner, most often used to indicate a
|
|
* loading state. The .spinner element must define a width, height, and
|
|
* border-width for the spinner to apply.
|
|
*/
|
|
|
|
@keyframes spin {
|
|
0% {
|
|
transform: rotate(0deg);
|
|
}
|
|
100% {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
|
|
.spinner {
|
|
@apply border-transparent border-t-current border-l-current rounded-full;
|
|
animation: spin 700ms linear infinite;
|
|
}
|
|
|
|
/**
|
|
* .link applies standard styling to links across the app. By default we unstyle
|
|
* all anchor tags. While this might sound crazy for a website, it's _very_
|
|
* helpful in an app, since anchor tags can be used to wrap buttons, icons,
|
|
* and all manner of UI component. As a result, all anchor tags intended to look
|
|
* like links should have a .link class.
|
|
*/
|
|
|
|
.link {
|
|
@apply text-text-primary;
|
|
}
|
|
|
|
.link:hover,
|
|
.link:active {
|
|
@apply text-blue-700;
|
|
}
|
|
|
|
.link-destructive {
|
|
@apply text-text-danger;
|
|
}
|
|
|
|
.link-destructive:hover,
|
|
.link-destructive:active {
|
|
@apply text-red-700;
|
|
}
|
|
|
|
.link-fade {
|
|
}
|
|
|
|
.link-fade:hover {
|
|
@apply opacity-75;
|
|
}
|
|
|
|
.link-underline {
|
|
@apply underline;
|
|
}
|
|
|
|
.link-underline:hover {
|
|
@apply opacity-75;
|
|
}
|
|
}
|
|
|
|
@layer utilities {
|
|
.h-input {
|
|
@apply h-[2.375rem];
|
|
}
|
|
}
|