Dynamic theming. Closes #241.

Upgrades to Roact master and introduces dynamic theme switching.

We branch on the theme name in order to try to use Rojo's brand
colors instead of Studio's. I kind of winged it with these colors
and we might want to choose slightly nicer dark theme colors
in the future.

I also took the opportunity to reorganize the color naming scheme
since it didn't really work for dark theme.
This commit is contained in:
Lucien Greathouse
2020-03-08 18:32:42 -07:00
parent 04529de7b3
commit 3107b1b21b
13 changed files with 455 additions and 346 deletions

View File

@@ -13,6 +13,7 @@ local Version = require(Plugin.Version)
local preloadAssets = require(Plugin.preloadAssets) local preloadAssets = require(Plugin.preloadAssets)
local strict = require(Plugin.strict) local strict = require(Plugin.strict)
local Theme = require(Plugin.Components.Theme)
local ConnectPanel = require(Plugin.Components.ConnectPanel) local ConnectPanel = require(Plugin.Components.ConnectPanel)
local ConnectingPanel = require(Plugin.Components.ConnectingPanel) local ConnectingPanel = require(Plugin.Components.ConnectingPanel)
local ConnectionActivePanel = require(Plugin.Components.ConnectionActivePanel) local ConnectionActivePanel = require(Plugin.Components.ConnectionActivePanel)
@@ -199,9 +200,11 @@ function App:render()
} }
end end
return Roact.createElement(Roact.Portal, { return Roact.createElement(Theme.StudioProvider, nil, {
target = self.dockWidget, UI = Roact.createElement(Roact.Portal, {
}, children) target = self.dockWidget,
}, children),
})
end end
function App:didMount() function App:didMount()

View File

