local Rojo = script:FindFirstAncestor("Rojo") local Plugin = Rojo.Plugin local Packages = Rojo.Packages local Roact = require(Packages.Roact) local Settings = require(Plugin.Settings) local Assets = require(Plugin.Assets) local Theme = require(Plugin.App.Theme) local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync) local Checkbox = require(Plugin.App.Components.Checkbox) local Dropdown = require(Plugin.App.Components.Dropdown) local IconButton = require(Plugin.App.Components.IconButton) local Tag = require(Plugin.App.Components.Tag) local e = Roact.createElement local DIVIDER_FADE_SIZE = 0.1 local TAG_TYPES = { unstable = { text = "UNSTABLE", icon = Assets.Images.Icons.Warning, color = { "Settings", "Setting", "UnstableColor" }, }, debug = { text = "DEBUG", icon = Assets.Images.Icons.Debug, color = { "Settings", "Setting", "DebugColor" }, }, } local function getTextBoundsWithLineHeight( text: string, font: Font, textSize: number, width: number, lineHeight: number ) local textBounds = getTextBoundsAsync(text, font, textSize, width) local lineCount = math.ceil(textBounds.Y / textSize) local lineHeightAbsolute = textSize * lineHeight return Vector2.new(textBounds.X, lineHeightAbsolute * lineCount - (lineHeightAbsolute - textSize)) end local function getThemeColorFromPath(theme, path) local color = theme for _, key in path do if color[key] == nil then return theme.BrandColor end color = color[key] end return color end local Setting = Roact.Component:extend("Setting") function Setting:init() self.contentSize, self.setContentSize = Roact.createBinding(Vector2.new(0, 0)) self.containerSize, self.setContainerSize = Roact.createBinding(Vector2.new(0, 0)) self.inputSize, self.setInputSize = Roact.createBinding(Vector2.new(0, 0)) self:setState({ setting = Settings:get(self.props.id), }) self.changedCleanup = Settings:onChanged(self.props.id, function(value) self:setState({ setting = value, }) end) end function Setting:willUnmount() self.changedCleanup() end function Setting:render() return Theme.with(function(theme) local settingsTheme = theme.Settings return e("Frame", { Size = self.contentSize:map(function(value) return UDim2.new(1, 0, 0, value.Y + 20) end), LayoutOrder = self.props.layoutOrder, ZIndex = -self.props.layoutOrder, BackgroundTransparency = 1, Visible = self.props.visible, [Roact.Change.AbsoluteSize] = function(object) self.setContainerSize(object.AbsoluteSize) end, }, { RightAligned = Roact.createElement("Frame", { BackgroundTransparency = 1, Size = UDim2.new(1, 0, 1, 0), }, { Layout = e("UIListLayout", { VerticalAlignment = Enum.VerticalAlignment.Center, HorizontalAlignment = Enum.HorizontalAlignment.Right, FillDirection = Enum.FillDirection.Horizontal, SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, 2), [Roact.Change.AbsoluteContentSize] = function(rbx) self.setInputSize(rbx.AbsoluteContentSize) end, }), Input = if self.props.input ~= nil then self.props.input elseif self.props.options ~= nil then e(Dropdown, { locked = self.props.locked, lockedTooltip = self.props.lockedTooltip, options = self.props.options, active = self.state.setting, transparency = self.props.transparency, onClick = function(option) Settings:set(self.props.id, option) end, }) else e(Checkbox, { locked = self.props.locked, lockedTooltip = self.props.lockedTooltip, active = self.state.setting, transparency = self.props.transparency, onClick = function() local currentValue = Settings:get(self.props.id) Settings:set(self.props.id, not currentValue) end, }), Reset = if self.props.onReset then e(IconButton, { icon = Assets.Images.Icons.Reset, iconSize = 24, color = settingsTheme.BackButtonColor, transparency = self.props.transparency, visible = self.props.showReset, layoutOrder = -1, onClick = self.props.onReset, }) else nil, }), Text = e("Frame", { Size = UDim2.new(1, 0, 1, 0), BackgroundTransparency = 1, }, { Heading = e("Frame", { Size = UDim2.new(1, 0, 0, theme.TextSize.Medium), BackgroundTransparency = 1, }, { Layout = e("UIListLayout", { VerticalAlignment = Enum.VerticalAlignment.Center, FillDirection = Enum.FillDirection.Horizontal, SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, 5), }), Tag = if self.props.tag and TAG_TYPES[self.props.tag] then e(Tag, { layoutOrder = 1, transparency = self.props.transparency, text = TAG_TYPES[self.props.tag].text, icon = TAG_TYPES[self.props.tag].icon, color = getThemeColorFromPath(theme, TAG_TYPES[self.props.tag].color), }) else nil, Name = e("TextLabel", { Text = self.props.name, FontFace = theme.Font.Bold, TextSize = theme.TextSize.Medium, TextColor3 = if self.props.tag and TAG_TYPES[self.props.tag] then getThemeColorFromPath(theme, TAG_TYPES[self.props.tag].color) else settingsTheme.Setting.NameColor, TextXAlignment = Enum.TextXAlignment.Left, TextTransparency = self.props.transparency, RichText = true, Size = UDim2.new(1, 0, 0, theme.TextSize.Medium), LayoutOrder = 2, BackgroundTransparency = 1, }), }), Description = e("TextLabel", { Text = self.props.description, FontFace = theme.Font.Main, LineHeight = 1.2, TextSize = theme.TextSize.Body, TextColor3 = settingsTheme.Setting.DescriptionColor, TextXAlignment = Enum.TextXAlignment.Left, TextTransparency = self.props.transparency, TextWrapped = true, RichText = true, Size = Roact.joinBindings({ containerSize = self.containerSize, inputSize = self.inputSize, }):map(function(values) local offset = values.inputSize.X + 5 local textBounds = getTextBoundsWithLineHeight( self.props.description, theme.Font.Main, theme.TextSize.Body, values.containerSize.X - offset, 1.2 ) return UDim2.new(1, -offset, 0, textBounds.Y) end), LayoutOrder = 3, BackgroundTransparency = 1, }), Layout = e("UIListLayout", { VerticalAlignment = Enum.VerticalAlignment.Center, FillDirection = Enum.FillDirection.Vertical, SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, 5), [Roact.Change.AbsoluteContentSize] = function(object) self.setContentSize(object.AbsoluteContentSize) end, }), }), Divider = e("Frame", { BackgroundColor3 = settingsTheme.DividerColor, BackgroundTransparency = self.props.transparency, Size = UDim2.new(1, 0, 0, 1), BorderSizePixel = 0, }, { Gradient = e("UIGradient", { Transparency = NumberSequence.new({ NumberSequenceKeypoint.new(0, 1), NumberSequenceKeypoint.new(DIVIDER_FADE_SIZE, 0), NumberSequenceKeypoint.new(1 - DIVIDER_FADE_SIZE, 0), NumberSequenceKeypoint.new(1, 1), }), }), }), }) end) end return Setting