diff --git a/src/App.css b/src/App.css index 33a9731..31df293 100644 --- a/src/App.css +++ b/src/App.css @@ -1,122 +1,123 @@ :root { - --discord-white: #ffffff; /* Discord's white color */ - --discord-blue: #7289da; /* Discord's primary blue color */ - --discord-gray-1: #424549; /* Discord's primary blue color */ - --discord-gray-2: #36393e; /* Discord's primary blue color */ - --discord-gray-3: #282b30; /* Discord's primary blue color */ - --discord-gray-4: #1e2124; /* Discord's primary blue color */ - --warning-red: #e32727; + --bg: #16171a; + --card-bg: #1d1f23; + --card-border: #26282e; + --input-bg: #25272c; + --input-border: #34363c; + --text: #f3f2ef; + --text-muted: #9a9da4; + --text-secondary: #c7c9ce; + --accent: #c98a3f; + --accent-text: #1b1408; + --red: #e2585c; + --green: #5cb37a; + --orange: #e0aa4a; + --warning-red: #e2585c; +} + +@keyframes toastSlideIn { + from { + opacity: 0; + transform: translateY(8px); + } + to { + opacity: 1; + transform: translateY(0); + } } body { - background-color: '--discord-gray-1'; /* Replace #ffffff with the color code or name of your desired background color */ + background-color: var(--bg); + margin: 0; +} + +::selection { + background: var(--accent); + color: var(--accent-text); } h1 { - color: var(--discord-white); + color: var(--text); margin: 0; padding: 10px 0; } .section-heading { - color: var(--discord-white); - margin: 0 0 4px 0; - padding: 0; - text-align: left; + margin: 0; + font-size: 14px; + font-weight: 700; + color: var(--text); + text-transform: uppercase; + letter-spacing: 0.04em; } .property-editor { width: 100%; max-width: 100%; text-align: left; - align-self: flex-start; } .property-section { width: 100%; display: flex; flex-direction: column; - align-items: flex-start; - gap: 10px; + align-items: stretch; + gap: 16px; } a { text-decoration: none !important; } -/* styles.css */ - -/* styles.css */ - .dropdown-item { - padding: 5px; + padding: 10px 14px; + font-size: 13px; cursor: pointer; + color: var(--text); } .dropdown-item:hover { - background-color: var(--discord-gray-2); + background-color: var(--input-bg); } -.Top-banner { - background-color: var(--discord-gray-3); - color: var(--discord-white); - text-align: left; /* Align text to the left */ - padding: 20px; /* Increase header padding for a larger header */ +.chip { display: flex; - justify-content: space-between; /* Add space between text and the right edge */ - align-items: center; /* Center vertically */ -} - -#entry-list { - display: flex; - flex-direction: column; - align-items: flex-start; /* Align entries to the left */ - background-color: var(--discord-gray-1); -} - -#display { - display: flex; - flex-direction: column; - align-items: flex-start; /* Align entries to the left */ - background-color: var(--discord-gray-1); - color: var(--discord-white); - /* width: 100vw; Stretch the entry list to the bottom of the screen */ + align-items: center; + gap: 6px; + background: var(--input-bg); + border: 1px solid var(--input-border); + border-radius: 999px; + padding: 4px 6px 4px 12px; + font-size: 12px; + color: var(--text); } -#display-list { - display: flex; - flex-direction: column; - align-items: flex-start; /* Align entries to the left */ - background-color: var(--discord-gray-1); - color: var(--discord-white); - width: 420px; /* Stretch the entry list to the bottom of the screen */ +.chip button { + background: none; + border: none; + color: var(--text-muted); + cursor: pointer; + font-size: 13px; + padding: 0 4px; } -.entry { - /* margin-bottom: 10px; */ - padding: 10px; - background-color: var(--discord-gray-2); - width: 500px; - text-align: left; - color: var(--discord-white); +.segmented-control { display: flex; - flex-direction: column; - gap: 5px; - border-radius: 8px; -} - -.special-text { - width: 237.5px !important; + align-items: center; + gap: 2px; + background: var(--input-bg); + border: 1px solid var(--input-border); + border-radius: 9px; + padding: 3px; } -#entry { - margin-bottom: 10px; - padding: 10px; - width: 400px; - background-color: var(--discord-gray-2); - text-align: left; - color: var(--discord-white); - border-radius: 8px; +.segmented-control button { + border: none; + border-radius: 6px; + padding: 7px 14px; + font-size: 12.5px; + font-weight: 600; + cursor: pointer; } .toggle-button-shell { @@ -126,33 +127,130 @@ a { } .toggle-switch { - width: 60px; - height: 30px; - background-color: #ccc; - border-radius: 30px; + width: 34px; + height: 19px; + background-color: var(--input-border); + border-radius: 999px; position: relative; cursor: pointer; - transition: background-color 0.3s; + transition: background-color 0.2s; flex-shrink: 0; } .toggle-switch.toggled { - background-color: var(--discord-blue); + background-color: var(--accent); } .toggle-knob { - width: 28px; - height: 28px; - background-color: white; + width: 15px; + height: 15px; + background-color: var(--text); border-radius: 50%; position: absolute; - top: 1px; - left: 1px; - transition: left 0.3s; + top: 2px; + left: 2px; + transition: left 0.2s; } .toggle-switch.toggled .toggle-knob { - left: 31px; + left: 17px; +} + +.toggle-switch.toggle-switch-lg { + width: 38px; + height: 21px; +} + +.toggle-switch.toggle-switch-lg .toggle-knob { + width: 17px; + height: 17px; +} + +.toggle-switch.toggle-switch-lg.toggled .toggle-knob { + left: 19px; +} + +.main-grid { + grid-template-columns: minmax(0, 1fr) 420px; +} + +@media (max-width: 820px) { + .main-grid { + grid-template-columns: 1fr; + } +} + +.card-section { + background: var(--card-bg); + border: 1px solid var(--card-border); + border-radius: 12px; + padding: 20px; +} + +.header-button { + height: 36px; + padding: 0 14px; + border-radius: 7px; + border: 1px solid var(--input-border); + background: var(--input-bg); + color: var(--text); + font-size: 12.5px; + font-weight: 600; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.header-button-primary { + border: none; + background: var(--accent); + color: var(--accent-text); + font-weight: 700; +} + +.field-label { + display: block; + font-size: 12px; + color: var(--text-muted); + margin-bottom: 6px; +} + +.field-input { + width: 100%; + box-sizing: border-box; + background: var(--input-bg); + border: 1px solid var(--input-border); + color: var(--text); + border-radius: 8px; + padding: 10px 12px; + font-size: 13px; + outline: none; +} + +.preview-card { + display: flex; + gap: 12px; + background: var(--card-bg); + border: 1px solid var(--card-border); + border-radius: 12px; + padding: 14px; +} + +.toast { + animation: toastSlideIn 0.25s ease; + display: flex; + align-items: center; + gap: 10px; + padding: 12px 14px; + border-radius: 10px; + background: var(--card-bg); + border: 1px solid var(--input-border); + border-left: 3px solid var(--accent); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35); + font-size: 13px; + line-height: 1.4; + color: var(--text); } .App { @@ -171,18 +269,18 @@ a { } .App-header { - background-color: var(--discord-gray-1); + background-color: var(--bg); min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); - color: var(--discord-white); + color: var(--text); } .App-link { - color: var(--discord-blue); + color: var(--accent); } @keyframes App-logo-spin { diff --git a/src/App.tsx b/src/App.tsx index 9e41132..12bbaa1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useMemo, useState } from 'react' +import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react' import MaterialEntry from './Components/TextInputs/MaterialId' import MaterialDisplayName from './Components/TextInputs/MaterialDisplayName' import SliderEntry from './Components/Sliders/SliderEntry' @@ -128,10 +128,6 @@ const AppContent: React.FC = () => { setColorPalette(colors) } - const hasPropertyContent = (field: 'properties' | 'display_properties' | 'hidden_properties') => { - return Object.keys(propertyFields[field]).length > 0 - } - const handlePropertyFieldSubmit = (field: 'properties' | 'display_properties' | 'hidden_properties') => { return (value: Record) => { setPropertyFields((prev) => ({ @@ -155,42 +151,6 @@ const AppContent: React.FC = () => { })) } - const buttonStyle = { - padding: '10px', - margin: '5px', - backgroundColor: '#7289DA', // Discord's primary blue color - color: '#ffffff', // Discord's white color - border: 'none', - borderRadius: '5px', - cursor: 'pointer' - } - - const rootStyle = { - '--button-background': '#7289DA', // Discord's primary blue color - '--button-text-color': '#ffffff' // Discord's white color - } - - const floatingToggleBoxStyle = { - display: 'flex', - flexDirection: 'column' as const, - gap: '8px', - padding: '10px', - borderRadius: '10px', - backgroundColor: '#2f3136', - border: '1px solid #3a3f4b', - color: '#ffffff', - minWidth: '280px', - boxShadow: '0 4px 12px rgba(0, 0, 0, 0.25)' - } - - const floatingToggleRowStyle = { - display: 'flex', - alignItems: 'center', - justifyContent: 'flex-start', - gap: '10px', - padding: '6px 0' - } - const loadedPropertyFields = useMemo( () => ({ properties: loadData?.properties && typeof loadData.properties === 'object' && !Array.isArray(loadData.properties) ? loadData.properties : {}, @@ -206,12 +166,6 @@ const AppContent: React.FC = () => { [loadData] ) - const hasAnyPropertySectionEnabled = Object.values(enabledPropertyFields).some(Boolean) - const hasAnyPropertyContent = (['properties', 'display_properties', 'hidden_properties'] as const).some( - (field) => hasPropertyContent(field) || Object.keys(loadedPropertyFields[field]).length > 0 - ) - const shouldShowPropertySection = hasAnyPropertySectionEnabled || hasAnyPropertyContent - useEffect(() => { if (!loadData) { return @@ -258,11 +212,7 @@ const AppContent: React.FC = () => { } // Add files - if (is121Plus) { - materialFolder?.file(displayID + '.json', JSON.stringify(generateMaterialObject())) // Add your file content here - } else { - materialFolder?.file(displayID + '.json', JSON.stringify(generateMaterialObject())) // Add your file content here - } + materialFolder?.file(displayID + '.json', JSON.stringify(generateMaterialObject())) zip?.file('pack.mcmeta', JSON.stringify(mcMeta)) // Generate ZIP file @@ -366,152 +316,192 @@ const AppContent: React.FC = () => { addWarning('Successfully Copied! You might want to use a command block!', '#fcba03') } + // Height sync: keep the Properties panel's min-height matching the left + // column's overflow past the preview cards, mirroring the two-column layout. + const leftColRef = useRef(null) + const previewsBlockRef = useRef(null) + const [propertiesMinHeight, setPropertiesMinHeight] = useState(0) + + useLayoutEffect(() => { + const leftEl = leftColRef.current + const previewsEl = previewsBlockRef.current + if (!leftEl || !previewsEl) { + return + } + + const sync = () => { + const leftHeight = leftEl.getBoundingClientRect().height + const previewsHeight = previewsEl.getBoundingClientRect().height + const target = Math.max(0, Math.round(leftHeight - previewsHeight - 14)) + setPropertiesMinHeight((prev) => (Math.abs(prev - target) > 2 ? target : prev)) + } + + const observer = new ResizeObserver(sync) + observer.observe(leftEl) + observer.observe(previewsEl) + sync() + + return () => observer.disconnect() + }, []) + + const propertyFieldOrder = ['properties', 'display_properties', 'hidden_properties'] as const + return (
-
-
- + + Truly Modular logo +
+ Truly Modular + Material Helper +
+
+ +
+
-
-
- { - addWarning(warning, color) - }} - is121Plus={is121Plus} - > + 1.21+ +
-
- - - -
-
+ -
-
-
-
-