@@ -4,8 +4,8 @@ local Plugin = Rojo.Plugin
local Roact = require(Rojo.Roact) local Roact = require(Rojo.Roact)
local Config = require(Plugin.Config) local Config = require(Plugin.Config)
local Theme = require(Plugin.Theme)
local Theme = require(Plugin.Components.Theme)
local Panel = require(Plugin.Components.Panel) local Panel = require(Plugin.Components.Panel)
local FitList = require(Plugin.Components.FitList) local FitList = require(Plugin.Components.FitList)
local FitText = require(Plugin.Components.FitText) local FitText = require(Plugin.Components.FitText)
@@ -26,136 +26,138 @@ end
function ConnectPanel:render() function ConnectPanel:render()
local startSession = self.props.startSession local startSession = self.props.startSession
return e(Panel, nil, { return Theme.with(function(theme)
Layout = e("UIListLayout", { return e(Panel, nil, {
SortOrder = Enum.SortOrder.LayoutOrder, Layout = e("UIListLayout", {
HorizontalAlignment = Enum.HorizontalAlignment.Center, SortOrder = Enum.SortOrder.LayoutOrder,
VerticalAlignment = Enum.VerticalAlignment.Center, HorizontalAlignment = Enum.HorizontalAlignment.Center,
}), VerticalAlignment = Enum.VerticalAlignment.Center,
}),
Inputs = e(FitList, { Inputs = e(FitList, {
containerProps = {
BackgroundTransparency = 1,
LayoutOrder = 1,
},
layoutProps = {
FillDirection = Enum.FillDirection.Horizontal,
Padding = UDim.new(0, 8),
},
paddingProps = {
PaddingTop = UDim.new(0, 20),
PaddingBottom = UDim.new(0, 10),
PaddingLeft = UDim.new(0, 24),
PaddingRight = UDim.new(0, 24),
},
}, {
Address = e(FitList, {
containerProps = { containerProps = {
LayoutOrder = 1,
BackgroundTransparency = 1, BackgroundTransparency = 1,
LayoutOrder = 1,
}, },
layoutProps = { layoutProps = {
Padding = UDim.new(0, 4), FillDirection = Enum.FillDirection.Horizontal,
Padding = UDim.new(0, 8),
},
paddingProps = {
PaddingTop = UDim.new(0, 20),
PaddingBottom = UDim.new(0, 10),
PaddingLeft = UDim.new(0, 24),
PaddingRight = UDim.new(0, 24),
}, },
}, { }, {
Label = e(FitText, { Address = e(FitList, {
Kind = "TextLabel", containerProps = {
LayoutOrder = 1, LayoutOrder = 1,
BackgroundTransparency = 1, BackgroundTransparency = 1,
TextXAlignment = Enum.TextXAlignment.Left, },
Font = Theme.TitleFont, layoutProps = {
TextSize = 20, Padding = UDim.new(0, 4),
Text = "Address", },
TextColor3 = Theme.PrimaryColor, }, {
Label = e(FitText, {
Kind = "TextLabel",
LayoutOrder = 1,
BackgroundTransparency = 1,
TextXAlignment = Enum.TextXAlignment.Left,
Font = theme.TitleFont,
TextSize = 20,
Text = "Address",
TextColor3 = theme.Text1,
}),
Input = e(FormTextInput, {
layoutOrder = 2,
width = UDim.new(0, 220),
value = self.state.address,
placeholderValue = Config.defaultHost,
onValueChange = function(newValue)
self:setState({
address = newValue,
})
end,
}),
}), }),
Input = e(FormTextInput, { Port = e(FitList, {
layoutOrder = 2, containerProps = {
width = UDim.new(0, 220), LayoutOrder = 2,
value = self.state.address, BackgroundTransparency = 1,
placeholderValue = Config.defaultHost, },
onValueChange = function(newValue) layoutProps = {
self:setState({ Padding = UDim.new(0, 4),
address = newValue, },
}) }, {
end, Label = e(FitText, {
Kind = "TextLabel",
LayoutOrder = 1,
BackgroundTransparency = 1,
TextXAlignment = Enum.TextXAlignment.Left,
Font = theme.TitleFont,
TextSize = 20,
Text = "Port",
TextColor3 = theme.Text1,
}),
Input = e(FormTextInput, {
layoutOrder = 2,
width = UDim.new(0, 80),
value = self.state.port,
placeholderValue = Config.defaultPort,
onValueChange = function(newValue)
self:setState({
port = newValue,
})
end,
}),
}), }),
}), }),
Port = e(FitList, { Buttons = e(FitList, {
fitAxes = "Y",
containerProps = { containerProps = {
BackgroundTransparency = 1,
LayoutOrder = 2, LayoutOrder = 2,
BackgroundTransparency = 1, Size = UDim2.new(1, 0, 0, 0),
}, },
layoutProps = { layoutProps = {
Padding = UDim.new(0, 4), FillDirection = Enum.FillDirection.Horizontal,
HorizontalAlignment = Enum.HorizontalAlignment.Right,
Padding = UDim.new(0, 8),
},
paddingProps = {
PaddingTop = UDim.new(0, 0),
PaddingBottom = UDim.new(0, 20),
PaddingLeft = UDim.new(0, 24),
PaddingRight = UDim.new(0, 24),
}, },
}, { }, {
Label = e(FitText, { e(FormButton, {
Kind = "TextLabel",
LayoutOrder = 1,
BackgroundTransparency = 1,
TextXAlignment = Enum.TextXAlignment.Left,
Font = Theme.TitleFont,
TextSize = 20,
Text = "Port",
TextColor3 = Theme.PrimaryColor,
}),
Input = e(FormTextInput, {
layoutOrder = 2, layoutOrder = 2,
width = UDim.new(0, 80), text = "Connect",
value = self.state.port, onClick = function()
placeholderValue = Config.defaultPort, if startSession ~= nil then
onValueChange = function(newValue) local address = self.state.address
self:setState({ if address:len() == 0 then
port = newValue, address = Config.defaultHost
}) end
local port = self.state.port
if port:len() == 0 then
port = Config.defaultPort
end
startSession(address, port)
end
end, end,
}), }),
}), }),
}), })
end)
Buttons = e(FitList, {
fitAxes = "Y",
containerProps = {
BackgroundTransparency = 1,
LayoutOrder = 2,
Size = UDim2.new(1, 0, 0, 0),
},
layoutProps = {
FillDirection = Enum.FillDirection.Horizontal,
HorizontalAlignment = Enum.HorizontalAlignment.Right,
Padding = UDim.new(0, 8),
},
paddingProps = {
PaddingTop = UDim.new(0, 0),
PaddingBottom = UDim.new(0, 20),
PaddingLeft = UDim.new(0, 24),
PaddingRight = UDim.new(0, 24),
},
}, {
e(FormButton, {
layoutOrder = 2,
text = "Connect",
onClick = function()
if startSession ~= nil then
local address = self.state.address
if address:len() == 0 then
address = Config.defaultHost
end
local port = self.state.port
if port:len() == 0 then
port = Config.defaultPort
end
startSession(address, port)
end
end,
}),
}),
})
end end
return ConnectPanel return ConnectPanel

