refactor: enhance CSS patching and restoration logic in deployment script

- Added a new installation script to patch webgui CSS files, ensuring that styles for specific elements are wrapped with `:not(.unraid-reset)` to prevent style leakage.
- Implemented a backup and restoration mechanism for original CSS files, allowing for easy recovery after patching.
- Improved the handling of CSS directories and added warnings for missing directories to enhance robustness during deployment.
This commit is contained in:
Eli Bosley
2025-08-31 09:00:40 -04:00
parent 3cd5c0e8fd
commit 9dcd05748e
2 changed files with 175 additions and 46 deletions

View File

@@ -161,7 +161,100 @@ exit 0
sed -i 's|<body>|<body>\n<unraid-modals></unraid-modals>|' "/usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php"
fi
fi
]]>
</INLINE>
</FILE>
<FILE Run="/bin/php" Method="install">
<INLINE>
<![CDATA[
<?php
echo "Patching webgui CSS files to exclude .unraid-reset components...\n";
$cssDir = "/usr/local/emhttp/plugins/dynamix/styles";
$backupDir = "$cssDir/.unraid-api-backup";
if (!is_dir($cssDir)) {
echo "Warning: CSS directory not found at $cssDir\n";
exit(0);
}
// Create backup directory
if (!is_dir($backupDir)) {
mkdir($backupDir, 0755, true);
}
// Elements to wrap with :not(.unraid-reset)
$elementsToWrap = [
// Form inputs
"input", "textarea", "select", "button", "label",
// Tables
"table", "thead", "tbody", "tfoot", "tr", "td", "th",
// Links styled as buttons
"a.button",
// Common structural elements that might have global styles
"form", "fieldset", "legend"
];
// Process only default-* and dynamix-* CSS files
foreach (glob("$cssDir/*.css") as $cssFile) {
$filename = basename($cssFile);
// Only process default-* and dynamix-* files
if (!preg_match('/^(default-|dynamix-).*\.css$/', $filename)) {
continue;
}
$backupFile = "$backupDir/$filename";
// Read file content
$content = file_get_contents($cssFile);
// Skip if already patched
if (strpos($content, ":not(.unraid-reset)") !== false) {
echo " $filename already patched, skipping...\n";
continue;
}
// Create backup if it doesn't exist
if (!file_exists($backupFile)) {
copy($cssFile, $backupFile);
}
echo " Patching $filename...\n";
// Process each line
$lines = explode("\n", $content);
$modifiedLines = [];
foreach ($lines as $line) {
$modified = false;
$trimmedLine = ltrim($line);
$leadingWhitespace = substr($line, 0, strlen($line) - strlen($trimmedLine));
// Check if line starts with any element selector
foreach ($elementsToWrap as $element) {
// Match element at start of selector (with possible pseudo-classes)
if (preg_match("/^" . preg_quote($element, "/") . "([\[\:\.\#\s\,\>]|$)/", $trimmedLine)) {
// Add :not(.unraid-reset) prefix
$modifiedLines[] = $leadingWhitespace . ":not(.unraid-reset) " . $trimmedLine;
$modified = true;
break;
}
}
if (!$modified) {
$modifiedLines[] = $line;
}
}
// Write modified content back
file_put_contents($cssFile, implode("\n", $modifiedLines));
}
echo "CSS patching complete.\n";
?>
]]>
</INLINE>
</FILE>
@@ -272,6 +365,27 @@ exit 0
[ -f "$FILE-" ] && mv -f "$FILE-" "$FILE"
done
# Restore CSS files from backup
echo "Restoring original CSS files..."
CSS_DIR="/usr/local/emhttp/plugins/dynamix/styles"
BACKUP_DIR="$CSS_DIR/.unraid-api-backup"
if [ -d "$BACKUP_DIR" ]; then
for backup_file in "$BACKUP_DIR"/*.css; do
if [ -f "$backup_file" ]; then
filename=$(basename "$backup_file")
original_file="$CSS_DIR/$filename"
echo " Restoring $filename..."
cp "$backup_file" "$original_file"
fi
done
# Remove backup directory after restoration
rm -rf "$BACKUP_DIR"
echo "CSS restoration complete."
else
echo "No CSS backup found, skipping restoration."
fi
# Handle the unraid-components directory
DIR=/usr/local/emhttp/plugins/dynamix.my.servers/unraid-components
# Remove the archive's contents before restoring

View File

@@ -8,76 +8,91 @@
@source "../../unraid-ui/src/**/*.{vue,ts}";
@source "../**/*.{vue,ts,js}";
/* Create a CSS layer for resets with lower priority than Tailwind */
@layer base {
/* Reset inherited styles from webgui for Unraid components */
.unraid-reset,
.unraid-reset *:not(svg):not(path):not(g):not(circle):not(rect):not(line):not(polyline):not(polygon):not(ellipse):not(text):not(tspan):not(stop):not(defs):not(clipPath):not(mask):not(marker):not(symbol):not(use):not(image):not(pattern) {
/* Reset all CSS properties to browser defaults */
all: unset;
/* Restore essential properties */
display: revert;
box-sizing: border-box;
}
/*
* Strategy: Only reset the specific properties that webgui sets
* This preserves Tailwind's ability to style elements
*/
/* Apply isolation to non-modal components to prevent style leakage */
.unraid-reset:not(#teleports):not(#modals):not(unraid-modals) {
/* Create a new stacking context for style isolation */
isolation: isolate;
}
/* Container wrapper */
.unraid-reset {
/* Create isolation and set base styles */
isolation: isolate;
display: contents;
/* Ensure SVG icons render properly - don't reset them */
.unraid-reset svg {
fill: currentColor;
}
/* Override webgui font settings */
font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
font-size: 16px;
line-height: 1.5;
color: rgb(17 24 39);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* Specific resets for interactive elements to restore functionality */
/* Dark mode */
.dark .unraid-reset {
color: rgb(243 244 246);
}
/* Reset only the properties that webgui commonly sets */
.unraid-reset * {
/* Reset text transforms */
text-transform: none;
letter-spacing: normal;
/* Ensure box-sizing is correct */
box-sizing: border-box;
}
/* Specific resets for form elements that webgui heavily styles */
.unraid-reset button,
.unraid-reset input,
.unraid-reset select,
.unraid-reset textarea {
cursor: revert;
/* Reset button borders that leak from webgui */
border: none;
background: none;
padding: 0;
margin: 0;
/* Remove webgui form styling */
appearance: none;
background-image: none;
font: inherit;
color: inherit;
text-align: inherit;
min-width: initial;
}
.unraid-reset a {
/* Ensure buttons are clickable */
.unraid-reset button,
.unraid-reset [role="button"],
.unraid-reset input[type="button"],
.unraid-reset input[type="submit"],
.unraid-reset input[type="reset"] {
cursor: pointer;
text-decoration: revert;
}
/* Links */
.unraid-reset a {
color: inherit;
text-decoration: none;
cursor: pointer;
}
/* Hidden elements */
.unraid-reset [hidden] {
display: none !important;
}
/* Ensure modals and their backdrops appear above all other content */
[role="dialog"] {
z-index: 99999 !important;
/* SVG icons should inherit color */
.unraid-reset svg {
fill: currentColor;
}
/* Modal backdrop */
.fixed.inset-0[aria-hidden="true"],
[data-headlessui-portal] .fixed.inset-0 {
z-index: 99998 !important;
}
/* Teleport container children */
/* Modal z-index management */
[role="dialog"],
[data-headlessui-portal],
#teleports > *,
#modals > *,
unraid-modals > * {
z-index: 99999 !important;
}
/* Portal roots from HeadlessUI */
[data-headlessui-portal] {
position: relative;
z-index: 99999 !important;
}
/* Modal backdrops */
.fixed.inset-0[aria-hidden="true"],
[data-headlessui-portal] .fixed.inset-0 {
z-index: 99998 !important;
}