Details

-
-
- setMaterialId(entryText)} /> - setMaterialDisplayName(entryText)} /> -
- -
-
- -
- -
-
-
-

Stats

- -
- {shouldShowPropertySection && ( -
-

Properties

- {(['properties', 'display_properties', 'hidden_properties'] as const) - .filter( - (field) => enabledPropertyFields[field] || hasPropertyContent(field) || Object.keys(loadedPropertyFields[field]).length > 0 - ) - .map((field) => ( - } - onSubmit={handlePropertyFieldSubmit(field)} - /> - ))} -
- )} +
+
+

+ Details +

+
+ setMaterialId(entryText)} /> + setMaterialDisplayName(entryText)} />
-
-

Previews

- {isAutoGenerateColors && ( -
- Previews aren't representing ingame colors anymore, since automatic generation is toggled! -
+ +
+ + + +
+
+

Stats

+ {is121Plus && ( + )} -
-
+ +
-
-
-
- Toggles -
- {is121Plus && ( -
- - Generate converters + +
+
+ {isAutoGenerateColors && ( +
+ Previews aren't representing in-game colors anymore, since automatic generation is toggled!
)} - {(['properties', 'display_properties', 'hidden_properties'] as const).map((field) => ( -
- togglePropertyField(field)} /> - {field} -
- ))} +
- {warnings.map((warning) => ( - - ))} + +
+

Properties

+ {propertyFieldOrder.map((field) => ( + } + onSubmit={handlePropertyFieldSubmit(field)} + enabled={enabledPropertyFields[field]} + onToggle={() => togglePropertyField(field)} + /> + ))} +
-
+ + +
+ {warnings.map((warning) => ( + + ))}
) diff --git a/src/Components/Buttons/ToggleButton.tsx b/src/Components/Buttons/ToggleButton.tsx index f277ba2..0878dff 100644 --- a/src/Components/Buttons/ToggleButton.tsx +++ b/src/Components/Buttons/ToggleButton.tsx @@ -1,11 +1,22 @@ -const ToggleButton = ({ isToggled, setIsToggled }: { isToggled: boolean; setIsToggled: (value: boolean) => void }) => { +const ToggleButton = ({ + isToggled, + setIsToggled, + size = 'sm' +}: { + isToggled: boolean + setIsToggled: (value: boolean) => void + size?: 'sm' | 'lg' +}) => { const handleToggle = () => { setIsToggled(!isToggled) } return (
-
+
diff --git a/src/Components/ColorPicker/ColoPickerProps.tsx b/src/Components/ColorPicker/ColoPickerProps.tsx index b2efdfa..6fdb022 100644 --- a/src/Components/ColorPicker/ColoPickerProps.tsx +++ b/src/Components/ColorPicker/ColoPickerProps.tsx @@ -43,44 +43,50 @@ const ColorPicker: React.FC = ({ initialColor, onChange, disab } return ( -
-
- {showPicker && !disabled && ( +
+
- -
- )} - {disabled && ( -
- )} + {showPicker && !disabled && ( +
+ +
+ )} + {disabled && ( +
+ )} +
+ {color}
) } diff --git a/src/Components/ColorPicker/ColorPickerGroup.tsx b/src/Components/ColorPicker/ColorPickerGroup.tsx index 2404ab0..3f9462d 100644 --- a/src/Components/ColorPicker/ColorPickerGroup.tsx +++ b/src/Components/ColorPicker/ColorPickerGroup.tsx @@ -71,68 +71,87 @@ const ColorPickerGroup: React.FC = ({ initialColors, onSu } return ( -
-

Material Colors

-
- {/* Generate Automatically Checkbox and Plus/Minus Buttons */} -
- {/* Left-aligned checkbox */} -
- - setColorAutoGenerate(e.target.checked)} /> -
- - {/* Right-aligned buttons */} -
- -
- {/* Color Pickers */} -
- {gradientColors.map((color, index) => ( - handleColorChange(index, newColor)} - disabled={autoGenerateColors} - /> - ))} -
- {/* Banner with dynamic gradient background */} -
-
+ {/* Color Pickers */} +
+ {gradientColors.map((color, index) => ( + handleColorChange(index, newColor)} + disabled={autoGenerateColors} + /> + ))} +
+ {/* Banner with dynamic gradient background */} +
+ ) } diff --git a/src/Components/Displays/DisplayComponent.tsx b/src/Components/Displays/DisplayComponent.tsx index ec98caa..292c899 100644 --- a/src/Components/Displays/DisplayComponent.tsx +++ b/src/Components/Displays/DisplayComponent.tsx @@ -17,22 +17,30 @@ interface CustomComponentProps { lines: LineProps[] } -const Line: React.FC = ({ text }) =>
{text}
+const Line: React.FC = ({ text }) => ( +
{text}
+) const CustomComponent: React.FC = ({ imageProps, headerText, lines }) => { const { imageUrl, colorPalette } = imageProps return ( -
-
- -
-
-

{headerText}

+
+ +
+

{headerText}

{lines.map((line, index) => ( ))} diff --git a/src/Components/Displays/StatDisplays.tsx b/src/Components/Displays/StatDisplays.tsx index 769fc57..9df3b7b 100644 --- a/src/Components/Displays/StatDisplays.tsx +++ b/src/Components/Displays/StatDisplays.tsx @@ -36,10 +36,8 @@ const StatBoxComponent: React.FC = ({ sliderValues, colorPalette, trans } return ( -
-
-
- + = ({ sliderValues, colorPalette, trans { text: 'Mining Speed : ' + sliderValues.mining_speed } ]} /> -
-
= ({ sliderValues, colorPalette, trans headerText={translation + 'Helmet'} lines={[ { - text: 'Armor : ' + Math.floor(sliderValues.hardness / 2).toFixed(2) + text: 'Armor : ' + Math.floor(sliderValues.hardness / 2).toFixed(2) }, { text: @@ -112,7 +108,7 @@ const StatBoxComponent: React.FC = ({ sliderValues, colorPalette, trans headerText={translation + 'Chestplate'} lines={[ { - text: 'Armor : ' + (sliderValues.hardness + 2 - Math.ceil(sliderValues.flexibility / 4)).toFixed(2) + text: 'Armor : ' + (sliderValues.hardness + 2 - Math.ceil(sliderValues.flexibility / 4)).toFixed(2) }, { text: @@ -145,7 +141,7 @@ const StatBoxComponent: React.FC = ({ sliderValues, colorPalette, trans lines={[ { text: - 'Armor : ' + + 'Armor : ' + (((sliderValues.hardness - Math.ceil(sliderValues.hardness / 6.5) + Math.ceil(sliderValues.hardness / 4.5) - 1) / 7) * 7).toFixed(2) }, { @@ -178,7 +174,7 @@ const StatBoxComponent: React.FC = ({ sliderValues, colorPalette, trans headerText={translation + 'Boots'} lines={[ { - text: 'Armor : ' + Math.floor(sliderValues.hardness / 2 - Math.floor(sliderValues.density / 4)).toFixed(2) + text: 'Armor : ' + Math.floor(sliderValues.hardness / 2 - Math.floor(sliderValues.density / 4)).toFixed(2) }, { text: @@ -202,8 +198,6 @@ const StatBoxComponent: React.FC = ({ sliderValues, colorPalette, trans } ]} /> -
-
) } diff --git a/src/Components/Load/FileUploadButton.tsx b/src/Components/Load/FileUploadButton.tsx index 7b18b49..2f0afd8 100644 --- a/src/Components/Load/FileUploadButton.tsx +++ b/src/Components/Load/FileUploadButton.tsx @@ -39,25 +39,25 @@ const FileUpload: React.FC = ({ onWarning, is121Plus }) => { const apiFileCacheKey = `miapi-material-file-cache-v1:${versionLabel}` const buttonStyle = { - padding: '0 12px', - margin: '5px', - backgroundColor: '#7289DA', - color: '#ffffff', - border: 'none', - borderRadius: '5px', + padding: '0 14px', + margin: '0', + backgroundColor: 'var(--input-bg)', + color: 'var(--text)', + border: '1px solid var(--input-border)', + borderRadius: '7px', cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', - fontSize: '13px', + fontSize: '12.5px', fontFamily: 'inherit', fontWeight: 600, lineHeight: 1.1, - minHeight: '42px', - height: '42px', - minWidth: '180px', - width: '180px', - maxWidth: '180px', + minHeight: '36px', + height: '36px', + minWidth: '150px', + width: '150px', + maxWidth: '150px', boxSizing: 'border-box' as const, whiteSpace: 'nowrap', textAlign: 'center' as const, @@ -400,20 +400,24 @@ const FileUpload: React.FC = ({ onWarning, is121Plus }) => { background: 'transparent', border: 'none', padding: '4px 0', - color: '#f2f2f2', - fontWeight: 600, + color: 'var(--accent)', + fontWeight: 700, + textTransform: 'uppercase', + letterSpacing: '.06em', textAlign: 'left', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '6px', fontFamily: 'inherit', - fontSize: '13px' + fontSize: '11px' }} > - {isExpanded ? '▾' : '▸'} + {isExpanded ? '▾' : '▸'} {node.name} - {node.path} + + {node.path} + {isExpanded && (
{renderTree(node.children, depth + 1)}
@@ -442,21 +446,21 @@ const FileUpload: React.FC = ({ onWarning, is121Plus }) => { }} disabled={isDisabledEntry} style={{ - background: isDisabledEntry ? '#2b2f36' : '#36393f', - color: isDisabledEntry ? '#9aa0a6' : '#fff', - border: isDisabledEntry ? '1px dashed #4f545c' : '1px solid #4f545c', - borderRadius: '6px', - padding: '6px 8px', + background: isDisabledEntry ? '#1d1f23' : 'var(--input-bg)', + color: isDisabledEntry ? 'var(--text-muted)' : 'var(--text)', + border: isDisabledEntry ? '1px dashed var(--input-border)' : '1px solid var(--input-border)', + borderRadius: '7px', + padding: '7px 9px', textAlign: 'left', cursor: isDisabledEntry ? 'not-allowed' : 'pointer', marginLeft: depth * 8, - fontSize: '13px', + fontSize: '12.5px', opacity: isDisabledEntry ? 0.85 : 1 }} > - {node.materialId || `miapi:${node.path.replace(/\.json$/, '')}`} - {node.path} - {isDisabledEntry && Child material} +
{node.materialId || `miapi:${node.path.replace(/\.json$/, '')}`}
+
{node.path}
+ {isDisabledEntry &&
Child material
} ) }) @@ -469,7 +473,7 @@ const FileUpload: React.FC = ({ onWarning, is121Plus }) => { return (
-
)}
- {filename} + {filename}
) diff --git a/src/Components/Load/LoadDataProvider.tsx b/src/Components/Load/LoadDataProvider.tsx index e41ede1..7de3ddd 100644 --- a/src/Components/Load/LoadDataProvider.tsx +++ b/src/Components/Load/LoadDataProvider.tsx @@ -1,4 +1,4 @@ -import React, { createContext, useState, useContext, ReactNode } from 'react' +import React, { createContext, useState, useContext, useCallback, useMemo, ReactNode } from 'react' interface LoadDataContextType { loadData: any | null @@ -23,27 +23,34 @@ const LoadDataProvider: React.FC<{ children: ReactNode }> = ({ children }) => { const [loadData, setLoadData] = useState(null) const [listeners, setListeners] = useState<((message: string, color: string) => void)[]>([]) - const addWarning = (message: string) => { - listeners.forEach((listener) => listener(message, 'orange')) - } + const addWarning = useCallback( + (message: string) => { + listeners.forEach((listener) => listener(message, 'orange')) + }, + [listeners] + ) - const addCustomMessage = (message: string, color: string) => { - listeners.forEach((listener) => listener(message, color)) - } + const addCustomMessage = useCallback( + (message: string, color: string) => { + listeners.forEach((listener) => listener(message, color)) + }, + [listeners] + ) - const registerWarningListener = (callback: (message: string, color: string) => void) => { + const registerWarningListener = useCallback((callback: (message: string, color: string) => void) => { setListeners((prevListeners) => [...prevListeners, callback]) - } + }, []) - const clearWarningListeners = () => { + const clearWarningListeners = useCallback(() => { setListeners([]) - } + }, []) - return ( - - {children} - + const contextValue = useMemo( + () => ({ loadData, setLoadData, addWarning, addCustomMessage, registerWarningListener, clearWarningListeners }), + [loadData, addWarning, addCustomMessage, registerWarningListener, clearWarningListeners] ) + + return {children} } export default LoadDataProvider diff --git a/src/Components/SelfDeletingWarning.tsx b/src/Components/SelfDeletingWarning.tsx index c2a3661..e0b78f3 100644 --- a/src/Components/SelfDeletingWarning.tsx +++ b/src/Components/SelfDeletingWarning.tsx @@ -7,6 +7,19 @@ interface WarningProps { color: string } +const dotColorFor = (color: string): string => { + switch (color) { + case "red": + return "var(--red)" + case "green": + return "var(--green)" + case "orange": + return "var(--orange)" + default: + return color || "var(--accent)" + } +} + const Warning: React.FC = ({ id, message, onRemove, color }) => { useEffect(() => { const timeoutId = setTimeout(() => { @@ -17,15 +30,15 @@ const Warning: React.FC = ({ id, message, onRemove, color }) => { }, [id, onRemove]) return ( -
- {message} +
+
+
{message}
+
) } diff --git a/src/Components/Sliders/HighLimitSliderEntry.tsx b/src/Components/Sliders/HighLimitSliderEntry.tsx index 32bc5f4..e826418 100644 --- a/src/Components/Sliders/HighLimitSliderEntry.tsx +++ b/src/Components/Sliders/HighLimitSliderEntry.tsx @@ -8,16 +8,32 @@ interface HighLimitSliderEntryProps { const HighLimitSliderEntry: React.FC = ({ label, value, onChange }) => { return ( -
-
) diff --git a/src/Components/Sliders/IntegerSliderEntry.tsx b/src/Components/Sliders/IntegerSliderEntry.tsx index 9f07c56..fe5239e 100644 --- a/src/Components/Sliders/IntegerSliderEntry.tsx +++ b/src/Components/Sliders/IntegerSliderEntry.tsx @@ -39,70 +39,55 @@ const IntegerSliderEntry: React.FC = ({ } } - return ( -
- {editableLabel ? ( + const rangeInput = ( + { + onChange(parseInt(e.target.value, 10)) + }} + min={0} + max={5} + style={{ accentColor: "var(--accent)", flex: 1, width: "100%" }} + /> + ) + + const textInput = ( + { + textParse(e.target.value) + }} + className="field-input" + style={{ width: editableLabel ? "64px" : "70px", flexShrink: 0, fontFamily: "ui-monospace, Menlo, monospace", padding: "6px 8px" }} + /> + ) + + if (editableLabel) { + return ( +
{ - onLabelChange?.(event.target.value) - }} + onChange={(event) => onLabelChange?.(event.target.value)} + className="field-input" + style={{ width: "120px", flexShrink: 0, padding: "6px 8px", fontSize: "12px" }} /> - ) : ( - - )} - { - onChange(parseInt(e.target.value, 10)) - }} - min={0} - max={5} - style={{ - backgroundColor: "transparent", - width: editableLabel ? "62%" : "60%", - height: "50%", - }} - /> -
- { - textParse(e.target.value) - }} - min={0} - max={15} - style={{ - backgroundColor: "var(--discord-gray-3)", - color: "var(--discord-white)", - border: "none", - width: "10%", - }} - /> + {rangeInput} + {textInput} +
+ ) + } + + return ( +
+
+ {label} + {textInput} +
+ {rangeInput}
) } diff --git a/src/Components/Sliders/SingleSlider.tsx b/src/Components/Sliders/SingleSlider.tsx index ff8290e..d492c60 100644 --- a/src/Components/Sliders/SingleSlider.tsx +++ b/src/Components/Sliders/SingleSlider.tsx @@ -38,65 +38,52 @@ const SingleSlider: React.FC = ({ label, value, onChange, edi setText('' + parseFloat(test)) } - return ( -
- {editableLabel ? ( + const rangeInput = ( + ) => sliderUpdate(e.target.value)} + min={0} + max={15} + step={0.01} // Set a step value to allow for two decimal places + style={{ accentColor: 'var(--accent)', flex: 1, width: '100%' }} + /> + ) + + const textInput = ( + ) => textParse(e.target.value)} + className="field-input" + style={{ width: editableLabel ? '64px' : '70px', flexShrink: 0, fontFamily: 'ui-monospace, Menlo, monospace', padding: '6px 8px' }} + /> + ) + + if (editableLabel) { + return ( +
{ - onLabelChange?.(event.target.value) - }} + onChange={(event) => onLabelChange?.(event.target.value)} + className="field-input" + style={{ width: '120px', flexShrink: 0, padding: '6px 8px', fontSize: '12px' }} /> - ) : ( - - )} - ) => sliderUpdate(e.target.value)} - min={0} - max={15} - step={0.01} // Set a step value to allow for two decimal places - style={{ - backgroundColor: 'transparent', - width: editableLabel ? '62%' : '60%', - height: '50%' - }} - /> -
- ) => textParse(e.target.value)} - style={{ - backgroundColor: 'var(--discord-gray-3)', - color: 'var(--discord-white)', - border: 'none', - width: '10%' - }} - /> + {rangeInput} + {textInput} +
+ ) + } + + return ( +
+
+ {label} + {textInput} +
+ {rangeInput}
) } diff --git a/src/Components/Sliders/SliderEntry.tsx b/src/Components/Sliders/SliderEntry.tsx index cc10555..53f8800 100644 --- a/src/Components/Sliders/SliderEntry.tsx +++ b/src/Components/Sliders/SliderEntry.tsx @@ -264,9 +264,20 @@ const SliderEntry: React.FC = ({ onSubmit, is121Plus }) => { } return ( -
-
+
+ {sliderComponent}
) @@ -288,38 +300,32 @@ const SliderEntry: React.FC = ({ onSubmit, is121Plus }) => { } return ( -
- handleSliderChange('hardness', value)} /> - handleSliderChange('density', value)} /> - handleSliderChange('flexibility', value)} /> - handleSliderChange('durability', value)} /> - handleSliderChange('mining_speed', value)} /> - {is121Plus ? ( - handleSliderChange('mining_level', value)} - editableLabel={false} - /> - ) : ( - handleSliderChange('mining_level', value)} - /> - )} - - {renderCustomSliders()} -
+
+
+ handleSliderChange('hardness', value)} /> + handleSliderChange('density', value)} /> + handleSliderChange('flexibility', value)} /> + handleSliderChange('durability', value)} /> + handleSliderChange('mining_speed', value)} /> + {is121Plus ? ( + handleSliderChange('mining_level', value)} + editableLabel={false} + /> + ) : ( + handleSliderChange('mining_level', value)} + /> + )} +
+ +
{renderCustomSliders()}
+ +
{isDropdownOpen && (
-
    - {Object.keys(CustomSliderType) - .filter((key) => isNaN(Number(key))) - .map((key) => ( -
  • { - let uuid - do { - uuid = generateId() - } while (customSliders[uuid] !== undefined) - setCustomSliders({ - ...customSliders, - [uuid]: { - id: uuid, - name: 'new', - value: key === 'STRING' ? '' : 0, - type: CustomSliderType[key as keyof typeof CustomSliderType] - } - }) - setIsDropdownOpen(false) - }} - className="dropdown-item" - > - {key} -
  • - ))} -
+ {Object.keys(CustomSliderType) + .filter((key) => isNaN(Number(key))) + .map((key) => ( +
{ + let uuid + do { + uuid = generateId() + } while (customSliders[uuid] !== undefined) + setCustomSliders({ + ...customSliders, + [uuid]: { + id: uuid, + name: 'new', + value: key === 'STRING' ? '' : 0, + type: CustomSliderType[key as keyof typeof CustomSliderType] + } + }) + setIsDropdownOpen(false) + }} + className="dropdown-item" + style={{ textTransform: 'capitalize' }} + > + {key.toLowerCase()} +
+ ))}
)}
@@ -393,8 +401,8 @@ export default SliderEntry const DeleteIcon = (props: any) => ( = ({ editableLabel, onLabelChange, }) => { - return ( -
- {editableLabel ? ( + const valueInput = ( + { + onChange(e.target.value) + }} + className="field-input" + style={{ flex: 1, fontFamily: "ui-monospace, Menlo, monospace", fontSize: "12.5px", padding: editableLabel ? "6px 8px" : undefined }} + /> + ) + + if (editableLabel) { + return ( +
{ - onLabelChange?.(event.target.value) - }} + onChange={(event) => onLabelChange?.(event.target.value)} + className="field-input" + style={{ width: "120px", flexShrink: 0, padding: "6px 8px", fontSize: "12px" }} /> - ) : ( - - )} - { - onChange(e.target.value) - }} - style={{ - backgroundColor: "var(--discord-gray-3)", - color: "var(--discord-white)", - border: "none", - width: "100%", - }} - /> + {valueInput} +
+ ) + } + + return ( +
+
+ {label} +
+ {valueInput}
) } diff --git a/src/Components/TextInputs/MaterialDisplayName.tsx b/src/Components/TextInputs/MaterialDisplayName.tsx index cc38148..3b5fd56 100644 --- a/src/Components/TextInputs/MaterialDisplayName.tsx +++ b/src/Components/TextInputs/MaterialDisplayName.tsx @@ -34,34 +34,11 @@ const MaterialDisplayName: React.FC = ({ onSubmit }) = } return ( -
-