View File

@@ -2,8 +2,7 @@ local Roact = require(script:FindFirstAncestor("Rojo").Roact)
local Plugin = script:FindFirstAncestor("Plugin") local Plugin = script:FindFirstAncestor("Plugin")
local Theme = require(Plugin.Theme) local Theme = require(Plugin.Components.Theme)
local Panel = require(Plugin.Components.Panel) local Panel = require(Plugin.Components.Panel)
local FitText = require(Plugin.Components.FitText) local FitText = require(Plugin.Components.FitText)
@@ -12,23 +11,25 @@ local e = Roact.createElement
local ConnectingPanel = Roact.Component:extend("ConnectingPanel") local ConnectingPanel = Roact.Component:extend("ConnectingPanel")
function ConnectingPanel:render() function ConnectingPanel:render()
return e(Panel, nil, { return Theme.with(function(theme)
Layout = Roact.createElement("UIListLayout", { return e(Panel, nil, {
HorizontalAlignment = Enum.HorizontalAlignment.Center, Layout = Roact.createElement("UIListLayout", {
VerticalAlignment = Enum.VerticalAlignment.Center, HorizontalAlignment = Enum.HorizontalAlignment.Center,
SortOrder = Enum.SortOrder.LayoutOrder, VerticalAlignment = Enum.VerticalAlignment.Center,
Padding = UDim.new(0, 8), SortOrder = Enum.SortOrder.LayoutOrder,
}), Padding = UDim.new(0, 8),
}),
Text = e(FitText, { Text = e(FitText, {
Padding = Vector2.new(12, 6), Padding = Vector2.new(12, 6),
Font = Theme.ButtonFont, Font = theme.ButtonFont,
TextSize = 18, TextSize = 18,
Text = "Connecting...", Text = "Connecting...",
TextColor3 = Theme.PrimaryColor, TextColor3 = theme.Text1,
BackgroundTransparency = 1, BackgroundTransparency = 1,
}), }),
}) })
end)
end end
return ConnectingPanel return ConnectingPanel

View File

