diff --git a/public/css/main-site.css b/public/css/main-site.css new file mode 100644 index 0000000..1c86b29 --- /dev/null +++ b/public/css/main-site.css @@ -0,0 +1,1527 @@ +/*! tailwindcss v4.1.10 | MIT License | https://tailwindcss.com */ +@layer properties; +@layer theme, base, components, utilities; +@layer theme { + :root, :host { + --font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", + "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", + "Courier New", monospace; + --color-teal-300: oklch(85.5% 0.138 181.071); + --color-teal-400: oklch(77.7% 0.152 181.912); + --color-blue-400: oklch(70.7% 0.165 254.624); + --color-blue-500: oklch(62.3% 0.214 259.815); + --color-gray-200: oklch(92.8% 0.006 264.531); + --color-gray-300: oklch(87.2% 0.01 258.338); + --color-gray-800: oklch(27.8% 0.033 256.848); + --color-gray-900: oklch(21% 0.034 264.665); + --color-white: #fff; + --spacing: 0.25rem; + --container-2xl: 42rem; + --container-3xl: 48rem; + --container-7xl: 80rem; + --text-sm: 0.875rem; + --text-sm--line-height: calc(1.25 / 0.875); + --text-base: 1rem; + --text-base--line-height: calc(1.5 / 1); + --text-lg: 1.125rem; + --text-lg--line-height: calc(1.75 / 1.125); + --text-xl: 1.25rem; + --text-xl--line-height: calc(1.75 / 1.25); + --text-2xl: 1.5rem; + --text-2xl--line-height: calc(2 / 1.5); + --text-3xl: 1.875rem; + --text-3xl--line-height: calc(2.25 / 1.875); + --text-4xl: 2.25rem; + --text-4xl--line-height: calc(2.5 / 2.25); + --text-5xl: 3rem; + --text-5xl--line-height: 1; + --font-weight-medium: 500; + --font-weight-semibold: 600; + --font-weight-bold: 700; + --tracking-tight: -0.025em; + --tracking-wide: 0.025em; + --leading-relaxed: 1.625; + --radius-md: 0.375rem; + --radius-lg: 0.5rem; + --radius-xl: 0.75rem; + --ease-out: cubic-bezier(0, 0, 0.2, 1); + --blur-xl: 24px; + --default-transition-duration: 150ms; + --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + --default-font-family: var(--font-sans); + --default-mono-font-family: var(--font-mono); + } +} +@layer base { + *, ::after, ::before, ::backdrop, ::file-selector-button { + box-sizing: border-box; + margin: 0; + padding: 0; + border: 0 solid; + } + html, :host { + line-height: 1.5; + -webkit-text-size-adjust: 100%; + tab-size: 4; + font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"); + font-feature-settings: var(--default-font-feature-settings, normal); + font-variation-settings: var(--default-font-variation-settings, normal); + -webkit-tap-highlight-color: transparent; + } + 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; + -webkit-text-decoration: inherit; + text-decoration: inherit; + } + b, strong { + font-weight: bolder; + } + code, kbd, samp, pre { + font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace); + font-feature-settings: var(--default-mono-font-feature-settings, normal); + font-variation-settings: var(--default-mono-font-variation-settings, normal); + font-size: 1em; + } + small { + font-size: 80%; + } + sub, sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; + } + sub { + bottom: -0.25em; + } + sup { + top: -0.5em; + } + table { + text-indent: 0; + border-color: inherit; + border-collapse: collapse; + } + :-moz-focusring { + outline: auto; + } + progress { + vertical-align: baseline; + } + summary { + display: list-item; + } + ol, ul, menu { + list-style: none; + } + img, svg, video, canvas, audio, iframe, embed, object { + display: block; + vertical-align: middle; + } + img, video { + max-width: 100%; + height: auto; + } + button, input, select, optgroup, textarea, ::file-selector-button { + font: inherit; + font-feature-settings: inherit; + font-variation-settings: inherit; + letter-spacing: inherit; + color: inherit; + border-radius: 0; + background-color: transparent; + opacity: 1; + } + :where(select:is([multiple], [size])) optgroup { + font-weight: bolder; + } + :where(select:is([multiple], [size])) optgroup option { + padding-inline-start: 20px; + } + ::file-selector-button { + margin-inline-end: 4px; + } + ::placeholder { + opacity: 1; + } + @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) { + ::placeholder { + color: currentcolor; + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, currentcolor 50%, transparent); + } + } + } + textarea { + resize: vertical; + } + ::-webkit-search-decoration { + -webkit-appearance: none; + } + ::-webkit-date-and-time-value { + min-height: 1lh; + text-align: inherit; + } + ::-webkit-datetime-edit { + display: inline-flex; + } + ::-webkit-datetime-edit-fields-wrapper { + padding: 0; + } + ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field { + padding-block: 0; + } + :-moz-ui-invalid { + box-shadow: none; + } + button, input:where([type="button"], [type="reset"], [type="submit"]), ::file-selector-button { + appearance: button; + } + ::-webkit-inner-spin-button, ::-webkit-outer-spin-button { + height: auto; + } + [hidden]:where(:not([hidden="until-found"])) { + display: none !important; + } +} +@layer utilities { + .visible { + visibility: visible; + } + .absolute { + position: absolute; + } + .fixed { + position: fixed; + } + .relative { + position: relative; + } + .static { + position: static; + } + .inset-0 { + inset: calc(var(--spacing) * 0); + } + .z-1 { + z-index: 1; + } + .z-2 { + z-index: 2; + } + .z-10 { + z-index: 10; + } + .z-50 { + z-index: 50; + } + .container { + width: 100%; + @media (width >= 40rem) { + max-width: 40rem; + } + @media (width >= 48rem) { + max-width: 48rem; + } + @media (width >= 64rem) { + max-width: 64rem; + } + @media (width >= 80rem) { + max-width: 80rem; + } + @media (width >= 96rem) { + max-width: 96rem; + } + } + .mx-auto { + margin-inline: auto; + } + .mt-3 { + margin-top: calc(var(--spacing) * 3); + } + .mt-4 { + margin-top: calc(var(--spacing) * 4); + } + .mt-6 { + margin-top: calc(var(--spacing) * 6); + } + .mt-8 { + margin-top: calc(var(--spacing) * 8); + } + .mb-1\.5 { + margin-bottom: calc(var(--spacing) * 1.5); + } + .mb-2 { + margin-bottom: calc(var(--spacing) * 2); + } + .mb-3 { + margin-bottom: calc(var(--spacing) * 3); + } + .mb-4 { + margin-bottom: calc(var(--spacing) * 4); + } + .mb-6 { + margin-bottom: calc(var(--spacing) * 6); + } + .mb-8 { + margin-bottom: calc(var(--spacing) * 8); + } + .mb-10 { + margin-bottom: calc(var(--spacing) * 10); + } + .mb-12 { + margin-bottom: calc(var(--spacing) * 12); + } + .ml-6 { + margin-left: calc(var(--spacing) * 6); + } + .block { + display: block; + } + .contents { + display: contents; + } + .flex { + display: flex; + } + .grid { + display: grid; + } + .hidden { + display: none; + } + .inline { + display: inline; + } + .inline-block { + display: inline-block; + } + .h-0\.5 { + height: calc(var(--spacing) * 0.5); + } + .h-10 { + height: calc(var(--spacing) * 10); + } + .w-6 { + width: calc(var(--spacing) * 6); + } + .w-10 { + width: calc(var(--spacing) * 10); + } + .max-w-2xl { + max-width: var(--container-2xl); + } + .max-w-3xl { + max-width: var(--container-3xl); + } + .max-w-7xl { + max-width: var(--container-7xl); + } + .max-w-full { + max-width: 100%; + } + .transform { + transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,); + } + .list-inside { + list-style-position: inside; + } + .list-decimal { + list-style-type: decimal; + } + .list-disc { + list-style-type: disc; + } + .grid-cols-1 { + grid-template-columns: repeat(1, minmax(0, 1fr)); + } + .flex-col { + flex-direction: column; + } + .flex-wrap { + flex-wrap: wrap; + } + .items-center { + align-items: center; + } + .justify-between { + justify-content: space-between; + } + .justify-center { + justify-content: center; + } + .gap-2 { + gap: calc(var(--spacing) * 2); + } + .gap-4 { + gap: calc(var(--spacing) * 4); + } + .gap-6 { + gap: calc(var(--spacing) * 6); + } + .space-y-2 { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse))); + } + } + .space-y-4 { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse))); + } + } + .space-y-6 { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse))); + } + } + .rounded { + border-radius: 0.25rem; + } + .rounded-lg { + border-radius: var(--radius-lg); + } + .rounded-md { + border-radius: var(--radius-md); + } + .rounded-xl { + border-radius: var(--radius-xl); + } + .border { + border-style: var(--tw-border-style); + border-width: 1px; + } + .bg-gray-800 { + background-color: var(--color-gray-800); + } + .bg-gray-900 { + background-color: var(--color-gray-900); + } + .bg-gray-900\/20 { + background-color: color-mix(in srgb, oklch(21% 0.034 264.665) 20%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-gray-900) 20%, transparent); + } + } + .bg-gray-900\/80 { + background-color: color-mix(in srgb, oklch(21% 0.034 264.665) 80%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-gray-900) 80%, transparent); + } + } + .bg-gray-900\/98 { + background-color: color-mix(in srgb, oklch(21% 0.034 264.665) 98%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-gray-900) 98%, transparent); + } + } + .bg-teal-400 { + background-color: var(--color-teal-400); + } + .bg-gradient-to-r { + --tw-gradient-position: to right in oklab; + background-image: linear-gradient(var(--tw-gradient-stops)); + } + .from-teal-400 { + --tw-gradient-from: var(--color-teal-400); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .to-blue-500 { + --tw-gradient-to: var(--color-blue-500); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .bg-clip-text { + background-clip: text; + } + .p-6 { + padding: calc(var(--spacing) * 6); + } + .p-8 { + padding: calc(var(--spacing) * 8); + } + .px-1 { + padding-inline: calc(var(--spacing) * 1); + } + .px-1\.5 { + padding-inline: calc(var(--spacing) * 1.5); + } + .px-2 { + padding-inline: calc(var(--spacing) * 2); + } + .px-4 { + padding-inline: calc(var(--spacing) * 4); + } + .py-0\.5 { + padding-block: calc(var(--spacing) * 0.5); + } + .py-1 { + padding-block: calc(var(--spacing) * 1); + } + .py-2 { + padding-block: calc(var(--spacing) * 2); + } + .py-8 { + padding-block: calc(var(--spacing) * 8); + } + .py-16 { + padding-block: calc(var(--spacing) * 16); + } + .pb-16 { + padding-bottom: calc(var(--spacing) * 16); + } + .pl-6 { + padding-left: calc(var(--spacing) * 6); + } + .text-center { + text-align: center; + } + .font-mono { + font-family: var(--font-mono); + } + .text-2xl { + font-size: var(--text-2xl); + line-height: var(--tw-leading, var(--text-2xl--line-height)); + } + .text-3xl { + font-size: var(--text-3xl); + line-height: var(--tw-leading, var(--text-3xl--line-height)); + } + .text-4xl { + font-size: var(--text-4xl); + line-height: var(--tw-leading, var(--text-4xl--line-height)); + } + .text-5xl { + font-size: var(--text-5xl); + line-height: var(--tw-leading, var(--text-5xl--line-height)); + } + .text-base { + font-size: var(--text-base); + line-height: var(--tw-leading, var(--text-base--line-height)); + } + .text-lg { + font-size: var(--text-lg); + line-height: var(--tw-leading, var(--text-lg--line-height)); + } + .text-sm { + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + } + .text-xl { + font-size: var(--text-xl); + line-height: var(--tw-leading, var(--text-xl--line-height)); + } + .leading-relaxed { + --tw-leading: var(--leading-relaxed); + line-height: var(--leading-relaxed); + } + .font-bold { + --tw-font-weight: var(--font-weight-bold); + font-weight: var(--font-weight-bold); + } + .font-medium { + --tw-font-weight: var(--font-weight-medium); + font-weight: var(--font-weight-medium); + } + .font-semibold { + --tw-font-weight: var(--font-weight-semibold); + font-weight: var(--font-weight-semibold); + } + .tracking-tight { + --tw-tracking: var(--tracking-tight); + letter-spacing: var(--tracking-tight); + } + .tracking-wide { + --tw-tracking: var(--tracking-wide); + letter-spacing: var(--tracking-wide); + } + .text-gray-200 { + color: var(--color-gray-200); + } + .text-gray-300 { + color: var(--color-gray-300); + } + .text-teal-300 { + color: var(--color-teal-300); + } + .text-teal-400 { + color: var(--color-teal-400); + } + .text-transparent { + color: transparent; + } + .text-white { + color: var(--color-white); + } + .underline { + text-decoration-line: underline; + } + .opacity-90 { + opacity: 90%; + } + .shadow-lg { + --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + .shadow-xl { + --tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + .backdrop-blur-xl { + --tw-backdrop-blur: blur(var(--blur-xl)); + -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + } + .backdrop-filter { + -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + } + .transition { + transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + .transition-all { + transition-property: all; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + .duration-300 { + --tw-duration: 300ms; + transition-duration: 300ms; + } + .ease-out { + --tw-ease: var(--ease-out); + transition-timing-function: var(--ease-out); + } + .hover\:bg-gradient-to-r { + &:hover { + @media (hover: hover) { + --tw-gradient-position: to right in oklab; + background-image: linear-gradient(var(--tw-gradient-stops)); + } + } + } + .hover\:from-blue-500 { + &:hover { + @media (hover: hover) { + --tw-gradient-from: var(--color-blue-500); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + } + } + .hover\:to-teal-400 { + &:hover { + @media (hover: hover) { + --tw-gradient-to: var(--color-teal-400); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + } + } + .hover\:text-blue-400 { + &:hover { + @media (hover: hover) { + color: var(--color-blue-400); + } + } + } + .focus\:outline-none { + &:focus { + --tw-outline-style: none; + outline-style: none; + } + } + .sm\:mb-8 { + @media (width >= 40rem) { + margin-bottom: calc(var(--spacing) * 8); + } + } + .sm\:grid-cols-2 { + @media (width >= 40rem) { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + } + .sm\:p-8 { + @media (width >= 40rem) { + padding: calc(var(--spacing) * 8); + } + } + .sm\:p-10 { + @media (width >= 40rem) { + padding: calc(var(--spacing) * 10); + } + } + .sm\:p-12 { + @media (width >= 40rem) { + padding: calc(var(--spacing) * 12); + } + } + .sm\:px-6 { + @media (width >= 40rem) { + padding-inline: calc(var(--spacing) * 6); + } + } + .sm\:text-2xl { + @media (width >= 40rem) { + font-size: var(--text-2xl); + line-height: var(--tw-leading, var(--text-2xl--line-height)); + } + } + .sm\:text-3xl { + @media (width >= 40rem) { + font-size: var(--text-3xl); + line-height: var(--tw-leading, var(--text-3xl--line-height)); + } + } + .sm\:text-4xl { + @media (width >= 40rem) { + font-size: var(--text-4xl); + line-height: var(--tw-leading, var(--text-4xl--line-height)); + } + } + .sm\:text-lg { + @media (width >= 40rem) { + font-size: var(--text-lg); + line-height: var(--tw-leading, var(--text-lg--line-height)); + } + } + .md\:flex { + @media (width >= 48rem) { + display: flex; + } + } + .md\:hidden { + @media (width >= 48rem) { + display: none; + } + } + .md\:p-10 { + @media (width >= 48rem) { + padding: calc(var(--spacing) * 10); + } + } + .md\:text-4xl { + @media (width >= 48rem) { + font-size: var(--text-4xl); + line-height: var(--tw-leading, var(--text-4xl--line-height)); + } + } + .lg\:grid-cols-3 { + @media (width >= 64rem) { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + } + .lg\:grid-cols-4 { + @media (width >= 64rem) { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } + } + .lg\:p-16 { + @media (width >= 64rem) { + padding: calc(var(--spacing) * 16); + } + } + .lg\:px-8 { + @media (width >= 64rem) { + padding-inline: calc(var(--spacing) * 8); + } + } +} +@font-face { + font-family: 'Minecraft'; + src: url('../font/MinecraftRegular-Bmg3.otf') format('opentype'); + font-weight: normal; + font-style: normal; +} +html, body { + margin: 0; + padding: 0; + background: none; + min-height: 100vh; +} +body { + background: #10142b; + background-size: 200% 200%; + animation: bgShift 15s ease infinite; + font-family: 'Roboto', 'Verdana', sans-serif; + color: #e0e7ff; + overflow-x: hidden; + position: relative; + min-height: 100vh; + scroll-behavior: smooth; +} +@keyframes bgShift { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } +} +::-webkit-scrollbar { + width: 8px; +} +::-webkit-scrollbar-track { + background: linear-gradient(135deg, #0b0f2b, #1a2249); + border: none; +} +::-webkit-scrollbar-thumb { + background: linear-gradient(45deg, #14b8a6, #3b82f6); + border-radius: 4px; + border: 1px solid rgba(10, 17, 40, 0.8); + transition: background 0.3s ease; +} +::-webkit-scrollbar-thumb:hover { + background: linear-gradient(45deg, #2dd4bf, #60a5fa); + box-shadow: 0 0 10px rgba(20, 184, 166, 0.5); +} +.minecraft-font { + font-family: 'Minecraft', sans-serif; + letter-spacing: 0.8px; + text-shadow: 0 0 8px rgba(20, 184, 166, 0.5); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + background: linear-gradient(to right, #14b8a6, #3b82f6); + -webkit-background-clip: text; + background-clip: text; + color: transparent; + transform: translateZ(0); + position: relative; +} +.minecraft-font:hover { + animation: glitch 0.3s linear infinite; +} +@keyframes glitch { + 0% { + transform: translate(0); + text-shadow: 0 0 8px rgba(20, 184, 166, 0.5); + } + 20% { + transform: translate(-2px, 2px); + text-shadow: 0 0 8px rgba(20, 184, 166, 0.5), 2px 0 #3b82f6; + } + 40% { + transform: translate(2px, -2px); + text-shadow: 0 0 8px rgba(20, 184, 166, 0.5), -2px 0 #14b8a6; + } + 60% { + transform: translate(-2px, 0); + text-shadow: 0 0 8px rgba(20, 184, 166, 0.5), 2px 0 #3b82f6; + } + 80% { + transform: translate(2px, 0); + text-shadow: 0 0 8px rgba(20, 184, 166, 0.5), -2px 0 #14b8a6; + } + 100% { + transform: translate(0); + text-shadow: 0 0 8px rgba(20, 184, 166, 0.5); + } +} +.section-bg { + background: rgba(10, 17, 40, 0.3); + -webkit-backdrop-filter: blur(12px); + backdrop-filter: blur(12px); + border-radius: 24px; + border: 1px solid rgba(255, 255, 255, 0.15); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2), inset 0 0 15px rgba(255, 255, 255, 0.1); + transition: box-shadow 0.4s ease, background 0.4s ease, -webkit-backdrop-filter 0.4s ease, backdrop-filter 0.4s ease; + animation: floatSection 4s ease-in-out infinite; + z-index: 2; +} +.section-bg h1, .section-bg h2, .section-bg h3, .section-bg h4 { + transform: translateZ(0); +} +.section-bg p, .section-bg a:not(.btn-minecraft) { + font-family: 'Roboto', 'Verdana', sans-serif; + color: #e0e7ff; + transform: translateZ(0); +} +.section-bg:hover { + background: rgba(10, 17, 40, 0.4); + -webkit-backdrop-filter: blur(14px); + backdrop-filter: blur(14px); + box-shadow: 0 12px 40px rgba(20, 184, 166, 0.4), inset 0 0 20px rgba(255, 255, 255, 0.12); +} +@keyframes floatSection { + 0%, 100% { + box-shadow: 0 6px 25px rgba(0, 0, 0, 0.4), inset 0 0 15px rgba(255, 255, 255, 0.08); + } + 50% { + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5), inset 0 0 18px rgba(255, 255, 255, 0.1); + } +} +.btn-minecraft { + background: linear-gradient(45deg, #14b8a6, #3b82f6); + background-size: 300% 300%; + border: none; + color: #fff; + text-shadow: 0 0 8px rgba(0, 0, 0, 0.6); + border-radius: 14px; + padding: 14px 30px; + font-weight: 700; + position: relative; + overflow: hidden; + transition: transform 0.3s, box-shadow 0.3s; + animation: gradientShift 5s ease infinite; + box-shadow: 0 0 15px rgba(20, 184, 166, 0.5), 0 0 25px rgba(59, 130, 246, 0.3); +} +.btn-minecraft::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent); + transition: left 0.5s; +} +.btn-minecraft:hover::before { + left: 100%; +} +.btn-minecraft:hover { + transform: scale(1.1); + box-shadow: 0 0 20px rgba(20, 184, 166, 0.8), 0 0 30px rgba(59, 130, 246, 0.5), 0 0 40px rgba(20, 184, 166, 0.3); + animation: neonPulse 1.5s ease-in-out infinite; +} +.btn-minecraft::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 0; + height: 0; + background: radial-gradient(circle, rgba(20, 184, 166, 0.5), transparent); + opacity: 0; + transition: width 0.3s, height 0.3s, opacity 0.3s; + transform: translate(-50%, -50%); +} +.btn-minecraft:hover::after { + width: 200px; + height: 200px; + opacity: 1; +} +@keyframes neonPulse { + 0%, 100% { + filter: brightness(1); + } + 50% { + filter: brightness(1.2); + } +} +@keyframes gradientShift { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } +} +.hero-bg { + position: relative; + overflow: hidden; + min-height: 600px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 24px; + background: rgba(10, 17, 40, 0.75); + z-index: 2; +} +.hero-bg iframe { + position: absolute; + top: 50%; + left: 50%; + width: 120%; + height: 120%; + min-height: 600px; + transform: translate(-50%, -50%) scale(1.2); + object-fit: cover; + z-index: 1; + border: none; + pointer-events: none; + backface-visibility: hidden; +} +.hero-bg img { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + object-fit: cover; + z-index: 0; + display: none; +} +.hero-bg::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(to bottom, rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.6)); + z-index: 2; +} +.hero-content { + position: relative; + z-index: 3; + text-align: center; + padding: 4rem; + animation: scaleIn 1.2s ease-out; +} +.hero-content h2 { + transform: translateZ(0); +} +.hero-content p { + font-family: 'Roboto', 'Verdana', sans-serif; + color: #e0e7ff; + transform: translateZ(0); +} +.header-content { + animation: scaleIn 1s ease-out; +} +.header-content h1 { + transform: translateZ(0); +} +.header-content p { + font-family: 'Roboto', 'Verdana', sans-serif; + color: #e0e7ff; + transform: translateZ(0); +} +@keyframes scaleIn { + from { + opacity: 0; + transform: scale(0.95); + } + to { + opacity: 1; + transform: scale(1); + } +} +.feature-card { + background: rgba(15, 23, 50, 0.85); + border-radius: 18px; + padding: 2rem; + border: 1px solid rgba(255, 255, 255, 0.06); + position: relative; + overflow: hidden; +} + +.feature-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0; +} +.feature-card:hover::before { + opacity: 1; +} +.feature-card h3, .feature-card h4 { +} +.feature-card p { + font-family: 'Roboto', 'Verdana', sans-serif; + color: #e0e7ff; +} +.particle { + position: absolute; + width: 8px; + height: 8px; + background: linear-gradient(45deg, #14b8a6, #3b82f6); + border-radius: 50%; + opacity: 0; + animation: float linear infinite, fadeInOut ease-in-out infinite; + z-index: -1; + pointer-events: none; + mix-blend-mode: screen; + will-change: transform, opacity; +} +.particle.large { + width: 12px; + height: 12px; +} +@keyframes fadeInOut { + 0%, 100% { + opacity: 0; + } + 50% { + opacity: 0.8; + } +} +@keyframes float { + 0% { + transform: translateY(0); + } + 100% { + transform: translateY(-100vh); + } +} +.particle.fade-out { + animation: fadeOut 0.5s ease-out forwards; +} +@keyframes fadeOut { + 0% { + opacity: 0.8; + } + 100% { + opacity: 0; + } +} +.header-bg { + background: linear-gradient(180deg, rgba(10, 17, 40, 0.95), rgba(5, 15, 35, 0.95)); + border-bottom: 1px solid rgba(255, 255, 255, 0.12); + position: relative; + overflow: hidden; + z-index: 2; +} +footer { + background: rgba(10, 17, 40, 0.75); + -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); + z-index: 2; +} +footer a { + color: #2dd4bf; + transition: color 0.3s, text-shadow 0.3s; +} +footer a:hover { + color: #60a5fa; + text-shadow: 0 0 8px rgba(96, 165, 250, 0.7); +} +.nav-btn { + display: inline-block; + padding: 0.5rem 1rem; + background: linear-gradient(to right, #14b8a6, #3b82f6); + color: white; + text-decoration: none; + border-radius: 0.375rem; + font-size: 0.875rem; + font-weight: 500; + transition: transform 0.2s, box-shadow 0.2s; + min-width: 50px; + text-align: center; + position: relative; + overflow: hidden; +} +.nav-btn2 { + display: inline-block; + padding: 0.5rem 1rem; + background: linear-gradient(to right, #14b8a6, #3b82f6); + color: white; + text-decoration: none; + border-radius: 0.375rem; + font-size: 0.875rem; + font-weight: 500; + transition: transform 0.2s, box-shadow 0.2s; + min-width: 50px; + text-align: center; + position: relative; + overflow: hidden; +} +.nav-btn::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); + transition: left 0.4s ease; +} +.nav-btn2::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); + transition: left 0.4s ease; +} +.nav-btn:hover::before { + left: 100%; +} +.nav-btn2:hover::before { + left: 100%; +} +.nav-btn:hover { + transform: translateY(-2px); + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); +} +.nav-btn2:hover { + transform: translateY(-2px); + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); +} +.hamburger { + display: none; + position: fixed; + top: 1rem; + right: 1rem; + z-index: 20001; +} +.hamburger.active .bar:nth-child(1) { + transform: translateY(8px) rotate(45deg); +} +.hamburger.active .bar:nth-child(2) { + opacity: 0; +} +.hamburger.active .bar:nth-child(3) { + transform: translateY(-8px) rotate(-45deg); +} +.mobile-nav-container { + display: none; + opacity: 0; + visibility: hidden; + transition: opacity 0.3s ease, visibility 0.3s ease; + background: linear-gradient(135deg, rgba(10, 17, 40, 0.98), rgba(5, 15, 35, 0.98)); + -webkit-backdrop-filter: blur(5px); + backdrop-filter: blur(5px); + z-index: 20000; + padding: 4rem 2rem; + pointer-events: auto; +} +.mobile-nav-container.active { + display: flex; + opacity: 1; + visibility: visible; +} +.mobile-nav-container ul li a { + display: block; + padding: 1rem 2rem; + border-radius: 8px; + transition: background 0.3s ease; + font-size: 1.25rem; + text-shadow: 0 0 8px rgba(20, 184, 166, 0.5); + transform: translateZ(0); +} +.mobile-nav-container ul li a:hover { + transform: translateX(10px); +} +@media not all and (min-resolution:.001dpcm) { + .particle { + z-index: -2; + backface-visibility: hidden; + } +} +@media (max-width: 768px) { + .hero-bg { + min-height: 500px; + } + .hero-bg iframe { + min-height: 500px; + } + .btn-minecraft { + padding: 12px 26px; + font-size: 0.9rem; + } + .minecraft-font.text-5xl { + font-size: 2.5rem; + } + .minecraft-font.text-4xl { + font-size: 2rem; + } + .minecraft-font.text-3xl { + font-size: 1.75rem; + } + .feature-card { + padding: 1.5rem; + } + .nav-btn { + display: none; + } + .hamburger { + display: flex; + } + #toggleTutorial.nav-btn { + @apply block; + } +} +@media (max-width: 640px) { + .hero-bg { + min-height: 400px; + } + .hero-bg iframe { + min-height: 400px; + } + .minecraft-font.text-5xl { + font-size: 2rem; + } + .minecraft-font.text-4xl { + font-size: 1.75rem; + } + .minecraft-font.text-3xl { + font-size: 1.5rem; + } + .mobile-nav-container ul li a { + font-size: 1rem; + padding: 0.75rem 1.5rem; + } +} +@property --tw-rotate-x { + syntax: "*"; + inherits: false; +} +@property --tw-rotate-y { + syntax: "*"; + inherits: false; +} +@property --tw-rotate-z { + syntax: "*"; + inherits: false; +} +@property --tw-skew-x { + syntax: "*"; + inherits: false; +} +@property --tw-skew-y { + syntax: "*"; + inherits: false; +} +@property --tw-space-y-reverse { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-border-style { + syntax: "*"; + inherits: false; + initial-value: solid; +} +@property --tw-gradient-position { + syntax: "*"; + inherits: false; +} +@property --tw-gradient-from { + syntax: ""; + inherits: false; + initial-value: #0000; +} +@property --tw-gradient-via { + syntax: ""; + inherits: false; + initial-value: #0000; +} +@property --tw-gradient-to { + syntax: ""; + inherits: false; + initial-value: #0000; +} +@property --tw-gradient-stops { + syntax: "*"; + inherits: false; +} +@property --tw-gradient-via-stops { + syntax: "*"; + inherits: false; +} +@property --tw-gradient-from-position { + syntax: ""; + inherits: false; + initial-value: 0%; +} +@property --tw-gradient-via-position { + syntax: ""; + inherits: false; + initial-value: 50%; +} +@property --tw-gradient-to-position { + syntax: ""; + inherits: false; + initial-value: 100%; +} +@property --tw-leading { + syntax: "*"; + inherits: false; +} +@property --tw-font-weight { + syntax: "*"; + inherits: false; +} +@property --tw-tracking { + syntax: "*"; + inherits: false; +} +@property --tw-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-shadow-color { + syntax: "*"; + inherits: false; +} +@property --tw-shadow-alpha { + syntax: ""; + inherits: false; + initial-value: 100%; +} +@property --tw-inset-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-inset-shadow-color { + syntax: "*"; + inherits: false; +} +@property --tw-inset-shadow-alpha { + syntax: ""; + inherits: false; + initial-value: 100%; +} +@property --tw-ring-color { + syntax: "*"; + inherits: false; +} +@property --tw-ring-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-inset-ring-color { + syntax: "*"; + inherits: false; +} +@property --tw-inset-ring-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-ring-inset { + syntax: "*"; + inherits: false; +} +@property --tw-ring-offset-width { + syntax: ""; + inherits: false; + initial-value: 0px; +} +@property --tw-ring-offset-color { + syntax: "*"; + inherits: false; + initial-value: #fff; +} +@property --tw-ring-offset-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-backdrop-blur { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-brightness { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-contrast { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-grayscale { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-hue-rotate { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-invert { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-opacity { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-saturate { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-sepia { + syntax: "*"; + inherits: false; +} +@property --tw-duration { + syntax: "*"; + inherits: false; +} +@property --tw-ease { + syntax: "*"; + inherits: false; +} +@layer properties { + @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) { + *, ::before, ::after, ::backdrop { + --tw-rotate-x: initial; + --tw-rotate-y: initial; + --tw-rotate-z: initial; + --tw-skew-x: initial; + --tw-skew-y: initial; + --tw-space-y-reverse: 0; + --tw-border-style: solid; + --tw-gradient-position: initial; + --tw-gradient-from: #0000; + --tw-gradient-via: #0000; + --tw-gradient-to: #0000; + --tw-gradient-stops: initial; + --tw-gradient-via-stops: initial; + --tw-gradient-from-position: 0%; + --tw-gradient-via-position: 50%; + --tw-gradient-to-position: 100%; + --tw-leading: initial; + --tw-font-weight: initial; + --tw-tracking: initial; + --tw-shadow: 0 0 #0000; + --tw-shadow-color: initial; + --tw-shadow-alpha: 100%; + --tw-inset-shadow: 0 0 #0000; + --tw-inset-shadow-color: initial; + --tw-inset-shadow-alpha: 100%; + --tw-ring-color: initial; + --tw-ring-shadow: 0 0 #0000; + --tw-inset-ring-color: initial; + --tw-inset-ring-shadow: 0 0 #0000; + --tw-ring-inset: initial; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-backdrop-blur: initial; + --tw-backdrop-brightness: initial; + --tw-backdrop-contrast: initial; + --tw-backdrop-grayscale: initial; + --tw-backdrop-hue-rotate: initial; + --tw-backdrop-invert: initial; + --tw-backdrop-opacity: initial; + --tw-backdrop-saturate: initial; + --tw-backdrop-sepia: initial; + --tw-duration: initial; + --tw-ease: initial; + } + } +} diff --git a/public/css/style.css b/public/css/style.css new file mode 100644 index 0000000..7ff1acc --- /dev/null +++ b/public/css/style.css @@ -0,0 +1,552 @@ +@import "tailwindcss"; + +@font-face { + font-family: 'Minecraft'; + src: url('../font/MinecraftRegular-Bmg3.otf') format('opentype'); + font-weight: normal; + font-style: normal; + font-display: swap; +} + +@layer base { + html { + @apply h-full; + margin: 0; + padding: 0; + box-sizing: border-box; + overflow-x: hidden; + } + + *, + *:before, + *:after { + box-sizing: inherit; + } + + body { + @apply min-h-full flex flex-col bg-gray-900 text-white; + font-family: 'Roboto', 'Verdana', sans-serif; + overflow-x: hidden; + } + + h1, + h2, + h3, + h4, + h5, + h6 { + @apply font-[Minecraft] text-white; + letter-spacing: 0.5px; + } + + .xterm { + background-color: #111426 !important; + } + + #app { + @apply flex-grow; + } + + main { + @apply flex-grow container mx-auto px-4 sm:px-6 lg:px-8 py-6; + } + + footer { + @apply bg-gray-800 py-4 text-center; + } + + canvas { + @apply w-full max-w-[150px] h-auto; + aspect-ratio: 1/1; + } + + ::-webkit-scrollbar { + width: 8px; + } + + ::-webkit-scrollbar-track { + @apply bg-gray-800; + } + + ::-webkit-scrollbar-thumb { + @apply bg-blue-600 rounded; + } + + ::-webkit-scrollbar-thumb:hover { + @apply bg-blue-700; + } +} + +@layer components { + .section-bg { + @apply bg-gray-800 p-6 rounded-lg shadow-lg mb-6 w-full max-w-full; + overflow-x: hidden; + } + + .modal { + @apply fixed inset-0 bg-black/75 flex items-center justify-center z-[1000]; + } + + .modal-content { + @apply bg-gray-800 p-6 rounded-lg w-full max-w-xl relative max-h-[80vh] overflow-y-auto; + scrollbar-width: thin; + scrollbar-color: #4B5563 #1F2937; + } + + @media (max-width: 640px) { + .holesail-output-mobile-hidden { + display: none; + } + } + + .modal-content::-webkit-scrollbar { + @apply w-2; + } + + .modal-content::-webkit-scrollbar-track { + @apply bg-gray-800; + } + + .modal-content::-webkit-scrollbar-thumb { + @apply bg-gray-600 rounded; + } + + .modal-content::-webkit-scrollbar-thumb:hover { + @apply bg-gray-500; + } + + .modal-close { + @apply absolute top-2 right-2 bg-transparent border-none text-white text-xl cursor-pointer; + } + + .control-btn { + @apply text-white font-medium px-4 py-2 rounded transition duration-200; + } + + .spinner { + @apply border-4 border-gray-700 border-t-blue-600 rounded-full w-6 h-6 animate-spin inline-block; + } + + @keyframes spin { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } + } + + #notificationContainer { + @apply fixed bottom-4 right-4 z-[1000] flex flex-col-reverse gap-2; + } + + .notification { + @apply bg-gray-800 p-3 rounded-lg text-white flex items-center gap-2 shadow-lg; + max-width: 90%; + font-size: 0.875rem; + } + + .notification.success { + @apply bg-green-600; + } + + .notification.error { + @apply bg-red-600; + } + + #dockerLogsTerminal { + @apply bg-gray-900 p-4 rounded-lg w-full max-w-full box-border; + height: 250px; + overflow-y: hidden; + overflow-x: hidden; + } + + .xterm .xterm-viewport { + @apply overflow-y-auto; + height: 250px; + scrollbar-width: thin; + scrollbar-color: #3b82f6 #1f2937; + } + + .xterm .xterm-viewport::-webkit-scrollbar { + width: 8px; + } + + .xterm .xterm-viewport::-webkit-scrollbar-track { + @apply bg-gray-800; + } + + .xterm .xterm-viewport::-webkit-scrollbar-thumb { + @apply bg-blue-600 rounded; + } + + .xterm .xterm-viewport::-webkit-scrollbar-thumb:hover { + @apply bg-blue-700; + } + + .xterm .xterm-screen { + @apply w-full; + } + + .item-entry { + @apply flex items-center gap-2 mb-2 w-full flex-wrap; + } + + .item-entry input { + @apply bg-gray-700 p-2 rounded text-white w-full sm:w-auto; + } + + .item-entry .item-amount { + @apply w-16 sm:w-12; + } + + [role="switch"] { + @apply inline-block relative w-10 h-6 cursor-pointer; + } + + [role="switch"]>div:first-child { + @apply block w-full h-full rounded-full bg-gray-700 transition-colors duration-200; + } + + [role="switch"]>div:last-child { + @apply absolute w-4 h-4 rounded-full bg-white top-1 transition-all duration-200; + } + + [role="switch"][aria-checked="true"]>div:first-child { + @apply bg-blue-600; + } + + [role="switch"][aria-checked="true"]>div:last-child { + @apply left-5; + } + + [role="switch"][aria-checked="false"]>div:last-child { + @apply left-1; + } + + #sftpIframe { + @apply w-full rounded; + height: 50vh; + min-height: 300px; + } + + #propertiesSearch { + @apply bg-gray-700 p-2 rounded text-white w-full; + } + + #propertiesList { + @apply space-y-2; + } + + .nav-btn { + @apply bg-blue-600 text-white font-medium px-3 py-1 rounded transition duration-200 text-sm; + } + .nav-btn2 { + @apply bg-blue-600 text-white font-medium px-3 py-1 rounded transition duration-200 text-sm; + } + + .nav-btn:hover:not(.disabled) { + @apply bg-blue-700; + } + + .nav-btn.current { + @apply bg-blue-800 border-2 border-blue-400 font-bold; + } + + .nav-btn.disabled { + @apply bg-gray-600 cursor-not-allowed opacity-50; + } + + .pagination-container { + @apply flex justify-center items-center gap-1 mt-4; + } + + .pagination-container .nav-btn { + @apply px-2 py-0.5 text-xs rounded-sm; + } + + .pagination-container .nav-btn.current { + @apply bg-blue-800 border-1 border-blue-400 font-bold; + } + + .pagination-container .nav-btn.disabled { + @apply bg-gray-600 cursor-not-allowed opacity-50; + } +} + +.hamburger { + @apply md:hidden flex flex-col justify-center items-center w-10 h-10 fixed top-4 right-4 z-[99999]; +} + +.hamburger .bar { + @apply w-6 h-0.5 bg-blue-400 mb-1.5 transition-all duration-300; +} + +.hamburger.active .bar:nth-child(1) { + @apply translate-y-2 rotate-45; +} + +.hamburger.active .bar:nth-child(2) { + @apply opacity-0; +} + +.hamburger.active .bar:nth-child(3) { + @apply -translate-y-2 -rotate-45; +} + +.mobile-nav-container { + @apply hidden fixed inset-0 flex-col items-center justify-center bg-gray-900 z-[99998] p-4; + transition: opacity 0.3s ease, visibility 0.3s ease; +} + +.mobile-nav-container.active { + @apply flex opacity-100 visible; +} + +.mobile-nav-container ul li a, +.mobile-nav-container ul li button { + @apply block px-4 py-2 rounded text-lg text-white bg-blue-600 hover:bg-blue-700 mb-4; +} + +.control-btn { + @apply text-white font-medium px-4 py-2 rounded transition duration-200; +} + +#startBtn { + @apply bg-green-600 hover:bg-green-700; +} + +#stopBtn { + @apply bg-red-600 hover:bg-red-700; +} + +#restartBtn { + @apply bg-yellow-500 hover:bg-yellow-600 text-black; +} + +.disabled-btn { + @apply pointer-events-none cursor-not-allowed opacity-50; +} + +.disabled-btn:hover { + @apply cursor-not-allowed; +} + +.copy-key-btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.25rem; + background-color: #374151; + border-radius: 0.25rem; + color: #ffffff; + transition: background-color 0.2s; +} + +.copy-key-btn:hover { + background-color: #4b5563; +} + +.copy-key-btn svg { + width: 1rem; + height: 1rem; +} + +@media (max-width: 768px) { + .section-bg { + @apply p-4; + } + + .modal-content { + @apply p-4 max-w-[95%]; + } + + .section-bg .grid { + @apply grid-cols-1; + } + + .section-bg .flex { + @apply flex-col gap-2; + } + + canvas { + @apply max-w-[120px]; + } + + .section-bg input, + .section-bg textarea, + .section-bg select { + @apply p-2 text-sm; + } + + .section-bg pre { + @apply text-sm; + } + + #sftpIframe { + @apply h-[40vh] min-h-[300px]; + } + + #consoleOutput { + @apply h-32 text-sm; + } + + .notification { + @apply text-sm p-2 max-w-[80%]; + } + + h1 { + @apply text-3xl; + } + + h2 { + @apply text-xl; + } + + h3 { + @apply text-base; + } + + p, + span, + a { + @apply text-sm; + } + + .nav-btn { + @apply hidden; + } + + .hamburger { + @apply flex; + } + + .control-btn { + @apply px-3 py-1 text-sm; + } + + .item-entry { + @apply flex-col gap-1; + } + + .item-entry .item-amount { + @apply w-full; + } +} + +@media (max-width: 640px) { + .section-bg { + @apply p-3; + } + + .modal-content { + @apply p-3 max-w-[95%]; + } + + canvas { + @apply max-w-[100px]; + } + + .section-bg input, + .section-bg textarea, + .section-bg select { + @apply p-1 text-xs; + } + + .section-bg pre { + @apply text-xs; + } + + #sftpIframe { + @apply h-[35vh] min-h-[250px]; + } + + #consoleOutput { + @apply h-28 text-xs; + } + + .notification { + @apply text-xs p-1 max-w-[90%]; + } + + h1 { + @apply text-2xl; + } + + h2 { + @apply text-lg; + } + + h3 { + @apply text-sm; + } + + p, + span, + a { + @apply text-xs; + } + + .control-btn { + @apply px-2 py-1 text-xs; + } +} + +@media (max-width: 480px) { + .section-bg { + @apply p-2; + } + + .modal-content { + @apply p-2 max-w-[98%]; + } + + canvas { + @apply max-w-[80px]; + } + + .section-bg input, + .section-bg textarea, + .section-bg select { + @apply p-1 text-xs; + } + + .section-bg pre { + @apply text-xs; + } + + #sftpIframe { + @apply h-[30vh] min-h-[200px]; + } + + #consoleOutput { + @apply h-24 text-xs; + } + + .notification { + @apply text-xs p-1 max-w-[95%]; + } + + h1 { + @apply text-xl; + } + + h2 { + @apply text-base; + } + + h3 { + @apply text-xs; + } + + p, + span, + a { + @apply text-xs; + } + + .control-btn { + @apply px-2 py-1 text-xs; + } +} \ No newline at end of file diff --git a/public/css/styles.min.css b/public/css/style.min.css similarity index 57% rename from public/css/styles.min.css rename to public/css/style.min.css index ea78bb7..1d5b18a 100644 --- a/public/css/styles.min.css +++ b/public/css/style.min.css @@ -1,17 +1,5 @@ /*! tailwindcss v4.1.8 | MIT License | https://tailwindcss.com */ @layer properties; -@font-face { - font-family: 'Minecraft'; - src: url('../font/MinecraftRegular-Bmg3.otf') format('opentype'); - font-weight: normal; - font-style: normal; - font-display: swap; -} -@media (max-width: 640px) { - .holesail-output-mobile-hidden { - display: none; - } -} @layer theme, base, components, utilities; @layer theme { :root, :host { @@ -22,10 +10,13 @@ --color-red-500: oklch(63.7% 0.237 25.331); --color-red-600: oklch(57.7% 0.245 27.325); --color-red-700: oklch(50.5% 0.213 27.518); + --color-yellow-500: oklch(79.5% 0.184 86.047); --color-yellow-600: oklch(68.1% 0.162 75.834); --color-yellow-700: oklch(55.4% 0.135 66.442); --color-green-600: oklch(62.7% 0.194 149.214); --color-green-700: oklch(52.7% 0.154 150.069); + --color-teal-300: oklch(85.5% 0.138 181.071); + --color-teal-400: oklch(77.7% 0.152 181.912); --color-teal-600: oklch(60% 0.118 184.704); --color-teal-700: oklch(51.1% 0.096 186.391); --color-cyan-600: oklch(60.9% 0.126 221.723); @@ -34,6 +25,7 @@ --color-blue-500: oklch(62.3% 0.214 259.815); --color-blue-600: oklch(54.6% 0.245 262.881); --color-blue-700: oklch(48.8% 0.243 264.376); + --color-blue-800: oklch(42.4% 0.199 265.638); --color-purple-600: oklch(55.8% 0.288 302.321); --color-purple-700: oklch(49.6% 0.265 301.924); --color-gray-100: oklch(96.7% 0.003 264.542); @@ -50,6 +42,9 @@ --spacing: 0.25rem; --container-md: 28rem; --container-xl: 36rem; + --container-2xl: 42rem; + --container-3xl: 48rem; + --container-7xl: 80rem; --text-xs: 0.75rem; --text-xs--line-height: calc(1 / 0.75); --text-sm: 0.875rem; @@ -62,15 +57,26 @@ --text-xl--line-height: calc(1.75 / 1.25); --text-2xl: 1.5rem; --text-2xl--line-height: calc(2 / 1.5); + --text-3xl: 1.875rem; + --text-3xl--line-height: calc(2.25 / 1.875); + --text-4xl: 2.25rem; + --text-4xl--line-height: calc(2.5 / 2.25); + --text-5xl: 3rem; + --text-5xl--line-height: 1; --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; + --tracking-tight: -0.025em; + --tracking-wide: 0.025em; --leading-relaxed: 1.625; + --radius-sm: 0.25rem; --radius-md: 0.375rem; --radius-lg: 0.5rem; --radius-xl: 0.75rem; + --ease-out: cubic-bezier(0, 0, 0.2, 1); --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); --animate-spin: spin 1s linear infinite; + --blur-xl: 24px; --default-transition-duration: 150ms; --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); --default-font-family: var(--font-sans); @@ -238,6 +244,9 @@ .inset-0 { inset: calc(var(--spacing) * 0); } + .z-2 { + z-index: 2; + } .z-50 { z-index: 50; } @@ -268,6 +277,9 @@ .mt-2 { margin-top: calc(var(--spacing) * 2); } + .mt-3 { + margin-top: calc(var(--spacing) * 3); + } .mt-4 { margin-top: calc(var(--spacing) * 4); } @@ -277,6 +289,9 @@ .mb-1 { margin-bottom: calc(var(--spacing) * 1); } + .mb-1\.5 { + margin-bottom: calc(var(--spacing) * 1.5); + } .mb-2 { margin-bottom: calc(var(--spacing) * 2); } @@ -289,6 +304,12 @@ .mb-6 { margin-bottom: calc(var(--spacing) * 6); } + .mb-8 { + margin-bottom: calc(var(--spacing) * 8); + } + .mb-12 { + margin-bottom: calc(var(--spacing) * 12); + } .ml-2 { margin-left: calc(var(--spacing) * 2); } @@ -310,8 +331,14 @@ .inline-block { display: inline-block; } - .h-5 { - height: calc(var(--spacing) * 5); + .h-0\.5 { + height: calc(var(--spacing) * 0.5); + } + .h-4 { + height: calc(var(--spacing) * 4); + } + .h-10 { + height: calc(var(--spacing) * 10); } .h-24 { height: calc(var(--spacing) * 24); @@ -322,9 +349,6 @@ .h-full { height: 100%; } - .max-h-\[95vh\] { - max-height: 95vh; - } .max-h-\[calc\(95vh-10rem\)\] { max-height: calc(95vh - 10rem); } @@ -337,8 +361,14 @@ .w-2\/3 { width: calc(2/3 * 100%); } - .w-5 { - width: calc(var(--spacing) * 5); + .w-4 { + width: calc(var(--spacing) * 4); + } + .w-6 { + width: calc(var(--spacing) * 6); + } + .w-10 { + width: calc(var(--spacing) * 10); } .w-20 { width: calc(var(--spacing) * 20); @@ -349,12 +379,18 @@ .w-full { width: 100%; } - .max-w-\[95\%\] { - max-width: 95%; + .max-w-7xl { + max-width: var(--container-7xl); } .max-w-md { max-width: var(--container-md); } + .min-w-0 { + min-width: calc(var(--spacing) * 0); + } + .min-w-\[250px\] { + min-width: 250px; + } .flex-1 { flex: 1; } @@ -385,6 +421,9 @@ .flex-col { flex-direction: column; } + .flex-row { + flex-direction: row; + } .flex-wrap { flex-wrap: wrap; } @@ -444,6 +483,13 @@ margin-inline-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-x-reverse))); } } + .space-x-3 { + :where(& > :not(:last-child)) { + --tw-space-x-reverse: 0; + margin-inline-start: calc(calc(var(--spacing) * 3) * var(--tw-space-x-reverse)); + margin-inline-end: calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-x-reverse))); + } + } .space-x-4 { :where(& > :not(:last-child)) { --tw-space-x-reverse: 0; @@ -454,9 +500,6 @@ .overflow-x-auto { overflow-x: auto; } - .overflow-x-hidden { - overflow-x: hidden; - } .overflow-y-auto { overflow-y: auto; } @@ -487,11 +530,17 @@ border-bottom-style: var(--tw-border-style); border-bottom-width: 1px; } - .border-gray-500 { - border-color: var(--color-gray-500); + .border-\[rgba\(255\,255\,255\,0\.12\)\] { + border-color: rgba(255,255,255,0.12); } - .border-gray-600 { - border-color: var(--color-gray-600); + .border-\[rgba\(255\,255\,255\,0\.15\)\] { + border-color: rgba(255,255,255,0.15); + } + .bg-\[rgba\(10\,17\,40\,0\.3\)\] { + background-color: rgba(10,17,40,0.3); + } + .bg-\[rgba\(10\,17\,40\,0\.75\)\] { + background-color: rgba(10,17,40,0.75); } .bg-black { background-color: var(--color-black); @@ -511,8 +560,11 @@ .bg-gray-800 { background-color: var(--color-gray-800); } - .bg-gray-900 { - background-color: var(--color-gray-900); + .bg-gray-800\/40 { + background-color: color-mix(in srgb, oklch(27.8% 0.033 256.848) 40%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-gray-800) 40%, transparent); + } } .bg-green-600 { background-color: var(--color-green-600); @@ -523,14 +575,29 @@ .bg-red-600 { background-color: var(--color-red-600); } + .bg-teal-400 { + background-color: var(--color-teal-400); + } .bg-teal-600 { background-color: var(--color-teal-600); } .bg-white { background-color: var(--color-white); } - .bg-yellow-600 { - background-color: var(--color-yellow-600); + .bg-gradient-to-r { + --tw-gradient-position: to right in oklab; + background-image: linear-gradient(var(--tw-gradient-stops)); + } + .from-teal-400 { + --tw-gradient-from: var(--color-teal-400); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .to-blue-500 { + --tw-gradient-to: var(--color-blue-500); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .bg-clip-text { + background-clip: text; } .p-2 { padding: calc(var(--spacing) * 2); @@ -544,9 +611,6 @@ .p-6 { padding: calc(var(--spacing) * 6); } - .p-8 { - padding: calc(var(--spacing) * 8); - } .px-1 { padding-inline: calc(var(--spacing) * 1); } @@ -559,20 +623,20 @@ .px-4 { padding-inline: calc(var(--spacing) * 4); } - .px-6 { - padding-inline: calc(var(--spacing) * 6); - } .py-1 { padding-block: calc(var(--spacing) * 1); } .py-2 { padding-block: calc(var(--spacing) * 2); } - .py-4 { - padding-block: calc(var(--spacing) * 4); + .py-8 { + padding-block: calc(var(--spacing) * 8); } - .pb-2 { - padding-bottom: calc(var(--spacing) * 2); + .py-16 { + padding-block: calc(var(--spacing) * 16); + } + .pb-16 { + padding-bottom: calc(var(--spacing) * 16); } .pl-6 { padding-left: calc(var(--spacing) * 6); @@ -584,6 +648,14 @@ font-size: var(--text-2xl); line-height: var(--tw-leading, var(--text-2xl--line-height)); } + .text-3xl { + font-size: var(--text-3xl); + line-height: var(--tw-leading, var(--text-3xl--line-height)); + } + .text-5xl { + font-size: var(--text-5xl); + line-height: var(--tw-leading, var(--text-5xl--line-height)); + } .text-base { font-size: var(--text-base); line-height: var(--tw-leading, var(--text-base--line-height)); @@ -620,6 +692,10 @@ --tw-font-weight: var(--font-weight-semibold); font-weight: var(--font-weight-semibold); } + .tracking-wide { + --tw-tracking: var(--tracking-wide); + letter-spacing: var(--tracking-wide); + } .break-words { overflow-wrap: break-word; } @@ -629,15 +705,12 @@ .whitespace-pre-wrap { white-space: pre-wrap; } + .text-\[\#e0e7ff\] { + color: #e0e7ff; + } .text-blue-400 { color: var(--color-blue-400); } - .text-gray-100 { - color: var(--color-gray-100); - } - .text-gray-200 { - color: var(--color-gray-200); - } .text-gray-300 { color: var(--color-gray-300); } @@ -647,28 +720,73 @@ .text-red-500 { color: var(--color-red-500); } + .text-teal-400 { + color: var(--color-teal-400); + } + .text-transparent { + color: transparent; + } .text-white { color: var(--color-white); } + .underline { + text-decoration-line: underline; + } .opacity-50 { opacity: 50%; } - .shadow-lg { - --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + .opacity-90 { + opacity: 90%; + } + .shadow-md { + --tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); } .filter { 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,); } + .backdrop-blur-\[12px\] { + --tw-backdrop-blur: blur(12px); + -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + } + .backdrop-blur-xl { + --tw-backdrop-blur: blur(var(--blur-xl)); + -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + } + .backdrop-filter { + -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + } .transition { transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events; transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); transition-duration: var(--tw-duration, var(--default-transition-duration)); } + .transition-all { + transition-property: all; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + .transition-colors { + transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + .transition-shadow { + transition-property: box-shadow; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } .duration-200 { --tw-duration: 200ms; transition-duration: 200ms; } + .duration-300 { + --tw-duration: 300ms; + transition-duration: 300ms; + } .ease-in-out { --tw-ease: var(--ease-in-out); transition-timing-function: var(--ease-in-out); @@ -722,17 +840,34 @@ } } } - .hover\:bg-yellow-700 { + .hover\:bg-gradient-to-r { &:hover { @media (hover: hover) { - background-color: var(--color-yellow-700); + --tw-gradient-position: to right in oklab; + background-image: linear-gradient(var(--tw-gradient-stops)); } } } - .hover\:text-blue-500 { + .hover\:from-blue-500 { &:hover { @media (hover: hover) { - color: var(--color-blue-500); + --tw-gradient-from: var(--color-blue-500); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + } + } + .hover\:to-teal-400 { + &:hover { + @media (hover: hover) { + --tw-gradient-to: var(--color-teal-400); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + } + } + .hover\:text-blue-400 { + &:hover { + @media (hover: hover) { + color: var(--color-blue-400); } } } @@ -743,13 +878,6 @@ } } } - .hover\:text-white { - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } - } .hover\:underline { &:hover { @media (hover: hover) { @@ -757,19 +885,38 @@ } } } - .sm\:w-\[90\%\] { - @media (width >= 40rem) { - width: 90%; + .hover\:shadow-lg { + &:hover { + @media (hover: hover) { + --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } } } - .sm\:p-4 { - @media (width >= 40rem) { - padding: calc(var(--spacing) * 4); + .focus\:outline-none { + &:focus { + --tw-outline-style: none; + outline-style: none; } } - .md\:w-\[85\%\] { + .sm\:px-6 { + @media (width >= 40rem) { + padding-inline: calc(var(--spacing) * 6); + } + } + .md\:mt-0 { @media (width >= 48rem) { - width: 85%; + margin-top: calc(var(--spacing) * 0); + } + } + .md\:flex { + @media (width >= 48rem) { + display: flex; + } + } + .md\:hidden { + @media (width >= 48rem) { + display: none; } } .md\:grid-cols-2 { @@ -777,274 +924,114 @@ grid-template-columns: repeat(2, minmax(0, 1fr)); } } - .md\:grid-cols-3 { - @media (width >= 48rem) { - grid-template-columns: repeat(3, minmax(0, 1fr)); - } - } - .lg\:w-\[80\%\] { + .lg\:px-8 { @media (width >= 64rem) { - width: 80%; + padding-inline: calc(var(--spacing) * 8); } } } +@font-face { + font-family: 'Minecraft'; + src: url('../font/MinecraftRegular-Bmg3.otf') format('opentype'); + font-weight: normal; + font-style: normal; + font-display: swap; +} @layer base { html { height: 100%; + margin: 0; + padding: 0; + box-sizing: border-box; + overflow-x: hidden; + } + *, *:before, *:after { + box-sizing: inherit; } body { display: flex; min-height: 100%; flex-direction: column; + background-color: var(--color-gray-900); + color: var(--color-white); + font-family: 'Roboto', 'Verdana', sans-serif; + overflow-x: hidden; } h1, h2, h3, h4, h5, h6 { - font-family: 'Minecraft', sans-serif; + font-family: Minecraft; + color: var(--color-white); + letter-spacing: 0.5px; + } + .xterm { + background-color: #111426 !important; } #app { - display: flex; - flex: 1; - flex-direction: column; - } - main { flex-grow: 1; } + main { + width: 100%; + @media (width >= 40rem) { + max-width: 40rem; + } + @media (width >= 48rem) { + max-width: 48rem; + } + @media (width >= 64rem) { + max-width: 64rem; + } + @media (width >= 80rem) { + max-width: 80rem; + } + @media (width >= 96rem) { + max-width: 96rem; + } + margin-inline: auto; + flex-grow: 1; + padding-inline: calc(var(--spacing) * 4); + padding-block: calc(var(--spacing) * 6); + @media (width >= 40rem) { + padding-inline: calc(var(--spacing) * 6); + } + @media (width >= 64rem) { + padding-inline: calc(var(--spacing) * 8); + } + } footer { - flex-shrink: 0; + background-color: var(--color-gray-800); + padding-block: calc(var(--spacing) * 4); + text-align: center; + } + canvas { + height: auto; + width: 100%; + max-width: 150px; + aspect-ratio: 1/1; + } + ::-webkit-scrollbar { + width: 8px; + } + ::-webkit-scrollbar-track { + background-color: var(--color-gray-800); + } + ::-webkit-scrollbar-thumb { + border-radius: 0.25rem; + background-color: var(--color-blue-600); + } + ::-webkit-scrollbar-thumb:hover { + background-color: var(--color-blue-700); } } @layer components { - .spinner { - display: inline-block; - height: calc(var(--spacing) * 6); - width: calc(var(--spacing) * 6); - animation: var(--animate-spin); - border-radius: calc(infinity * 1px); - border-style: var(--tw-border-style); - border-width: 4px; - border-color: var(--color-gray-700); - border-top-color: var(--color-white); - } - @keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } - } - #notificationContainer { - position: fixed; - right: calc(var(--spacing) * 5); - bottom: calc(var(--spacing) * 5); - z-index: 1000; - display: flex; - flex-direction: column-reverse; - gap: calc(var(--spacing) * 2); - } - .notification { - display: flex; - align-items: center; - gap: calc(var(--spacing) * 3); + .section-bg { + margin-bottom: calc(var(--spacing) * 6); + width: 100%; + max-width: 100%; border-radius: var(--radius-lg); background-color: var(--color-gray-800); - padding: calc(var(--spacing) * 4); - color: var(--color-white); + padding: calc(var(--spacing) * 6); --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - transition-property: opacity; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - --tw-duration: 300ms; - transition-duration: 300ms; - } - .notification.success { - background-color: var(--color-green-700); - } - .notification.error { - background-color: var(--color-red-700); - } - #dockerLogsTerminal { - max-height: calc(var(--spacing) * 48); - width: 100%; - border-radius: var(--radius-lg); - background-color: var(--color-gray-800); - padding: calc(var(--spacing) * 4); - } - .xterm .xterm-viewport { - overflow-y: auto; - scrollbar-width: thin; - scrollbar-color: #4B5563 #1F2937; - } - .xterm .xterm-viewport::-webkit-scrollbar { - width: calc(var(--spacing) * 2); - } - .xterm .xterm-viewport::-webkit-scrollbar-track { - background-color: var(--color-gray-800); - } - .xterm .xterm-viewport::-webkit-scrollbar-thumb { - border-radius: 0.25rem; - background-color: var(--color-gray-600); - } - .xterm .xterm-viewport::-webkit-scrollbar-thumb:hover { - background-color: var(--color-gray-500); - } - .xterm .xterm-screen { - width: 100%; - } - .control-btn { - min-width: 80px; - padding-inline: calc(var(--spacing) * 4); - padding-block: calc(var(--spacing) * 2); - text-align: center; - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - --tw-font-weight: var(--font-weight-medium); - font-weight: var(--font-weight-medium); - --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); - box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - transition-property: all; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - --tw-duration: 200ms; - transition-duration: 200ms; - } - .control-btn:hover:not(.disabled-btn) { - --tw-translate-y: -1px; - translate: var(--tw-translate-x) var(--tw-translate-y); - } - .control-btn:active:not(.disabled-btn) { - --tw-translate-y: calc(var(--spacing) * 0); - translate: var(--tw-translate-x) var(--tw-translate-y); - } - .tell-player { - border-radius: 0.25rem; - background-color: var(--color-blue-600); - padding-inline: calc(var(--spacing) * 2); - padding-block: calc(var(--spacing) * 1); - font-family: Minecraft; - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - transition-property: all; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - --tw-duration: 200ms; - transition-duration: 200ms; - &:hover { - @media (hover: hover) { - background-color: var(--color-blue-700); - } - } - } - .give-player { - border-radius: 0.25rem; - background-color: var(--color-green-600); - padding-inline: calc(var(--spacing) * 2); - padding-block: calc(var(--spacing) * 1); - font-family: Minecraft; - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - transition-property: all; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - --tw-duration: 200ms; - transition-duration: 200ms; - &:hover { - @media (hover: hover) { - background-color: var(--color-green-700); - } - } - } - .op-player, .deop-player { - border-radius: 0.25rem; - background-color: var(--color-purple-600); - padding-inline: calc(var(--spacing) * 2); - padding-block: calc(var(--spacing) * 1); - font-family: Minecraft; - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - transition-property: all; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - --tw-duration: 200ms; - transition-duration: 200ms; - &:hover { - @media (hover: hover) { - background-color: var(--color-purple-700); - } - } - } - .kick-player, .ban-player { - border-radius: 0.25rem; - background-color: var(--color-red-600); - padding-inline: calc(var(--spacing) * 2); - padding-block: calc(var(--spacing) * 1); - font-family: Minecraft; - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - transition-property: all; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - --tw-duration: 200ms; - transition-duration: 200ms; - &:hover { - @media (hover: hover) { - background-color: var(--color-red-700); - } - } - } - .teleport-player { - border-radius: 0.25rem; - background-color: var(--color-cyan-600); - padding-inline: calc(var(--spacing) * 2); - padding-block: calc(var(--spacing) * 1); - font-family: Minecraft; - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - transition-property: all; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - --tw-duration: 200ms; - transition-duration: 200ms; - &:hover { - @media (hover: hover) { - background-color: var(--color-cyan-700); - } - } - } - .teleport-player:hover:not(.disabled-btn) { - --tw-translate-y: -1px; - translate: var(--tw-translate-x) var(--tw-translate-y); - } - .teleport-player:active:not(.disabled-btn) { - --tw-translate-y: calc(var(--spacing) * 0); - translate: var(--tw-translate-x) var(--tw-translate-y); - } - .effect-player { - border-radius: 0.25rem; - background-color: var(--color-teal-600); - padding-inline: calc(var(--spacing) * 2); - padding-block: calc(var(--spacing) * 1); - font-family: Minecraft; - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - transition-property: all; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - --tw-duration: 200ms; - transition-duration: 200ms; - &:hover { - @media (hover: hover) { - background-color: var(--color-teal-700); - } - } - } - .effect-player:hover:not(.disabled-btn) { - --tw-translate-y: -1px; - translate: var(--tw-translate-x) var(--tw-translate-y); - } - .effect-player:active:not(.disabled-btn) { - --tw-translate-y: calc(var(--spacing) * 0); - translate: var(--tw-translate-x) var(--tw-translate-y); + overflow-x: hidden; } .modal { position: fixed; @@ -1070,6 +1057,11 @@ scrollbar-width: thin; scrollbar-color: #4B5563 #1F2937; } + @media (max-width: 640px) { + .holesail-output-mobile-hidden { + display: none; + } + } .modal-content::-webkit-scrollbar { width: calc(var(--spacing) * 2); } @@ -1095,58 +1087,145 @@ line-height: var(--tw-leading, var(--text-xl--line-height)); color: var(--color-white); } - .disabled-btn { - pointer-events: none; - cursor: not-allowed; - opacity: 50%; + .control-btn { + border-radius: 0.25rem; + padding-inline: calc(var(--spacing) * 4); + padding-block: calc(var(--spacing) * 2); + --tw-font-weight: var(--font-weight-medium); + font-weight: var(--font-weight-medium); + color: var(--color-white); + transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + --tw-duration: 200ms; + transition-duration: 200ms; } - .disabled-btn:hover { - cursor: not-allowed; + .spinner { + display: inline-block; + height: calc(var(--spacing) * 6); + width: calc(var(--spacing) * 6); + animation: var(--animate-spin); + border-radius: calc(infinity * 1px); + border-style: var(--tw-border-style); + border-width: 4px; + border-color: var(--color-gray-700); + border-top-color: var(--color-blue-600); } - #searchContainer { - margin-bottom: calc(var(--spacing) * 4); - display: block; + @keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } } - #propertiesSearch { - display: block; + #notificationContainer { + position: fixed; + right: calc(var(--spacing) * 4); + bottom: calc(var(--spacing) * 4); + z-index: 1000; + display: flex; + flex-direction: column-reverse; + gap: calc(var(--spacing) * 2); + } + .notification { + display: flex; + align-items: center; + gap: calc(var(--spacing) * 2); + border-radius: var(--radius-lg); + background-color: var(--color-gray-800); + padding: calc(var(--spacing) * 3); + color: var(--color-white); + --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + max-width: 90%; + font-size: 0.875rem; + } + .notification.success { + background-color: var(--color-green-600); + } + .notification.error { + background-color: var(--color-red-600); + } + #dockerLogsTerminal { + box-sizing: border-box; + width: 100%; + max-width: 100%; + border-radius: var(--radius-lg); + background-color: var(--color-gray-900); + padding: calc(var(--spacing) * 4); + height: 250px; + overflow-y: hidden; + overflow-x: hidden; + } + .xterm .xterm-viewport { + overflow-y: auto; + height: 250px; + scrollbar-width: thin; + scrollbar-color: #3b82f6 #1f2937; + } + .xterm .xterm-viewport::-webkit-scrollbar { + width: 8px; + } + .xterm .xterm-viewport::-webkit-scrollbar-track { + background-color: var(--color-gray-800); + } + .xterm .xterm-viewport::-webkit-scrollbar-thumb { + border-radius: 0.25rem; + background-color: var(--color-blue-600); + } + .xterm .xterm-viewport::-webkit-scrollbar-thumb:hover { + background-color: var(--color-blue-700); + } + .xterm .xterm-screen { + width: 100%; + } + .item-entry { + margin-bottom: calc(var(--spacing) * 2); + display: flex; + width: 100%; + flex-wrap: wrap; + align-items: center; + gap: calc(var(--spacing) * 2); + } + .item-entry input { width: 100%; border-radius: 0.25rem; background-color: var(--color-gray-700); - padding-inline: calc(var(--spacing) * 4); - padding-block: calc(var(--spacing) * 2); + padding: calc(var(--spacing) * 2); color: var(--color-white); + @media (width >= 40rem) { + width: auto; + } } - #propertiesList { - :where(& > :not(:last-child)) { - --tw-space-y-reverse: 0; - margin-block-start: calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse)); - margin-block-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse))); + .item-entry .item-amount { + width: calc(var(--spacing) * 16); + @media (width >= 40rem) { + width: calc(var(--spacing) * 12); } } [role="switch"] { position: relative; - z-index: 10; display: inline-block; height: calc(var(--spacing) * 6); width: calc(var(--spacing) * 10); cursor: pointer; } - [role="switch"] > div:first-child { + [role="switch"]>div:first-child { + display: block; height: 100%; width: 100%; border-radius: calc(infinity * 1px); + background-color: var(--color-gray-700); transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to; transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); transition-duration: var(--tw-duration, var(--default-transition-duration)); --tw-duration: 200ms; transition-duration: 200ms; - --tw-ease: var(--ease-in-out); - transition-timing-function: var(--ease-in-out); } - [role="switch"] > div:last-child { + [role="switch"]>div:last-child { position: absolute; top: calc(var(--spacing) * 1); - z-index: 11; height: calc(var(--spacing) * 4); width: calc(var(--spacing) * 4); border-radius: calc(infinity * 1px); @@ -1156,52 +1235,440 @@ transition-duration: var(--tw-duration, var(--default-transition-duration)); --tw-duration: 200ms; transition-duration: 200ms; - --tw-ease: var(--ease-in-out); - transition-timing-function: var(--ease-in-out); } - [role="switch"][aria-checked="true"] > div:first-child { - background-color: var(--color-green-600); + [role="switch"][aria-checked="true"]>div:first-child { + background-color: var(--color-blue-600); } - [role="switch"][aria-checked="false"] > div:first-child { - background-color: var(--color-gray-600); + [role="switch"][aria-checked="true"]>div:last-child { + left: calc(var(--spacing) * 5); } - [role="switch"][aria-checked="true"] > div:last-child { - left: calc(var(--spacing) * 6); - } - [role="switch"][aria-checked="false"] > div:last-child { + [role="switch"][aria-checked="false"]>div:last-child { left: calc(var(--spacing) * 1); } + #sftpIframe { + width: 100%; + border-radius: 0.25rem; + height: 50vh; + min-height: 300px; + } + #propertiesSearch { + width: 100%; + border-radius: 0.25rem; + background-color: var(--color-gray-700); + padding: calc(var(--spacing) * 2); + color: var(--color-white); + } + #propertiesList { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse))); + } + } + .nav-btn { + border-radius: 0.25rem; + background-color: var(--color-blue-600); + padding-inline: calc(var(--spacing) * 3); + padding-block: calc(var(--spacing) * 1); + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + --tw-font-weight: var(--font-weight-medium); + font-weight: var(--font-weight-medium); + color: var(--color-white); + transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + --tw-duration: 200ms; + transition-duration: 200ms; + } + .nav-btn2 { + border-radius: 0.25rem; + background-color: var(--color-blue-600); + padding-inline: calc(var(--spacing) * 3); + padding-block: calc(var(--spacing) * 1); + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + --tw-font-weight: var(--font-weight-medium); + font-weight: var(--font-weight-medium); + color: var(--color-white); + transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + --tw-duration: 200ms; + transition-duration: 200ms; + } + .nav-btn:hover:not(.disabled) { + background-color: var(--color-blue-700); + } + .nav-btn.current { + border-style: var(--tw-border-style); + border-width: 2px; + border-color: var(--color-blue-400); + background-color: var(--color-blue-800); + --tw-font-weight: var(--font-weight-bold); + font-weight: var(--font-weight-bold); + } + .nav-btn.disabled { + cursor: not-allowed; + background-color: var(--color-gray-600); + opacity: 50%; + } + .pagination-container { + margin-top: calc(var(--spacing) * 4); + display: flex; + align-items: center; + justify-content: center; + gap: calc(var(--spacing) * 1); + } + .pagination-container .nav-btn { + border-radius: var(--radius-sm); + padding-inline: calc(var(--spacing) * 2); + padding-block: calc(var(--spacing) * 0.5); + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } + .pagination-container .nav-btn.current { + border-style: var(--tw-border-style); + border-width: 1px; + border-color: var(--color-blue-400); + background-color: var(--color-blue-800); + --tw-font-weight: var(--font-weight-bold); + font-weight: var(--font-weight-bold); + } + .pagination-container .nav-btn.disabled { + cursor: not-allowed; + background-color: var(--color-gray-600); + opacity: 50%; + } } -@layer utilities; -@media (max-width: 640px) { - .bg-gray-800.p-6.rounded-lg.shadow-lg .grid { +.hamburger { + position: fixed; + top: calc(var(--spacing) * 4); + right: calc(var(--spacing) * 4); + z-index: 99999; + display: flex; + height: calc(var(--spacing) * 10); + width: calc(var(--spacing) * 10); + flex-direction: column; + align-items: center; + justify-content: center; + @media (width >= 48rem) { + display: none; + } +} +.hamburger .bar { + margin-bottom: calc(var(--spacing) * 1.5); + height: calc(var(--spacing) * 0.5); + width: calc(var(--spacing) * 6); + background-color: var(--color-blue-400); + transition-property: all; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + --tw-duration: 300ms; + transition-duration: 300ms; +} +.hamburger.active .bar:nth-child(1) { + --tw-translate-y: calc(var(--spacing) * 2); + translate: var(--tw-translate-x) var(--tw-translate-y); + rotate: 45deg; +} +.hamburger.active .bar:nth-child(2) { + opacity: 0%; +} +.hamburger.active .bar:nth-child(3) { + --tw-translate-y: calc(var(--spacing) * -2); + translate: var(--tw-translate-x) var(--tw-translate-y); + rotate: calc(45deg * -1); +} +.mobile-nav-container { + position: fixed; + inset: calc(var(--spacing) * 0); + z-index: 99998; + display: none; + flex-direction: column; + align-items: center; + justify-content: center; + background-color: var(--color-gray-900); + padding: calc(var(--spacing) * 4); + transition: opacity 0.3s ease, visibility 0.3s ease; +} +.mobile-nav-container.active { + visibility: visible; + display: flex; + opacity: 100%; +} +.mobile-nav-container ul li a, .mobile-nav-container ul li button { + margin-bottom: calc(var(--spacing) * 4); + display: block; + border-radius: 0.25rem; + background-color: var(--color-blue-600); + padding-inline: calc(var(--spacing) * 4); + padding-block: calc(var(--spacing) * 2); + font-size: var(--text-lg); + line-height: var(--tw-leading, var(--text-lg--line-height)); + color: var(--color-white); + &:hover { + @media (hover: hover) { + background-color: var(--color-blue-700); + } + } +} +.control-btn { + border-radius: 0.25rem; + padding-inline: calc(var(--spacing) * 4); + padding-block: calc(var(--spacing) * 2); + --tw-font-weight: var(--font-weight-medium); + font-weight: var(--font-weight-medium); + color: var(--color-white); + transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + --tw-duration: 200ms; + transition-duration: 200ms; +} +#startBtn { + background-color: var(--color-green-600); + &:hover { + @media (hover: hover) { + background-color: var(--color-green-700); + } + } +} +#stopBtn { + background-color: var(--color-red-600); + &:hover { + @media (hover: hover) { + background-color: var(--color-red-700); + } + } +} +#restartBtn { + background-color: var(--color-yellow-500); + color: var(--color-black); + &:hover { + @media (hover: hover) { + background-color: var(--color-yellow-600); + } + } +} +.disabled-btn { + pointer-events: none; + cursor: not-allowed; + opacity: 50%; +} +.disabled-btn:hover { + cursor: not-allowed; +} +.copy-key-btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.25rem; + background-color: #374151; + border-radius: 0.25rem; + color: #ffffff; + transition: background-color 0.2s; +} +.copy-key-btn:hover { + background-color: #4b5563; +} +.copy-key-btn svg { + width: 1rem; + height: 1rem; +} +@media (max-width: 768px) { + .section-bg { + padding: calc(var(--spacing) * 4); + } + .modal-content { + max-width: 95%; + padding: calc(var(--spacing) * 4); + } + .section-bg .grid { grid-template-columns: repeat(1, minmax(0, 1fr)); } - .bg-gray-800.p-6.rounded-lg.shadow-lg p { - display: flex; + .section-bg .flex { flex-direction: column; gap: calc(var(--spacing) * 2); - word-break: break-all; } - .bg-gray-800.p-6.rounded-lg.shadow-lg a, .bg-gray-800.p-6.rounded-lg.shadow-lg span { - overflow-wrap: break-word; - white-space: normal; + canvas { + max-width: 120px; } - .bg-gray-800.p-6.rounded-lg.shadow-lg button { - margin-top: calc(var(--spacing) * 2); + .section-bg input, .section-bg textarea, .section-bg select { + padding: calc(var(--spacing) * 2); + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + } + .section-bg pre { + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + } + #sftpIframe { + height: 40vh; + min-height: 300px; + } + #consoleOutput { + height: calc(var(--spacing) * 32); + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + } + .notification { + max-width: 80%; + padding: calc(var(--spacing) * 2); + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + } + h1 { + font-size: var(--text-3xl); + line-height: var(--tw-leading, var(--text-3xl--line-height)); + } + h2 { + font-size: var(--text-xl); + line-height: var(--tw-leading, var(--text-xl--line-height)); + } + h3 { + font-size: var(--text-base); + line-height: var(--tw-leading, var(--text-base--line-height)); + } + p, span, a { + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + } + .nav-btn { + display: none; + } + .hamburger { + display: flex; + } + .control-btn { + padding-inline: calc(var(--spacing) * 3); + padding-block: calc(var(--spacing) * 1); + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + } + .item-entry { + flex-direction: column; + gap: calc(var(--spacing) * 1); + } + .item-entry .item-amount { width: 100%; } - .tell-player, .give-player, .teleport-player, .effect-player, .op-player, .deop-player, .kick-player, .ban-player { - margin-top: calc(var(--spacing) * 1); - width: 100%; - text-align: center; +} +@media (max-width: 640px) { + .section-bg { + padding: calc(var(--spacing) * 3); + } + .modal-content { + max-width: 95%; + padding: calc(var(--spacing) * 3); + } + canvas { + max-width: 100px; + } + .section-bg input, .section-bg textarea, .section-bg select { + padding: calc(var(--spacing) * 1); + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } + .section-bg pre { + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } + #sftpIframe { + height: 35vh; + min-height: 250px; + } + #consoleOutput { + height: calc(var(--spacing) * 28); + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } + .notification { + max-width: 90%; + padding: calc(var(--spacing) * 1); + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } + h1 { + font-size: var(--text-2xl); + line-height: var(--tw-leading, var(--text-2xl--line-height)); + } + h2 { + font-size: var(--text-lg); + line-height: var(--tw-leading, var(--text-lg--line-height)); + } + h3 { + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + } + p, span, a { + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } + .control-btn { + padding-inline: calc(var(--spacing) * 2); + padding-block: calc(var(--spacing) * 1); + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); } } -.bg-gray-800.p-6.rounded-lg.shadow-lg .grid { - overflow-x: hidden; -} -.bg-gray-800.p-6.rounded-lg.shadow-lg p { - max-width: 100%; +@media (max-width: 480px) { + .section-bg { + padding: calc(var(--spacing) * 2); + } + .modal-content { + max-width: 98%; + padding: calc(var(--spacing) * 2); + } + canvas { + max-width: 80px; + } + .section-bg input, .section-bg textarea, .section-bg select { + padding: calc(var(--spacing) * 1); + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } + .section-bg pre { + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } + #sftpIframe { + height: 30vh; + min-height: 200px; + } + #consoleOutput { + height: calc(var(--spacing) * 24); + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } + .notification { + max-width: 95%; + padding: calc(var(--spacing) * 1); + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } + h1 { + font-size: var(--text-xl); + line-height: var(--tw-leading, var(--text-xl--line-height)); + } + h2 { + font-size: var(--text-base); + line-height: var(--tw-leading, var(--text-base--line-height)); + } + h3 { + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } + p, span, a { + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } + .control-btn { + padding-inline: calc(var(--spacing) * 2); + padding-block: calc(var(--spacing) * 1); + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } } @property --tw-rotate-x { syntax: "*"; @@ -1238,6 +1705,48 @@ inherits: false; initial-value: solid; } +@property --tw-gradient-position { + syntax: "*"; + inherits: false; +} +@property --tw-gradient-from { + syntax: ""; + inherits: false; + initial-value: #0000; +} +@property --tw-gradient-via { + syntax: ""; + inherits: false; + initial-value: #0000; +} +@property --tw-gradient-to { + syntax: ""; + inherits: false; + initial-value: #0000; +} +@property --tw-gradient-stops { + syntax: "*"; + inherits: false; +} +@property --tw-gradient-via-stops { + syntax: "*"; + inherits: false; +} +@property --tw-gradient-from-position { + syntax: ""; + inherits: false; + initial-value: 0%; +} +@property --tw-gradient-via-position { + syntax: ""; + inherits: false; + initial-value: 50%; +} +@property --tw-gradient-to-position { + syntax: ""; + inherits: false; + initial-value: 100%; +} @property --tw-leading { syntax: "*"; inherits: false; @@ -1246,6 +1755,10 @@ syntax: "*"; inherits: false; } +@property --tw-tracking { + syntax: "*"; + inherits: false; +} @property --tw-shadow { syntax: "*"; inherits: false; @@ -1364,6 +1877,42 @@ syntax: "*"; inherits: false; } +@property --tw-backdrop-blur { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-brightness { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-contrast { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-grayscale { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-hue-rotate { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-invert { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-opacity { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-saturate { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-sepia { + syntax: "*"; + inherits: false; +} @property --tw-duration { syntax: "*"; inherits: false; @@ -1403,8 +1952,18 @@ --tw-space-y-reverse: 0; --tw-space-x-reverse: 0; --tw-border-style: solid; + --tw-gradient-position: initial; + --tw-gradient-from: #0000; + --tw-gradient-via: #0000; + --tw-gradient-to: #0000; + --tw-gradient-stops: initial; + --tw-gradient-via-stops: initial; + --tw-gradient-from-position: 0%; + --tw-gradient-via-position: 50%; + --tw-gradient-to-position: 100%; --tw-leading: initial; --tw-font-weight: initial; + --tw-tracking: initial; --tw-shadow: 0 0 #0000; --tw-shadow-color: initial; --tw-shadow-alpha: 100%; @@ -1432,6 +1991,15 @@ --tw-drop-shadow-color: initial; --tw-drop-shadow-alpha: 100%; --tw-drop-shadow-size: initial; + --tw-backdrop-blur: initial; + --tw-backdrop-brightness: initial; + --tw-backdrop-contrast: initial; + --tw-backdrop-grayscale: initial; + --tw-backdrop-hue-rotate: initial; + --tw-backdrop-invert: initial; + --tw-backdrop-opacity: initial; + --tw-backdrop-saturate: initial; + --tw-backdrop-sepia: initial; --tw-duration: initial; --tw-ease: initial; --tw-translate-x: 0; diff --git a/public/css/styles.css b/public/css/styles.css deleted file mode 100644 index 54b6f52..0000000 --- a/public/css/styles.css +++ /dev/null @@ -1,275 +0,0 @@ -@font-face { - font-family: 'Minecraft'; - src: url('../font/MinecraftRegular-Bmg3.otf') format('opentype'); - font-weight: normal; - font-style: normal; - font-display: swap; - } - @media (max-width: 640px) { - .holesail-output-mobile-hidden { - display: none; - } - } - - @import "tailwindcss"; - - @layer base { - /* Sticky footer base styles */ - html { - @apply h-full; - } - - body { - @apply min-h-full flex flex-col; - } - - h1, h2, h3, h4, h5, h6 { - font-family: 'Minecraft', sans-serif; - } - - #app { - @apply flex-1 flex flex-col; - } - - main { - @apply flex-grow; - } - - footer { - @apply flex-shrink-0; - } - } - - @layer components { - .spinner { - @apply border-4 border-gray-700 border-t-white rounded-full w-6 h-6 animate-spin inline-block; - } - - @keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } - } - - #notificationContainer { - @apply fixed bottom-5 right-5 z-[1000] flex flex-col-reverse gap-2; - } - - .notification { - @apply bg-gray-800 text-white p-4 rounded-lg flex items-center gap-3 shadow-lg transition-opacity duration-300; - } - - .notification.success { - @apply bg-green-700; - } - - .notification.error { - @apply bg-red-700; - } - - #dockerLogsTerminal { - @apply bg-gray-800 p-4 rounded-lg max-h-48 w-full; - } - - .xterm .xterm-viewport { - @apply overflow-y-auto; - scrollbar-width: thin; - scrollbar-color: #4B5563 #1F2937; - } - - .xterm .xterm-viewport::-webkit-scrollbar { - @apply w-2; - } - - .xterm .xterm-viewport::-webkit-scrollbar-track { - @apply bg-gray-800; - } - - .xterm .xterm-viewport::-webkit-scrollbar-thumb { - @apply bg-gray-600 rounded; - } - - .xterm .xterm-viewport::-webkit-scrollbar-thumb:hover { - @apply bg-gray-500; - } - - .xterm .xterm-screen { - @apply w-full; - } - - .control-btn { - @apply px-4 py-2 text-sm font-medium transition-all duration-200 min-w-[80px] text-center shadow-sm; - } - - .control-btn:hover:not(.disabled-btn) { - @apply -translate-y-px; - } - - .control-btn:active:not(.disabled-btn) { - @apply translate-y-0; - } - - /* Player button styles */ - .tell-player { - @apply bg-blue-600 hover:bg-blue-700 px-2 py-1 rounded text-sm font-[Minecraft] transition-all duration-200; - } - - .give-player { - @apply bg-green-600 hover:bg-green-700 px-2 py-1 rounded text-sm font-[Minecraft] transition-all duration-200; - } - - .op-player, .deop-player { - @apply bg-purple-600 hover:bg-purple-700 px-2 py-1 rounded text-sm font-[Minecraft] transition-all duration-200; - } - - .kick-player, .ban-player { - @apply bg-red-600 hover:bg-red-700 px-2 py-1 rounded text-sm font-[Minecraft] transition-all duration-200; - } - - .teleport-player { - @apply bg-cyan-600 hover:bg-cyan-700 px-2 py-1 rounded text-sm font-[Minecraft] transition-all duration-200; - } - - .teleport-player:hover:not(.disabled-btn) { - @apply -translate-y-px; - } - - .teleport-player:active:not(.disabled-btn) { - @apply translate-y-0; - } - - .effect-player { - @apply bg-teal-600 hover:bg-teal-700 px-2 py-1 rounded text-sm font-[Minecraft] transition-all duration-200; - } - - .effect-player:hover:not(.disabled-btn) { - @apply -translate-y-px; - } - - .effect-player:active:not(.disabled-btn) { - @apply translate-y-0; - } - - .modal { - @apply fixed inset-0 bg-black/75 flex items-center justify-center z-[1000]; - } - - .modal-content { - @apply bg-gray-800 p-6 rounded-lg w-full max-w-xl relative max-h-[80vh] overflow-y-auto; - scrollbar-width: thin; - scrollbar-color: #4B5563 #1F2937; - } - - .modal-content::-webkit-scrollbar { - @apply w-2; - } - - .modal-content::-webkit-scrollbar-track { - @apply bg-gray-800; - } - - .modal-content::-webkit-scrollbar-thumb { - @apply bg-gray-600 rounded; - } - - .modal-content::-webkit-scrollbar-thumb:hover { - @apply bg-gray-500; - } - - .modal-close { - @apply absolute top-2 right-2 bg-transparent border-none text-white text-xl cursor-pointer; - } - - .disabled-btn { - @apply opacity-50 cursor-not-allowed pointer-events-none; - } - - .disabled-btn:hover { - @apply cursor-not-allowed; - } - - /* Search box and properties fields */ - #searchContainer { - @apply mb-4 block; - } - - #propertiesSearch { - @apply bg-gray-700 px-4 py-2 rounded text-white w-full block; - } - - #propertiesList { - @apply space-y-2; - } - - /* Toggle switch styles */ - [role="switch"] { - @apply inline-block relative w-10 h-6 cursor-pointer z-10; - } - - [role="switch"] > div:first-child { - @apply w-full h-full rounded-full transition-colors duration-200 ease-in-out; - } - - [role="switch"] > div:last-child { - @apply absolute w-4 h-4 rounded-full bg-white top-1 transition-all duration-200 ease-in-out z-[11]; - } - - [role="switch"][aria-checked="true"] > div:first-child { - @apply bg-green-600; - } - - [role="switch"][aria-checked="false"] > div:first-child { - @apply bg-gray-600; - } - - [role="switch"][aria-checked="true"] > div:last-child { - @apply left-6; - } - - [role="switch"][aria-checked="false"] > div:last-child { - @apply left-1; - } - } - - @layer utilities { - /* Custom utilities */ - } - - /* Media queries */ - @media (max-width: 640px) { - .bg-gray-800.p-6.rounded-lg.shadow-lg .grid { - @apply grid-cols-1; - } - - .bg-gray-800.p-6.rounded-lg.shadow-lg p { - @apply flex flex-col gap-2 break-all; - } - - .bg-gray-800.p-6.rounded-lg.shadow-lg a, - .bg-gray-800.p-6.rounded-lg.shadow-lg span { - @apply break-words whitespace-normal; - } - - .bg-gray-800.p-6.rounded-lg.shadow-lg button { - @apply w-full mt-2; - } - - .tell-player, - .give-player, - .teleport-player, - .effect-player, - .op-player, - .deop-player, - .kick-player, - .ban-player { - @apply w-full text-center mt-1; - } - } - - /* Additional styles */ - .bg-gray-800.p-6.rounded-lg.shadow-lg .grid { - @apply overflow-x-hidden; - } - - .bg-gray-800.p-6.rounded-lg.shadow-lg p { - @apply max-w-full; - } \ No newline at end of file diff --git a/public/index.html b/public/index.html index c1ad243..9d66cb0 100644 --- a/public/index.html +++ b/public/index.html @@ -2,471 +2,546 @@ - - - - My-MC Panel - - - - - - - - - - + + + + My-MC Panel + + + + + + + + + + + + + + - -
- - - -
- - - - - - - - - - - - - - -
- + - - - - - - - - - + + + diff --git a/public/js/app.js b/public/js/app.js index 6b36a89..3263d3a 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -28,6 +28,61 @@ document.addEventListener('DOMContentLoaded', () => { 'enable-status' ]; + const sections = document.querySelectorAll('.section-bg'); + const observer = new IntersectionObserver((entries) => { + entries.forEach((entry, index) => { + if (entry.isIntersecting) { + entry.target.style.transform = 'translateY(0)'; + entry.target.style.opacity = '1'; + entry.target.style.transitionDelay = `${index * 0.1}s`; + } + }); + }, { threshold: 0.1 }); + + + function throttle(fn, wait) { + let lastTime = 0; + return function (...args) { + const now = Date.now(); + if (now - lastTime >= wait) { + fn.apply(this, args); + lastTime = now; + } + }; + } + + // Hamburger Menu Toggle + const hamburger = document.querySelector('.hamburger'); + const mobileNav = document.querySelector('[data-mobile-nav]'); + const navLinks = mobileNav.querySelectorAll('a'); + + // Debounce function to prevent rapid clicks + function debounce(fn, wait) { + let timeout; + return function (...args) { + clearTimeout(timeout); + timeout = setTimeout(() => fn.apply(this, args), wait); + }; + } + + hamburger.addEventListener('click', debounce(() => { + mobileNav.classList.toggle('active'); + hamburger.classList.toggle('active'); + }, 100)); + + navLinks.forEach(link => { + link.addEventListener('click', () => { + mobileNav.classList.remove('active'); + hamburger.classList.remove('active'); + }); + }); + + document.addEventListener('click', (e) => { + if (!mobileNav.contains(e.target) && !hamburger.contains(e.target) && mobileNav.classList.contains('active')) { + mobileNav.classList.remove('active'); + hamburger.classList.remove('active'); + } + }); const elements = { loginPage: document.getElementById('loginPage'), loginApiKey: document.getElementById('loginApiKey'), @@ -321,7 +376,7 @@ document.addEventListener('DOMContentLoaded', () => { terminal.clear(); } else { terminal = new Terminal({ - rows: 8, + rows: 22, fontSize: 14, fontFamily: 'monospace', theme: { @@ -497,91 +552,178 @@ document.addEventListener('DOMContentLoaded', () => { } } - function toggleSections(status) { - const sections = document.querySelectorAll('.bg-gray-800.p-6.rounded-lg.shadow-lg.mb-6'); - const serverStatusSection = document.querySelector('.bg-gray-800.p-6.rounded-lg.shadow-lg.mb-6[data-section="server-status"]'); - const editPropertiesBtn = elements.editPropertiesBtn; - const updateModsBtn = elements.updateModsBtn; - const backupBtn = elements.backupBtn; - const sftpBtn = elements.sftpBtn; - const startBtn = document.getElementById('startBtn'); - const stopBtn = elements.stopBtn; - const restartBtn = elements.restartBtn; - const sftpBrowserSection = elements.sftpBrowserSection; - - if (startBtn) { - if (status.toLowerCase() === 'running') { - startBtn.disabled = true; - startBtn.classList.add('disabled-btn'); - } else { - startBtn.disabled = false; - startBtn.classList.remove('disabled-btn'); - } + function updateDockerUI(message) { + if (message.error) { + console.log('Docker error detected, setting status to Not Running'); + if (elements.serverStatus) elements.serverStatus.textContent = 'Not Running'; + toggleSections('Not Running'); + return; } - if (status.toLowerCase() !== 'running') { + const memoryPercent = parseFloat(message.data?.memory?.percent) || 0; + if (state.memoryPercent !== memoryPercent && elements.memoryPercent && memoryMeter) { + memoryMeter.data.datasets[0].data = [memoryPercent, 100 - memoryPercent]; + memoryMeter.update(); + elements.memoryPercent.textContent = `${memoryPercent.toFixed(1)}%`; + state.memoryPercent = memoryPercent; + } + + const cpuPercent = parseFloat(message.data?.cpu) || 0; + if (state.cpuPercent !== cpuPercent && elements.cpuPercent && cpuMeter) { + const scaledCpuPercent = Math.min((cpuPercent / 600) * 100, 100); + cpuMeter.data.datasets[0].data = [scaledCpuPercent, 100 - scaledCpuPercent]; + cpuMeter.update(); + elements.cpuPercent.textContent = `${cpuPercent.toFixed(1)}%`; + state.cpuPercent = cpuPercent; + } + + const status = message.data?.status || 'Unknown'; + if (elements.serverStatus) { + elements.serverStatus.textContent = status; + state.serverStatus = status; + toggleSections(status); + } +} + +function toggleSections(status) { + const sections = document.querySelectorAll('.section-bg'); + const serverStatusSection = document.querySelector('.section-bg[data-section="server-status"]'); + const editPropertiesBtn = elements.editPropertiesBtn; + const updateModsBtn = elements.updateModsBtn; + const sftpBtn = elements.sftpBtn; + const startBtn = document.getElementById('startBtn'); + const stopBtn = elements.stopBtn; + const restartBtn = elements.restartBtn; + const sftpBrowserSection = elements.sftpBrowserSection; + // Menu items in desktop and mobile nav + const refreshBtn = elements.refresh || document.getElementById('refresh'); + const mobileRefreshBtn = elements.mobileRefresh || document.getElementById('mobileRefresh'); + const backupBtn = elements.backupBtn; + const mobileBackupBtn = elements.mobileBackupBtn; + const logoutBtn = elements.logoutBtn || document.getElementById('logoutBtn'); + const mobileLogoutBtn = elements.mobileLogoutBtn || document.getElementById('mobileLogoutBtn'); + + if (startBtn) { + if (status.toLowerCase() === 'running') { + startBtn.disabled = true; + startBtn.classList.add('disabled-btn'); + } else { + startBtn.disabled = false; + startBtn.classList.remove('disabled-btn'); + } + } + + if (status.toLowerCase() !== 'running') { + // Hide all sections except Server Status sections.forEach(section => { - if (section !== serverStatusSection) { - section.classList.add('hidden'); - } + if (section !== serverStatusSection) { + section.classList.add('hidden'); + } }); + // Hide control buttons if (editPropertiesBtn) { - editPropertiesBtn.classList.add('hidden'); + editPropertiesBtn.classList.add('hidden'); + editPropertiesBtn.style.display = 'none'; } if (updateModsBtn) { - updateModsBtn.classList.add('hidden'); - } - if (backupBtn) { - backupBtn.classList.add('hidden'); + updateModsBtn.classList.add('hidden'); + updateModsBtn.style.display = 'none'; } if (sftpBtn) { - sftpBtn.classList.add('hidden'); + sftpBtn.classList.add('hidden'); } if (stopBtn) { - stopBtn.disabled = true; - stopBtn.classList.add('disabled-btn'); + stopBtn.disabled = true; + stopBtn.classList.add('disabled-btn'); } if (restartBtn) { - restartBtn.disabled = true; - restartBtn.classList.add('disabled-btn'); + restartBtn.disabled = true; + restartBtn.classList.add('disabled-btn'); } if (sftpBrowserSection) { - sftpBrowserSection.style.display = 'none'; + sftpBrowserSection.style.display = 'none'; + } + // Hide Refresh, Backup, and Logout buttons in desktop nav + if (refreshBtn) { + refreshBtn.classList.add('hidden'); + refreshBtn.style.display = 'none'; + } + if (backupBtn) { + backupBtn.classList.add('hidden'); + backupBtn.style.display = 'none'; + } + if (logoutBtn) { + logoutBtn.classList.add('hidden'); + logoutBtn.style.display = 'none'; + } + // Hide Refresh, Backup, and Logout menu items in mobile nav + if (mobileRefreshBtn && mobileRefreshBtn.parentElement) { + mobileRefreshBtn.parentElement.classList.add('hidden'); + } + if (mobileBackupBtn && mobileBackupBtn.parentElement) { + mobileBackupBtn.parentElement.classList.add('hidden'); + } + if (mobileLogoutBtn && mobileLogoutBtn.parentElement) { + mobileLogoutBtn.parentElement.classList.add('hidden'); } if (!state.hasShownStartNotification) { - showNotification('Server is stopped. Click "Start" to enable all features.', 'error', 'server-stopped'); - state.hasShownStartNotification = true; + showNotification('Server is stopped. Click "Start" to enable all features.', 'error', 'server-stopped'); + state.hasShownStartNotification = true; } - } else { + } else { + // Show all sections sections.forEach(section => { - section.classList.remove('hidden'); + section.classList.remove('hidden'); }); + // Show control buttons if (editPropertiesBtn) { - editPropertiesBtn.classList.remove('hidden'); + editPropertiesBtn.classList.remove('hidden'); + editPropertiesBtn.style.display = ''; } if (updateModsBtn) { - updateModsBtn.classList.remove('hidden'); - } - if (backupBtn) { - backupBtn.classList.remove('hidden'); + updateModsBtn.classList.remove('hidden'); + updateModsBtn.style.display = ''; } if (sftpBtn) { - sftpBtn.classList.remove('hidden'); + sftpBtn.classList.remove('hidden'); } if (stopBtn) { - stopBtn.disabled = false; - stopBtn.classList.remove('disabled-btn'); + stopBtn.disabled = false; + stopBtn.classList.remove('disabled-btn'); } if (restartBtn) { - restartBtn.disabled = false; - restartBtn.classList.remove('disabled-btn'); + restartBtn.disabled = false; + stopBtn.classList.remove('disabled-btn'); } if (sftpBrowserSection) { - sftpBrowserSection.style.display = 'block'; + sftpBrowserSection.style.display = 'block'; + } + // Show Refresh, Backup, and Logout buttons in desktop nav + if (refreshBtn) { + refreshBtn.classList.remove('hidden'); + refreshBtn.style.display = ''; + } + if (backupBtn) { + backupBtn.classList.remove('hidden'); + refreshBtn.style.display = ''; + } + if (logoutBtn) { + logoutBtn.classList.remove('hidden'); + logoutBtn.style.display = ''; + } + // Show Refresh, Backup, and Logout menu items in mobile nav + if (mobileRefreshBtn && mobileRefreshBtn.parentElement) { + mobileRefreshBtn.parentElement.classList.remove('hidden'); + } + if (mobileBackupBtn && mobileBackupBtn.parentElement) { + mobileBackupBtn.parentElement.classList.remove('hidden'); + } + if (mobileLogoutBtn && mobileLogoutBtn.parentElement) { + mobileLogoutBtn.parentElement.classList.remove('hidden'); } state.hasShownStartNotification = false; - } } +} function updateDockerLogsUI(message) { if (message.error) { @@ -751,23 +893,52 @@ document.addEventListener('DOMContentLoaded', () => { ? players.map(player => `
${player} -
- - - - - - - - +
+ +
- `).join('') + `).join('') : 'None'; if (state.playerList !== playerListHtml && elements.playerList) { elements.playerList.innerHTML = playerListHtml; state.playerList = playerListHtml; - + + // Toggle action buttons + document.querySelectorAll('.toggle-actions').forEach(button => { + button.addEventListener('click', () => { + const player = button.getAttribute('data-player').trim(); + const actionDiv = document.querySelector(`.action-buttons[data-player="${player}"]`); + if (actionDiv) { + actionDiv.classList.toggle('hidden'); + button.textContent = actionDiv.classList.contains('hidden') ? 'Actions' : 'Hide'; + } + }); + }); + + // Close action buttons + document.querySelectorAll('.close-actions').forEach(button => { + button.addEventListener('click', () => { + const player = button.getAttribute('data-player').trim(); + const actionDiv = document.querySelector(`.action-buttons[data-player="${player}"]`); + const toggleButton = document.querySelector(`.toggle-actions[data-player="${player}"]`); + if (actionDiv && toggleButton) { + actionDiv.classList.add('hidden'); + toggleButton.textContent = 'Actions'; + } + }); + }); + document.querySelectorAll('.tell-player').forEach(button => { button.addEventListener('click', () => { const player = button.getAttribute('data-player').trim(); @@ -780,7 +951,7 @@ document.addEventListener('DOMContentLoaded', () => { elements.tellModal.classList.remove('hidden'); }); }); - + document.querySelectorAll('.give-player').forEach(button => { button.addEventListener('click', () => { const player = button.getAttribute('data-player').trim(); @@ -795,7 +966,7 @@ document.addEventListener('DOMContentLoaded', () => { elements.giveModal.classList.remove('hidden'); }); }); - + document.querySelectorAll('.teleport-player').forEach(button => { if (!button.disabled) { button.addEventListener('click', () => { @@ -813,7 +984,7 @@ document.addEventListener('DOMContentLoaded', () => { }); } }); - + document.querySelectorAll('.effect-player').forEach(button => { button.addEventListener('click', () => { const player = button.getAttribute('data-player').trim(); @@ -826,7 +997,7 @@ document.addEventListener('DOMContentLoaded', () => { elements.effectModal.classList.remove('hidden'); }); }); - + document.querySelectorAll('.kick-player').forEach(button => { button.addEventListener('click', () => { const player = button.getAttribute('data-player').trim(); @@ -858,7 +1029,7 @@ document.addEventListener('DOMContentLoaded', () => { } }); }); - + document.querySelectorAll('.ban-player').forEach(button => { button.addEventListener('click', () => { const player = button.getAttribute('data-player').trim(); @@ -890,7 +1061,7 @@ document.addEventListener('DOMContentLoaded', () => { } }); }); - + document.querySelectorAll('.op-player').forEach(button => { button.addEventListener('click', () => { const player = button.getAttribute('data-player').trim(); @@ -922,7 +1093,7 @@ document.addEventListener('DOMContentLoaded', () => { } }); }); - + document.querySelectorAll('.deop-player').forEach(button => { button.addEventListener('click', () => { const player = button.getAttribute('data-player').trim(); @@ -1038,9 +1209,7 @@ document.addEventListener('DOMContentLoaded', () => { } elements.loginPage.classList.remove('hidden'); elements.mainContent.classList.add('hidden'); - elements.authControls.innerHTML = ''; elements.apiKeyInput = document.getElementById('apiKey'); - elements.apiKeyInput.addEventListener('change', handleApiKeyChange); if (ws) { ws.close(); ws = null; @@ -1069,13 +1238,35 @@ document.addEventListener('DOMContentLoaded', () => { } elements.loginPage.classList.add('hidden'); elements.mainContent.classList.remove('hidden'); - elements.authControls.innerHTML = ''; - const logoutBtn = document.getElementById('logoutBtn'); - if (logoutBtn) { - logoutBtn.addEventListener('click', handleLogout); - } else { - console.error('Logout button not found after insertion'); - } + // Verify buttons exist + const logoutBtn = document.getElementById('logoutBtn'); + const mobileLogoutBtn = document.getElementById('mobileLogoutBtn'); + + if (logoutBtn) { + console.log('Desktop logout button found'); + } else { + console.error('Desktop logout button (#logoutBtn) not found'); + } + + if (mobileLogoutBtn) { + console.log('Mobile logout button found'); + } else { + console.error('Mobile logout button (#mobileLogoutBtn) not found'); + } + + // Remove any existing logout listeners to prevent duplicates + document.removeEventListener('click', handleLogoutClick); + + // Event delegation for logout buttons + function handleLogoutClick(event) { + if (event.target.id === 'logoutBtn' || event.target.id === 'mobileLogoutBtn') { + console.log(`Logout button clicked: ${event.target.id}`); + handleLogout(); + } + } + + document.addEventListener('click', handleLogoutClick); + initializeCharts(); initializeTerminal(); } @@ -1095,72 +1286,84 @@ document.addEventListener('DOMContentLoaded', () => { showLoginPage(); } + async function handleRefresh() { + if (ws && ws.readyState === WebSocket.OPEN) { + const key = `action-refresh`; + const notification = showNotification('Refreshing server data...', 'loading', key); + ws.send(JSON.stringify({ type: 'refresh' })); + initializeTerminal(); + setTimeout(() => updateNotification(notification, 'Server data refreshed successfully', 'success', key), 1000); + } else { + showNotification('Not connected to server. Please log in.', 'error', 'ws-disconnected'); + } + } + function updatePagination() { const totalPages = Math.max(1, Math.ceil(totalResults / resultsPerPage)); elements.pagination.innerHTML = ''; const createPageButton = (page, text, disabled = false) => { - const button = document.createElement('button'); - button.textContent = text; - button.className = `px-3 py-1 rounded ${disabled || page === currentPage - ? 'bg-gray-600 cursor-not-allowed' - : 'bg-blue-600 hover:bg-blue-700' + const button = document.createElement('button'); + button.textContent = text; + button.className = `nav-btn ${disabled || page === currentPage + ? 'disabled' + : 'active' }`; - if (!disabled && page !== currentPage) { - button.addEventListener('click', () => { - currentPage = page; - searchMods(); - }); - } - elements.pagination.appendChild(button); + if (!disabled && page !== currentPage) { + button.addEventListener('click', () => { + currentPage = page; + searchMods(); + }); + } + elements.pagination.appendChild(button); }; if (totalResults > 0) { - createPageButton(currentPage - 1, 'Previous', currentPage === 1); - const maxButtons = 5; - const startPage = Math.max(1, currentPage - Math.floor(maxButtons / 2)); - const endPage = Math.min(totalPages, startPage + maxButtons - 1); - for (let i = startPage; i <= endPage; i++) { - createPageButton(i, i.toString()); - } - createPageButton(currentPage + 1, 'Next', currentPage === totalPages); + createPageButton(currentPage - 1, 'Previous', currentPage === 1); + const maxButtons = 5; + const startPage = Math.max(1, currentPage - Math.floor(maxButtons / 2)); + const endPage = Math.min(totalPages, startPage + maxButtons - 1); + for (let i = startPage; i <= endPage; i++) { + createPageButton(i, i.toString()); + } + createPageButton(currentPage + 1, 'Next', currentPage === totalPages); } - } +} - function updateModListPagination() { +function updateModListPagination() { const filteredMods = state.allMods.filter(mod => - mod.name.toLowerCase().includes(modListSearchQuery.toLowerCase()) + mod.name.toLowerCase().includes(modListSearchQuery.toLowerCase()) ); const totalModPages = Math.max(1, Math.ceil(filteredMods.length / resultsPerPage)); elements.modListPagination.innerHTML = ''; const createPageButton = (page, text, disabled = false) => { - const button = document.createElement('button'); - button.textContent = text; - button.className = `px-3 py-1 rounded ${disabled || page === modListCurrentPage - ? 'bg-gray-600 cursor-not-allowed' - : 'bg-blue-600 hover:bg-blue-700' + const button = document.createElement('button'); + button.textContent = text; + button.className = `nav-btn ${disabled || page === modListCurrentPage + ? 'disabled' + : 'active' }`; - if (!disabled && page !== modListCurrentPage) { - button.addEventListener('click', () => { - modListCurrentPage = page; - renderModList(); - }); - } - elements.modListPagination.appendChild(button); + if (!disabled && page !== modListCurrentPage) { + button.addEventListener('click', () => { + modListCurrentPage = page; + renderModList(); + }); + } + elements.modListPagination.appendChild(button); }; if (filteredMods.length > 0) { - createPageButton(modListCurrentPage - 1, 'Previous', modListCurrentPage === 1); - const maxButtons = 5; - const startPage = Math.max(1, modListCurrentPage - Math.floor(maxButtons / 2)); - const endPage = Math.min(totalModPages, startPage + maxButtons - 1); - for (let i = startPage; i <= endPage; i++) { - createPageButton(i, i.toString()); - } - createPageButton(modListCurrentPage + 1, 'Next', modListCurrentPage === totalModPages); + createPageButton(modListCurrentPage - 1, 'Previous', modListCurrentPage === 1); + const maxButtons = 5; + const startPage = Math.max(1, modListCurrentPage - Math.floor(maxButtons / 2)); + const endPage = Math.min(totalModPages, startPage + maxButtons - 1); + for (let i = startPage; i <= endPage; i++) { + createPageButton(i, i.toString()); + } + createPageButton(modListCurrentPage + 1, 'Next', modListCurrentPage === totalModPages); } - } +} function closeSearch() { elements.modSearch.value = ''; @@ -1648,9 +1851,6 @@ document.addEventListener('DOMContentLoaded', () => { if (filteredSettings.includes(key)) { return; } - - console.log(`Rendering field for ${key}: ${value}`); - const fieldDiv = document.createElement('div'); fieldDiv.className = 'flex items-center space-x-2'; fieldDiv.style.display = 'flex'; @@ -1687,7 +1887,6 @@ document.addEventListener('DOMContentLoaded', () => { switchContainer.className = 'relative inline-block'; switchContainer.setAttribute('role', 'switch'); switchContainer.setAttribute('aria-checked', value.toLowerCase()); - switchContainer.setAttribute('tabindex', '0'); switchContainer.dataset.name = key; switchContainer.style.width = '40px'; switchContainer.style.height = '24px'; @@ -1918,7 +2117,7 @@ document.addEventListener('DOMContentLoaded', () => { } }); - elements.apiKeyInput.addEventListener('change', handleApiKeyChange); + // elements.apiKeyInput.addEventListener('change', handleApiKeyChange); elements.generateMyLinkBtn.addEventListener('click', async () => { try { @@ -1969,46 +2168,47 @@ document.addEventListener('DOMContentLoaded', () => { document.getElementById('startBtn').addEventListener('click', async () => { try { - const key = `action-start`; - const notification = showNotification('Starting server...', 'loading', key); - await wsRequest('/start'); - initializeTerminal(); - if (ws && ws.readyState === WebSocket.OPEN) { - ws.send(JSON.stringify({ type: 'subscribe', endpoints: ['docker', 'docker-logs'] })); - const messageHandler = (event) => { - try { - const message = JSON.parse(event.data); - if (message.type === 'docker') { - state.serverStatus = message.data?.status || 'Unknown'; - elements.serverStatus.textContent = state.serverStatus; - toggleSections(state.serverStatus); - if (message.data?.status === 'running') { - updateNotification(notification, 'Server started successfully', 'success', key); - ws.removeEventListener('message', messageHandler); - } - } - } catch (error) { - console.error('Error parsing WebSocket message:', error); - } - }; - ws.addEventListener('message', messageHandler); - setTimeout(() => { - if (ws && ws.readyState === WebSocket.OPEN) { - ws.removeEventListener('message', messageHandler); - if (state.serverStatus !== 'running') { - updateNotification(notification, 'Failed to start server. Please try again.', 'error', key); - toggleSections(state.serverStatus); - } - } - }, 30000); - } else { - updateNotification(notification, 'Not connected to server. Please log in.', 'error', key); - } + const key = `action-start`; + const notification = showNotification('Starting server...', 'loading', key); + await wsRequest('/start'); + initializeTerminal(); + if (ws && ws.readyState === WebSocket.OPEN) { + ws.send(JSON.stringify({ type: 'subscribe', endpoints: ['docker', 'docker-logs'] })); + const messageHandler = (event) => { + try { + const message = JSON.parse(event.data); + if (message.type === 'docker') { + state.serverStatus = message.data?.status || 'Unknown'; + elements.serverStatus.textContent = state.serverStatus; + toggleSections(state.serverStatus); + if (message.data?.status === 'running') { + updateNotification(notification, 'Server started successfully', 'success', key); + ws.removeEventListener('message', messageHandler); + } + } + } catch (error) { + console.error('Error parsing WebSocket message:', error); + } + }; + ws.addEventListener('message', messageHandler); + setTimeout(() => { + if (ws && ws.readyState === WebSocket.OPEN) { + ws.removeEventListener('message', messageHandler); + if (state.serverStatus !== 'running') { + updateNotification(notification, 'Failed to start server. Please try again.', 'error', key); + toggleSections(state.serverStatus); + } + } + }, 30000); + } else { + updateNotification(notification, 'Not connected to server. Please log in.', 'error', key); + } } catch (error) { - console.error('Start server error:', error); - showNotification(`Failed to start server: ${error.message}`, 'error', 'start-error'); + console.error('Start server error:', error); + showNotification(`Failed to start server: ${error.message}`, 'error', 'start-error'); } - }); +}); + document.getElementById('stopBtn').addEventListener('click', async () => { try { @@ -2065,6 +2265,8 @@ document.addEventListener('DOMContentLoaded', () => { } }); + + elements.updateModsBtn.addEventListener('click', updateMods); elements.closeUpdateModsBtn.addEventListener('click', () => { @@ -2177,4 +2379,42 @@ document.addEventListener('DOMContentLoaded', () => { showLoginPage(); } window.showNotification = showNotification; + + // Add this at the end of the document.addEventListener('DOMContentLoaded', ...) block +function applyResponsiveStyles() { + const sections = document.querySelectorAll('.section-bg'); + sections.forEach(section => { + section.style.padding = window.innerWidth <= 640 ? '1rem' : window.innerWidth <= 768 ? '1.5rem' : '2rem'; + section.style.maxWidth = '100%'; + section.style.overflowX = 'hidden'; + }); + + const iframes = document.querySelectorAll('#sftpIframe'); + iframes.forEach(iframe => { + iframe.style.height = window.innerWidth <= 640 ? '300px' : window.innerWidth <= 768 ? '400px' : '650px'; + iframe.style.minHeight = iframe.style.height; + iframe.style.width = '100%'; + iframe.style.maxWidth = '100%'; + }); + + const canvases = document.querySelectorAll('#memoryMeter, #cpuMeter'); + canvases.forEach(canvas => { + canvas.style.width = window.innerWidth <= 640 ? '80px' : window.innerWidth <= 768 ? '100px' : '150px'; + canvas.style.height = canvas.style.width; + }); + + const terminals = document.querySelectorAll('#dockerLogsTerminal'); + terminals.forEach(terminal => { + terminal.style.maxHeight = window.innerWidth <= 640 ? '7rem' : window.innerWidth <= 768 ? '8rem' : '12rem'; + }); + + const consoles = document.querySelectorAll('#consoleOutput'); + consoles.forEach(console => { + console.style.height = window.innerWidth <= 640 ? '7rem' : window.innerWidth <= 768 ? '8rem' : '12rem'; + }); +} + +window.addEventListener('resize', applyResponsiveStyles); + + }); \ No newline at end of file diff --git a/public/screenshots/panel.png b/public/screenshots/panel.png index 7e5a9fe..1c14f6e 100644 Binary files a/public/screenshots/panel.png and b/public/screenshots/panel.png differ