aprs.me/assets/css/app.css
Graham McIntire 7dc6c616a2
Bundle all vendor JavaScript files locally instead of loading from CDNs
This change eliminates all external CDN dependencies by bundling JavaScript
libraries locally using esbuild. All vendor files are now served from the
application's own assets, improving reliability and privacy.

Changes:
- Created assets/js/vendor.js to bundle all external libraries
- Added vendor bundle configuration to esbuild in config files
- Updated all templates to use local vendor.js instead of CDN scripts
- Created download-vendor-files.sh script to fetch vendor libraries
- Added vendor files to .gitignore (they're downloaded during setup)
- Updated CSS imports to include vendor stylesheets
- Added vendor build step to assets.deploy mix task

Bundled libraries:
- Leaflet 1.9.4 (mapping library)
- Leaflet.heat 0.2.0 (heatmap plugin)
- Leaflet.markercluster 1.5.3 (marker clustering)
- OverlappingMarkerSpiderfier 0.2.6 (overlapping marker handling)
- Chart.js 4.5.0 (charting library)
- chartjs-adapter-date-fns 3.0.0 (date adapter for Chart.js)

All functionality tested and working correctly with local bundles.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-21 09:52:39 -05:00

391 lines
No EOL
11 KiB
CSS

@import "tailwindcss" source(none);
@source "../css";
@source "../js";
@source "../../lib/aprsme_web";
/* Import vendor CSS files */
@import "../vendor/leaflet.css";
@import "../vendor/MarkerCluster.css";
@import "../vendor/MarkerCluster.Default.css";
/* A Tailwind plugin that makes "hero-#{ICON}" classes available.
The heroicons installation itself is managed by your mix.exs */
@plugin "../vendor/heroicons";
/* daisyUI Tailwind Plugin. You can update this file by fetching the latest version with:
curl -sLO https://github.com/saadeghi/daisyui/releases/latest/download/daisyui.js
Make sure to look at the daisyUI changelog: https://daisyui.com/docs/changelog/ */
@plugin "../vendor/daisyui" {
themes: false;
}
/* daisyUI theme plugin. You can update this file by fetching the latest version with:
curl -sLO https://github.com/saadeghi/daisyui/releases/latest/download/daisyui-theme.js
We ship with two themes, a light one inspired on Phoenix colors and a dark one inspired
on Elixir colors. Build your own at: https://daisyui.com/theme-generator/ */
@plugin "../vendor/daisyui-theme" {
name: "dark";
default: false;
prefersdark: true;
color-scheme: "dark";
--color-base-100: oklch(30.33% 0.016 252.42);
--color-base-200: oklch(25.26% 0.014 253.1);
--color-base-300: oklch(20.15% 0.012 254.09);
--color-base-content: oklch(97.807% 0.029 256.847);
--color-primary: oklch(58% 0.233 277.117);
--color-primary-content: oklch(96% 0.018 272.314);
--color-secondary: oklch(58% 0.233 277.117);
--color-secondary-content: oklch(96% 0.018 272.314);
--color-accent: oklch(60% 0.25 292.717);
--color-accent-content: oklch(96% 0.016 293.756);
--color-neutral: oklch(37% 0.044 257.287);
--color-neutral-content: oklch(98% 0.003 247.858);
--color-info: oklch(58% 0.158 241.966);
--color-info-content: oklch(97% 0.013 236.62);
--color-success: oklch(60% 0.118 184.704);
--color-success-content: oklch(98% 0.014 180.72);
--color-warning: oklch(66% 0.179 58.318);
--color-warning-content: oklch(98% 0.022 95.277);
--color-error: oklch(58% 0.253 17.585);
--color-error-content: oklch(96% 0.015 12.422);
--radius-selector: 0.25rem;
--radius-field: 0.25rem;
--radius-box: 0.5rem;
--size-selector: 0.21875rem;
--size-field: 0.21875rem;
--border: 1.5px;
--depth: 1;
--noise: 0;
}
@plugin "../vendor/daisyui-theme" {
name: "light";
default: true;
prefersdark: false;
color-scheme: "light";
--color-base-100: oklch(98% 0 0);
--color-base-200: oklch(96% 0.001 286.375);
--color-base-300: oklch(92% 0.004 286.32);
--color-base-content: oklch(21% 0.006 285.885);
--color-primary: oklch(70% 0.213 47.604);
--color-primary-content: oklch(98% 0.016 73.684);
--color-secondary: oklch(55% 0.027 264.364);
--color-secondary-content: oklch(98% 0.002 247.839);
--color-accent: oklch(0% 0 0);
--color-accent-content: oklch(100% 0 0);
--color-neutral: oklch(44% 0.017 285.786);
--color-neutral-content: oklch(98% 0 0);
--color-info: oklch(62% 0.214 259.815);
--color-info-content: oklch(97% 0.014 254.604);
--color-success: oklch(70% 0.14 182.503);
--color-success-content: oklch(98% 0.014 180.72);
--color-warning: oklch(66% 0.179 58.318);
--color-warning-content: oklch(98% 0.022 95.277);
--color-error: oklch(58% 0.253 17.585);
--color-error-content: oklch(96% 0.015 12.422);
--radius-selector: 0.25rem;
--radius-field: 0.25rem;
--radius-box: 0.5rem;
--size-selector: 0.21875rem;
--size-field: 0.21875rem;
--border: 1.5px;
--depth: 1;
--noise: 0;
}
/* Add variants based on LiveView classes */
@custom-variant phx-click-loading (.phx-click-loading&, .phx-click-loading &);
@custom-variant phx-submit-loading (.phx-submit-loading&, .phx-submit-loading &);
@custom-variant phx-change-loading (.phx-change-loading&, .phx-change-loading &);
/* Make LiveView wrapper divs transparent for layout */
[data-phx-session] {
display: contents
}
/* This file is for your main application CSS */
/* Navbar dark mode fixes */
[data-theme="dark"] .navbar,
[data-theme="dark"] .navbar a,
[data-theme="dark"] .navbar .menu,
[data-theme="dark"] .navbar .btn,
[data-theme="dark"] .navbar .btn-ghost {
color: #fff !important;
}
[data-theme="dark"] .navbar .btn-ghost:hover {
background-color: oklch(25.26% 0.014 253.1);
color: #fff !important;
}
[data-theme="dark"] .navbar .text-primary {
color: oklch(58% 0.233 277.117) !important;
}
/* Input field dark mode fixes */
/* Marker cluster styles */
.marker-cluster-small {
background-color: rgba(16, 185, 129, 0.8);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.marker-cluster-small div {
background-color: rgba(16, 185, 129, 0.9);
box-shadow: inset 0 1px 2px rgba(255, 255, 255, 0.3);
}
.marker-cluster-medium {
background-color: rgba(59, 130, 246, 0.8);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.marker-cluster-medium div {
background-color: rgba(59, 130, 246, 0.9);
box-shadow: inset 0 1px 2px rgba(255, 255, 255, 0.3);
}
.marker-cluster-large {
background-color: rgba(239, 68, 68, 0.8);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.marker-cluster-large div {
background-color: rgba(239, 68, 68, 0.9);
box-shadow: inset 0 1px 2px rgba(255, 255, 255, 0.3);
}
/* Custom cluster icon styles */
.marker-cluster {
background-clip: padding-box;
border-radius: 50%;
border: 2px solid rgba(255, 255, 255, 0.8);
}
.marker-cluster div {
width: 30px;
height: 30px;
margin-left: 5px;
margin-top: 5px;
text-align: center;
border-radius: 50%;
font:
13px "Helvetica Neue",
Arial,
Helvetica,
sans-serif;
color: white;
font-weight: bold;
line-height: 30px;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}
.marker-cluster span {
line-height: 30px;
}
/* Cluster animations */
.leaflet-cluster-anim .leaflet-marker-icon,
.leaflet-cluster-anim .leaflet-marker-shadow {
transition:
transform 0.3s ease-out,
opacity 0.3s ease-out;
}
/* Hover effect for clusters */
.marker-cluster:hover {
transform: scale(1.1);
z-index: 1000 !important;
}
/* APRS marker styles */
.aprs-marker {
transition: transform 0.2s ease-out;
}
.aprs-marker:hover {
transform: scale(1.2);
z-index: 1000 !important;
}
/* High-DPI support for APRS symbols */
@media (-webkit-min-device-pixel-ratio: 2),
(min-resolution: 192dpi) {
.aprs-marker div[style*="aprs-symbols-24-0.png"] {
background-image: url("/aprs-symbols/aprs-symbols-24-0@2x.png") !important;
background-size: 384px 144px !important;
}
.aprs-marker div[style*="aprs-symbols-24-1.png"] {
background-image: url("/aprs-symbols/aprs-symbols-24-1@2x.png") !important;
background-size: 384px 144px !important;
}
.aprs-marker div[style*="aprs-symbols-24-2.png"] {
background-image: url("/aprs-symbols/aprs-symbols-24-2@2x.png") !important;
background-size: 384px 144px !important;
}
}
/* Trail visualization styles */
.trail-tooltip {
background-color: rgba(0, 0, 0, 0.8);
border: 1px solid #1e90ff;
color: white;
font-size: 11px;
padding: 2px 6px;
border-radius: 3px;
white-space: nowrap;
}
/* Trail polyline hover effect */
.leaflet-interactive:hover {
stroke-width: 5;
stroke-opacity: 1 !important;
}
/* Historical trail lines */
.leaflet-interactive[stroke="#1E90FF"] {
stroke-width: 3;
stroke-opacity: 0.8;
stroke-linecap: round;
stroke-linejoin: round;
}
.leaflet-interactive[stroke="#1E90FF"]:hover {
stroke-width: 5;
stroke-opacity: 1;
filter: drop-shadow(0 0 4px #1e90ff);
}
/* Position dot hover effect */
.leaflet-marker-icon.leaflet-interactive:hover {
transform: scale(1.5);
transition: transform 0.2s ease-out;
}
/* Trail controls styling */
.trail-toggle-control {
background-color: white;
border: 2px solid rgba(0, 0, 0, 0.2);
border-radius: 4px;
padding: 5px 10px;
font-size: 14px;
cursor: pointer;
transition: background-color 0.2s ease;
}
.trail-toggle-control:hover {
background-color: #f0f0f0;
}
.trail-toggle-control.active {
background-color: #1e90ff;
color: white;
}
/* Historical dot marker styles */
.historical-dot-marker {
cursor: pointer;
transition: transform 0.2s ease-out;
}
.historical-dot-marker:hover {
transform: scale(1.5);
z-index: 1000 !important;
}
.historical-dot-marker div {
box-shadow: 0 0 4px rgba(0, 0, 0, 0.4);
transition: all 0.2s ease-out;
}
.historical-dot-marker:hover div {
box-shadow: 0 0 8px rgba(255, 107, 107, 0.8);
border-color: #ff6b6b !important;
}
/* Historical trail line styling */
.historical-trail-line {
stroke-width: 3;
stroke-opacity: 0.8;
stroke-linecap: round;
stroke-linejoin: round;
fill: none;
transition: all 0.2s ease-out;
z-index: 1;
}
.historical-trail-line:hover {
stroke-width: 5;
stroke-opacity: 1;
filter: drop-shadow(0 0 4px currentColor);
z-index: 2;
}
/* Ensure markers are above trail lines */
.leaflet-marker-icon {
z-index: 10 !important;
}
.historical-dot-marker {
z-index: 15 !important;
}
/* Input field dark mode fixes - Override DaisyUI CSS variables for dark theme */
[data-theme="dark"] {
--color-base-100: #2d3748 !important;
--color-base-200: #1a202c !important;
--color-base-300: #171923 !important;
--color-base-content: #f7fafc !important;
--input-bg: #2d3748;
--input-color: #f7fafc;
--input-border: #4a5568;
}
/* Ultra-specific selector to override DaisyUI */
html[data-theme="dark"] .card .input,
html[data-theme="dark"] .card .input-bordered,
html[data-theme="dark"] .card input.input,
html[data-theme="dark"] .card input.input-bordered,
html[data-theme="dark"] .card input[type="email"],
html[data-theme="dark"] .card input[type="password"],
html[data-theme="dark"] .form-control input.input,
html[data-theme="dark"] .form-control input.input-bordered,
html[data-theme="dark"] .form-control input[type="email"],
html[data-theme="dark"] .form-control input[type="password"] {
background-color: #2d3748 !important;
color: #f7fafc !important;
border-color: #4a5568 !important;
}
html[data-theme="dark"] .card .input:focus,
html[data-theme="dark"] .card .input-bordered:focus,
html[data-theme="dark"] .card input.input:focus,
html[data-theme="dark"] .card input.input-bordered:focus,
html[data-theme="dark"] .card input[type="email"]:focus,
html[data-theme="dark"] .card input[type="password"]:focus,
html[data-theme="dark"] .form-control input.input:focus,
html[data-theme="dark"] .form-control input.input-bordered:focus,
html[data-theme="dark"] .form-control input[type="email"]:focus,
html[data-theme="dark"] .form-control input[type="password"]:focus {
background-color: #2d3748 !important;
color: #f7fafc !important;
border-color: #6366f1 !important;
}
html[data-theme="dark"] .input::placeholder,
html[data-theme="dark"] input.input::placeholder,
html[data-theme="dark"] input[type="email"]::placeholder,
html[data-theme="dark"] input[type="password"]::placeholder {
color: oklch(60% 0.029 256.847) !important;
}
html[data-theme="dark"] .checkbox,
html[data-theme="dark"] input.checkbox {
background-color: var(--input-bg) !important;
border-color: var(--input-border) !important;
}