@@ -2,8 +2,7 @@ local Roact = require(script:FindFirstAncestor("Rojo").Roact)
local Plugin = script:FindFirstAncestor("Plugin") local Plugin = script:FindFirstAncestor("Plugin")
local Theme = require(Plugin.Theme) local Theme = require(Plugin.Components.Theme)
local Panel = require(Plugin.Components.Panel) local Panel = require(Plugin.Components.Panel)
local FitText = require(Plugin.Components.FitText) local FitText = require(Plugin.Components.FitText)
local FormButton = require(Plugin.Components.FormButton) local FormButton = require(Plugin.Components.FormButton)
@@ -15,32 +14,34 @@ local ConnectionActivePanel = Roact.Component:extend("ConnectionActivePanel")
function ConnectionActivePanel:render() function ConnectionActivePanel:render()
local stopSession = self.props.stopSession local stopSession = self.props.stopSession
return e(Panel, nil, { return Theme.with(function(theme)
Layout = Roact.createElement("UIListLayout", { return e(Panel, nil, {
HorizontalAlignment = Enum.HorizontalAlignment.Center, Layout = Roact.createElement("UIListLayout", {
VerticalAlignment = Enum.VerticalAlignment.Center, HorizontalAlignment = Enum.HorizontalAlignment.Center,
SortOrder = Enum.SortOrder.LayoutOrder, VerticalAlignment = Enum.VerticalAlignment.Center,
Padding = UDim.new(0, 8), SortOrder = Enum.SortOrder.LayoutOrder,
}), Padding = UDim.new(0, 8),
}),
Text = e(FitText, { Text = e(FitText, {
Padding = Vector2.new(12, 6), Padding = Vector2.new(12, 6),
Font = Theme.ButtonFont, Font = theme.ButtonFont,
TextSize = 18, TextSize = 18,
Text = "Connected to Live-Sync Server", Text = "Connected to Live-Sync Server",
TextColor3 = Theme.PrimaryColor, TextColor3 = theme.Text1,
BackgroundTransparency = 1, BackgroundTransparency = 1,
}), }),
DisconnectButton = e(FormButton, { DisconnectButton = e(FormButton, {
layoutOrder = 2, layoutOrder = 2,
text = "Disconnect", text = "Disconnect",
secondary = true, secondary = true,
onClick = function() onClick = function()
stopSession() stopSession()
end, end,
}), }),
}) })
end)
end end
return ConnectionActivePanel return ConnectionActivePanel

View File

@@ -2,8 +2,7 @@ local Roact = require(script:FindFirstAncestor("Rojo").Roact)
local Plugin = script:FindFirstAncestor("Plugin") local Plugin = script:FindFirstAncestor("Plugin")
local Theme = require(Plugin.Theme) local Theme = require(Plugin.Components.Theme)
local Panel = require(Plugin.Components.Panel) local Panel = require(Plugin.Components.Panel)
local FitText = require(Plugin.Components.FitText) local FitText = require(Plugin.Components.FitText)
local FitScrollingFrame = require(Plugin.Components.FitScrollingFrame) local FitScrollingFrame = require(Plugin.Components.FitScrollingFrame)
@@ -20,50 +19,52 @@ function ErrorPanel:render()
local errorMessage = self.props.errorMessage local errorMessage = self.props.errorMessage
local onDismiss = self.props.onDismiss local onDismiss = self.props.onDismiss
return e(Panel, nil, { return Theme.with(function(theme)
Layout = Roact.createElement("UIListLayout", { return e(Panel, nil, {
HorizontalAlignment = Enum.HorizontalAlignment.Center, Layout = Roact.createElement("UIListLayout", {
VerticalAlignment = Enum.VerticalAlignment.Center, HorizontalAlignment = Enum.HorizontalAlignment.Center,
SortOrder = Enum.SortOrder.LayoutOrder, VerticalAlignment = Enum.VerticalAlignment.Center,
Padding = UDim.new(0, 8), SortOrder = Enum.SortOrder.LayoutOrder,
}), Padding = UDim.new(0, 8),
ErrorContainer = e(FitScrollingFrame, {
containerProps = {
BackgroundTransparency = 1,
BorderSizePixel = 0,
Size = UDim2.new(1, -HOR_PADDING * 2, 1, -BUTTON_HEIGHT),
Position = UDim2.new(0, HOR_PADDING, 0, 0),
ScrollBarImageColor3 = Theme.PrimaryColor,
VerticalScrollBarInset = Enum.ScrollBarInset.ScrollBar,
ScrollingDirection = Enum.ScrollingDirection.Y,
},
}, {
Text = e(FitText, {
Size = UDim2.new(1, 0, 0, 0),
LayoutOrder = 1,
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top,
FitAxis = "Y",
Font = Theme.ButtonFont,
TextSize = 18,
Text = errorMessage,
TextWrap = true,
TextColor3 = Theme.PrimaryColor,
BackgroundTransparency = 1,
}), }),
}),
DismissButton = e(FormButton, { ErrorContainer = e(FitScrollingFrame, {
layoutOrder = 2, containerProps = {
text = "Dismiss", BackgroundTransparency = 1,
secondary = true, BorderSizePixel = 0,
onClick = function() Size = UDim2.new(1, -HOR_PADDING * 2, 1, -BUTTON_HEIGHT),
onDismiss() Position = UDim2.new(0, HOR_PADDING, 0, 0),
end, ScrollBarImageColor3 = theme.Text1,
}), VerticalScrollBarInset = Enum.ScrollBarInset.ScrollBar,
}) ScrollingDirection = Enum.ScrollingDirection.Y,
},
}, {
Text = e(FitText, {
Size = UDim2.new(1, 0, 0, 0),
LayoutOrder = 1,
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top,
FitAxis = "Y",
Font = theme.ButtonFont,
TextSize = 18,
Text = errorMessage,
TextWrap = true,
TextColor3 = theme.Text1,
BackgroundTransparency = 1,
}),
}),
DismissButton = e(FormButton, {
layoutOrder = 2,
text = "Dismiss",
secondary = true,
onClick = function()
onDismiss()
end,
}),
})
end)
end end
return ErrorPanel return ErrorPanel

View File

@@ -4,7 +4,7 @@ local Plugin = Rojo.Plugin
local Roact = require(Rojo.Roact) local Roact = require(Rojo.Roact)
local Assets = require(Plugin.Assets) local Assets = require(Plugin.Assets)
local Theme = require(Plugin.Theme) local Theme = require(Plugin.Components.Theme)
local FitList = require(Plugin.Components.FitList) local FitList = require(Plugin.Components.FitList)
local FitText = require(Plugin.Components.FitText) local FitText = require(Plugin.Components.FitText)
@@ -20,43 +20,45 @@ local function FormButton(props)
local textColor local textColor
local backgroundColor local backgroundColor
if props.secondary then return Theme.with(function(theme)
textColor = Theme.AccentColor if props.secondary then
backgroundColor = Theme.SecondaryColor textColor = theme.Brand1
else backgroundColor = theme.Background2
textColor = Theme.SecondaryColor else
backgroundColor = Theme.AccentColor textColor = theme.TextOnAccent
end backgroundColor = theme.Brand1
end
return e(FitList, { return e(FitList, {
containerKind = "ImageButton", containerKind = "ImageButton",
containerProps = { containerProps = {
LayoutOrder = layoutOrder, LayoutOrder = layoutOrder,
BackgroundTransparency = 1, BackgroundTransparency = 1,
Image = RoundBox.asset, Image = RoundBox.asset,
ImageRectOffset = RoundBox.offset, ImageRectOffset = RoundBox.offset,
ImageRectSize = RoundBox.size, ImageRectSize = RoundBox.size,
SliceCenter = RoundBox.center, SliceCenter = RoundBox.center,
ScaleType = Enum.ScaleType.Slice, ScaleType = Enum.ScaleType.Slice,
ImageColor3 = backgroundColor, ImageColor3 = backgroundColor,
[Roact.Event.Activated] = function() [Roact.Event.Activated] = function()
if onClick ~= nil then if onClick ~= nil then
onClick() onClick()
end end
end, end,
}, },
}, { }, {
Text = e(FitText, { Text = e(FitText, {
Kind = "TextLabel", Kind = "TextLabel",
Text = text, Text = text,
TextSize = 18, TextSize = 18,
TextColor3 = textColor, TextColor3 = textColor,
Font = Theme.ButtonFont, Font = theme.ButtonFont,
Padding = Vector2.new(16, 8), Padding = Vector2.new(16, 8),
BackgroundTransparency = 1, BackgroundTransparency = 1,
}), }),
}) })
end)
end end
return FormButton return FormButton

View File

@@ -4,7 +4,7 @@ local Plugin = Rojo.Plugin
local Roact = require(Rojo.Roact) local Roact = require(Rojo.Roact)
local Assets = require(Plugin.Assets) local Assets = require(Plugin.Assets)
local Theme = require(Plugin.Theme) local Theme = require(Plugin.Components.Theme)
local e = Roact.createElement local e = Roact.createElement
@@ -35,46 +35,48 @@ function FormTextInput:render()
shownPlaceholder = placeholderValue shownPlaceholder = placeholderValue
end end
return e("ImageLabel", { return Theme.with(function(theme)
LayoutOrder = layoutOrder, return e("ImageLabel", {
Image = RoundBox.asset, LayoutOrder = layoutOrder,
ImageRectOffset = RoundBox.offset, Image = RoundBox.asset,
ImageRectSize = RoundBox.size, ImageRectOffset = RoundBox.offset,
ScaleType = Enum.ScaleType.Slice, ImageRectSize = RoundBox.size,
SliceCenter = RoundBox.center, ScaleType = Enum.ScaleType.Slice,
ImageColor3 = Theme.SecondaryColor, SliceCenter = RoundBox.center,
Size = UDim2.new(width.Scale, width.Offset, 0, TEXT_SIZE + PADDING * 2), ImageColor3 = theme.Background2,
BackgroundTransparency = 1, Size = UDim2.new(width.Scale, width.Offset, 0, TEXT_SIZE + PADDING * 2),
}, {
InputInner = e("TextBox", {
BackgroundTransparency = 1, BackgroundTransparency = 1,
Size = UDim2.new(1, -PADDING * 2, 1, -PADDING * 2), }, {
Position = UDim2.new(0.5, 0, 0.5, 0), InputInner = e("TextBox", {
AnchorPoint = Vector2.new(0.5, 0.5), BackgroundTransparency = 1,
Font = Theme.InputFont, Size = UDim2.new(1, -PADDING * 2, 1, -PADDING * 2),
ClearTextOnFocus = false, Position = UDim2.new(0.5, 0, 0.5, 0),
TextXAlignment = Enum.TextXAlignment.Center, AnchorPoint = Vector2.new(0.5, 0.5),
TextSize = TEXT_SIZE, Font = theme.InputFont,
Text = value, ClearTextOnFocus = false,
PlaceholderText = shownPlaceholder, TextXAlignment = Enum.TextXAlignment.Center,
PlaceholderColor3 = Theme.LightTextColor, TextSize = TEXT_SIZE,
TextColor3 = Theme.PrimaryColor, Text = value,
PlaceholderText = shownPlaceholder,
PlaceholderColor3 = theme.Text2,
TextColor3 = theme.Text1,
[Roact.Change.Text] = function(rbx) [Roact.Change.Text] = function(rbx)
onValueChange(rbx.Text) onValueChange(rbx.Text)
end, end,
[Roact.Event.Focused] = function() [Roact.Event.Focused] = function()
self:setState({ self:setState({
focused = true, focused = true,
}) })
end, end,
[Roact.Event.FocusLost] = function() [Roact.Event.FocusLost] = function()
self:setState({ self:setState({
focused = false, focused = false,
}) })
end, end,
}), }),
}) })
end)
end end
return FormTextInput return FormTextInput

View File

@@ -3,6 +3,7 @@ local Roact = require(script:FindFirstAncestor("Rojo").Roact)
local Plugin = script:FindFirstAncestor("Plugin") local Plugin = script:FindFirstAncestor("Plugin")
local RojoFooter = require(Plugin.Components.RojoFooter) local RojoFooter = require(Plugin.Components.RojoFooter)
local Theme = require(Plugin.Components.Theme)
local e = Roact.createElement local e = Roact.createElement
@@ -13,22 +14,25 @@ function Panel:init()
end end
function Panel:render() function Panel:render()
return e("Frame", { return Theme.with(function(theme)
Size = UDim2.new(1, 0, 1, 0), return e("Frame", {
BackgroundTransparency = 1, Size = UDim2.new(1, 0, 1, 0),
}, {
Layout = Roact.createElement("UIListLayout", {
HorizontalAlignment = Enum.HorizontalAlignment.Center,
SortOrder = Enum.SortOrder.LayoutOrder,
}),
Body = e("Frame", {
Size = UDim2.new(0, 360, 1, -32),
BackgroundTransparency = 1, BackgroundTransparency = 1,
}, self.props[Roact.Children]), }, {
Layout = Roact.createElement("UIListLayout", {
HorizontalAlignment = Enum.HorizontalAlignment.Center,
SortOrder = Enum.SortOrder.LayoutOrder,
}),
Footer = e(RojoFooter), Body = e("Frame", {
}) Size = UDim2.new(0, 360, 1, -32),
BackgroundColor3 = theme.Background1,
BorderSizePixel = 0,
}, self.props[Roact.Children]),
Footer = e(RojoFooter),
})
end)
end end
return Panel return Panel

View File

@@ -6,7 +6,7 @@ local Roact = require(Rojo.Roact)
local Config = require(Plugin.Config) local Config = require(Plugin.Config)
local Version = require(Plugin.Version) local Version = require(Plugin.Version)
local Assets = require(Plugin.Assets) local Assets = require(Plugin.Assets)
local Theme = require(Plugin.Theme) local Theme = require(Plugin.Components.Theme)
local e = Roact.createElement local e = Roact.createElement
@@ -18,50 +18,53 @@ function RojoFooter:init()
end end
function RojoFooter:render() function RojoFooter:render()
return e("Frame", { return Theme.with(function(theme)
LayoutOrder = 3, return e("Frame", {
Size = UDim2.new(1, 0, 0, 32), LayoutOrder = 3,
BackgroundColor3 = Theme.SecondaryColor, Size = UDim2.new(1, 0, 0, 32),
BorderSizePixel = 0, BackgroundColor3 = theme.Background2,
}, { BorderSizePixel = 0,
Padding = e("UIPadding", { ZIndex = 2,
PaddingTop = UDim.new(0, 4),
PaddingBottom = UDim.new(0, 4),
PaddingLeft = UDim.new(0, 8),
PaddingRight = UDim.new(0, 8),
}),
LogoContainer = e("Frame", {
BackgroundTransparency = 1,
Size = UDim2.new(0, 0, 0, 32),
}, { }, {
Logo = e("ImageLabel", { Padding = e("UIPadding", {
Image = Assets.Images.Logo, PaddingTop = UDim.new(0, 4),
Size = UDim2.new(0, 80, 0, 40), PaddingBottom = UDim.new(0, 4),
ScaleType = Enum.ScaleType.Fit, PaddingLeft = UDim.new(0, 8),
BackgroundTransparency = 1, PaddingRight = UDim.new(0, 8),
Position = UDim2.new(0, 0, 1, -10),
AnchorPoint = Vector2.new(0, 1),
}), }),
}),
Version = e("TextLabel", { LogoContainer = e("Frame", {
Position = UDim2.new(1, 0, 0, 0), BackgroundTransparency = 1,
Size = UDim2.new(0, 0, 1, 0),
AnchorPoint = Vector2.new(1, 0),
Font = Theme.TitleFont,
TextSize = 18,
Text = Version.display(Config.version),
TextXAlignment = Enum.TextXAlignment.Right,
TextColor3 = Theme.LightTextColor,
BackgroundTransparency = 1,
[Roact.Change.AbsoluteSize] = function(rbx) Size = UDim2.new(0, 0, 0, 32),
self.setFooterVersionSize(rbx.AbsoluteSize) }, {
end, Logo = e("ImageLabel", {
}), Image = Assets.Images.Logo,
}) Size = UDim2.new(0, 80, 0, 40),
ScaleType = Enum.ScaleType.Fit,
BackgroundTransparency = 1,
Position = UDim2.new(0, 0, 1, -10),
AnchorPoint = Vector2.new(0, 1),
}),
}),
Version = e("TextLabel", {
Position = UDim2.new(1, 0, 0, 0),
Size = UDim2.new(0, 0, 1, 0),
AnchorPoint = Vector2.new(1, 0),
Font = theme.TitleFont,
TextSize = 18,
Text = Version.display(Config.version),
TextXAlignment = Enum.TextXAlignment.Right,
TextColor3 = theme.Text2,
BackgroundTransparency = 1,
[Roact.Change.AbsoluteSize] = function(rbx)
self.setFooterVersionSize(rbx.AbsoluteSize)
end,
}),
})
end)
end end
return RojoFooter return RojoFooter

View File

@@ -0,0 +1,104 @@
--[[
Theming system taking advantage of Roact's new context API.
Doesn't use colors provided by Studio and instead just branches on theme
name. This isn't exactly best practice.
]]
local Studio = settings():GetService("Studio")
local Rojo = script:FindFirstAncestor("Rojo")
local Roact = require(Rojo.Roact)
local Log = require(Rojo.Log)
local strict = require(script.Parent.Parent.strict)
local lightTheme = strict("Theme", {
ButtonFont = Enum.Font.GothamSemibold,
InputFont = Enum.Font.Code,
TitleFont = Enum.Font.GothamBold,
MainFont = Enum.Font.Gotham,
Brand1 = Color3.fromRGB(225, 56, 53),
Text1 = Color3.fromRGB(64, 64, 64),
Text2 = Color3.fromRGB(160, 160, 160),
TextOnAccent = Color3.fromRGB(235, 235, 235),
Background1 = Color3.fromRGB(255, 255, 255),
Background2 = Color3.fromRGB(235, 235, 235),
})
local darkTheme = strict("Theme", {
ButtonFont = Enum.Font.GothamSemibold,
InputFont = Enum.Font.Code,
TitleFont = Enum.Font.GothamBold,
MainFont = Enum.Font.Gotham,
Brand1 = Color3.fromRGB(225, 56, 53),
Text1 = Color3.fromRGB(235, 235, 235),
Text2 = Color3.fromRGB(200, 200, 200),
TextOnAccent = Color3.fromRGB(235, 235, 235),
Background1 = Color3.fromRGB(48, 48, 48),
Background2 = Color3.fromRGB(64, 64, 64),
})
local Context = Roact.createContext(lightTheme)
local StudioProvider = Roact.Component:extend("StudioProvider")
-- Pull the current theme from Roblox Studio and update state with it.
function StudioProvider:updateTheme()
local studioTheme = Studio.Theme
if studioTheme.Name == "Light" then
self:setState({
theme = lightTheme,
})
elseif studioTheme.Name == "Dark" then
self:setState({
theme = darkTheme,
})
else
Log.warn("Unexpected theme '{}'' -- falling back to light theme!", studioTheme.Name)
self:setState({
theme = lightTheme,
})
end
end
function StudioProvider:init()
self:updateTheme()
end
function StudioProvider:render()
return Roact.createElement(Context.Provider, {
value = self.state.theme,
}, self.props[Roact.Children])
end
function StudioProvider:didMount()
self.connection = Studio.ThemeChanged:Connect(function()
self:updateTheme()
end)
end
function StudioProvider:willUnmount()
self.connection:Disconnect()
end
local function with(callback)
return Roact.createElement(Context.Consumer, {
render = callback,
})
end
return {
StudioProvider = StudioProvider,
Consumer = Context.Consumer,
with = with,
}

View File

@@ -1,14 +0,0 @@
local strict = require(script.Parent.strict)
return strict("Theme", {
ButtonFont = Enum.Font.GothamSemibold,
InputFont = Enum.Font.Code,
TitleFont = Enum.Font.GothamBold,
MainFont = Enum.Font.Gotham,
AccentColor = Color3.fromRGB(225, 56, 53),
AccentLightColor = Color3.fromRGB(255, 146, 145),
PrimaryColor = Color3.fromRGB(64, 64, 64),
SecondaryColor = Color3.fromRGB(235, 235, 235),
LightTextColor = Color3.fromRGB(160, 160, 160),
})

View File

@@ -19,7 +19,7 @@ local app = Roact.createElement(App, {
plugin = plugin, plugin = plugin,
}) })
local tree = Roact.mount(app, game:GetService("CoreGui"), "Rojo UI") local tree = Roact.mount(app, nil, "Rojo UI")
plugin.Unloading:Connect(function() plugin.Unloading:Connect(function()
Roact.unmount(tree) Roact.unmount(tree)