diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c23eeee..176810fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # Rojo Changelog ## [Unreleased] -* Changed plugin UI to be simpler and more flat +* Changed plugin UI to be way prettier + * Thanks to [Reselim](https://github.com/Reselim) for the design! * Changed plugin error messages to be a little more useful * Removed unused 'Config' button in plugin UI * Fixed bug where bad server responses could cause the plugin to be in a bad state diff --git a/assets/round-rect-4px-radius.png b/assets/round-rect-4px-radius.png new file mode 100644 index 00000000..f2b59bd1 Binary files /dev/null and b/assets/round-rect-4px-radius.png differ diff --git a/assets/round-rect-8px-radius-2px-border.png b/assets/round-rect-8px-radius-2px-border.png deleted file mode 100644 index 9c976f19..00000000 Binary files a/assets/round-rect-8px-radius-2px-border.png and /dev/null differ diff --git a/assets/round-rect-8px-radius.png b/assets/round-rect-8px-radius.png deleted file mode 100644 index 55d1ac41..00000000 Binary files a/assets/round-rect-8px-radius.png and /dev/null differ diff --git a/plugin/src/Assets.lua b/plugin/src/Assets.lua index 51f0934c..9b94d6e8 100644 --- a/plugin/src/Assets.lua +++ b/plugin/src/Assets.lua @@ -9,19 +9,16 @@ local Assets = { }, }, Slices = { - RoundBoxWithBorder = { - asset = "rbxassetid://2754309674", - offset = Vector2.new(0, 0), - size = Vector2.new(32, 32), - center = Rect.new(15, 15, 16, 16), - }, RoundBox = { - asset = "rbxassetid://2773074100", + asset = "rbxassetid://2773204550", offset = Vector2.new(0, 0), size = Vector2.new(32, 32), - center = Rect.new(15, 15, 16, 16), + center = Rect.new(4, 4, 4, 4), }, }, + Images = { + Logo = "rbxassetid://2773210620", + }, StartSession = "", SessionActive = "", Configure = "", diff --git a/plugin/src/Components/App.lua b/plugin/src/Components/App.lua index dd79be33..893754ab 100644 --- a/plugin/src/Components/App.lua +++ b/plugin/src/Components/App.lua @@ -83,7 +83,19 @@ function App:render() if self.state.sessionStatus == SessionStatus.Connected then children = { - ConnectionActivePanel = e(ConnectionActivePanel), + ConnectionActivePanel = e(ConnectionActivePanel, { + stopSession = function() + Logging.trace("Disconnecting session") + + self.currentSession:disconnect() + self.currentSession = nil + self:setState({ + sessionStatus = SessionStatus.Disconnected, + }) + + Logging.trace("Session terminated by user") + end, + }), } elseif self.state.sessionStatus == SessionStatus.ConfiguringSession then children = { diff --git a/plugin/src/Components/ConnectPanel.lua b/plugin/src/Components/ConnectPanel.lua index e9da6d01..3308569c 100644 --- a/plugin/src/Components/ConnectPanel.lua +++ b/plugin/src/Components/ConnectPanel.lua @@ -4,27 +4,38 @@ local Plugin = Rojo.Plugin local Roact = require(Rojo.Roact) local Config = require(Plugin.Config) +local Version = require(Plugin.Version) local Assets = require(Plugin.Assets) local Theme = require(Plugin.Theme) +local joinBindings = require(Plugin.joinBindings) local FitList = require(Plugin.Components.FitList) local FitText = require(Plugin.Components.FitText) local FormButton = require(Plugin.Components.FormButton) local FormTextInput = require(Plugin.Components.FormTextInput) -local WhiteCross = Assets.Sprites.WhiteCross local RoundBox = Assets.Slices.RoundBox local e = Roact.createElement -local TEXT_COLOR = Color3.new(0.05, 0.05, 0.05) -local FORM_TEXT_SIZE = 20 - local ConnectPanel = Roact.Component:extend("ConnectPanel") function ConnectPanel:init() - self.labelSizes = {} - self.labelSize, self.setLabelSize = Roact.createBinding(Vector2.new()) + self.footerSize, self.setFooterSize = Roact.createBinding(Vector2.new()) + self.footerVersionSize, self.setFooterVersionSize = Roact.createBinding(Vector2.new()) + + -- This is constructed in init because 'joinBindings' is a hack and we'd + -- leak memory constructing it every render. When this kind of feature lands + -- in Roact properly, we can do this inline in render without fear. + self.footerRestSize = joinBindings( + { + self.footerSize, + self.footerVersionSize, + }, + function(container, other) + return UDim2.new(0, container.X - other.X - 16, 0, 18) + end + ) self:setState({ address = Config.defaultHost, @@ -32,20 +43,6 @@ function ConnectPanel:init() }) end -function ConnectPanel:updateLabelSize(name, size) - self.labelSizes[name] = size - - local x = 0 - local y = 0 - - for _, size in pairs(self.labelSizes) do - x = math.max(x, size.X) - y = math.max(y, size.Y) - end - - self.setLabelSize(Vector2.new(x, y)) -end - function ConnectPanel:render() local startSession = self.props.startSession local cancel = self.props.cancel @@ -66,57 +63,14 @@ function ConnectPanel:render() HorizontalAlignment = Enum.HorizontalAlignment.Center, }, }, { - Head = e("ImageLabel", { - Image = RoundBox.asset, - ImageRectOffset = RoundBox.offset, - ImageRectSize = RoundBox.size * Vector2.new(1, 0.5), - SliceCenter = RoundBox.center, - ScaleType = Enum.ScaleType.Slice, - ImageColor3 = Theme.SecondaryColor, - LayoutOrder = 1, - Size = UDim2.new(1, 0, 0, 36), - BackgroundTransparency = 1, - }, { - Padding = e("UIPadding", { - PaddingTop = UDim.new(0, 8), - PaddingBottom = UDim.new(0, 8), - PaddingLeft = UDim.new(0, 8), - PaddingRight = UDim.new(0, 8), - }), - - Title = e("TextLabel", { - Font = Enum.Font.SourceSansBold, - TextSize = 22, - Text = "Start New Rojo Session", - Size = UDim2.new(1, 0, 1, 0), - TextXAlignment = Enum.TextXAlignment.Left, - BackgroundTransparency = 1, - TextColor3 = TEXT_COLOR, - }), - - Close = e("ImageButton", { - Image = WhiteCross.asset, - ImageRectOffset = WhiteCross.offset, - ImageRectSize = WhiteCross.size, - Size = UDim2.new(0, 18, 0, 18), - Position = UDim2.new(1, 0, 0.5, 0), - AnchorPoint = Vector2.new(1, 0.5), - ImageColor3 = TEXT_COLOR, - BackgroundTransparency = 1, - [Roact.Event.Activated] = function() - cancel() - end, - }), - }), - Inputs = e(FitList, { containerProps = { BackgroundTransparency = 1, - LayoutOrder = 2, + LayoutOrder = 1, }, layoutProps = { FillDirection = Enum.FillDirection.Horizontal, - Padding = UDim.new(0, 12), + Padding = UDim.new(0, 8), }, paddingProps = { PaddingTop = UDim.new(0, 8), @@ -140,23 +94,15 @@ function ConnectPanel:render() LayoutOrder = 1, BackgroundTransparency = 1, TextXAlignment = Enum.TextXAlignment.Left, - Font = Enum.Font.SourceSansBold, - TextSize = FORM_TEXT_SIZE, + Font = Theme.TitleFont, + TextSize = 20, Text = "Address", - TextColor3 = TEXT_COLOR, - - [Roact.Change.AbsoluteSize] = function(rbx) - self:updateLabelSize("address", rbx.AbsoluteSize) - end, - }, { - Sizing = e("UISizeConstraint", { - MinSize = self.labelSize, - }), + TextColor3 = Theme.AccentColor, }), Input = e(FormTextInput, { layoutOrder = 2, - size = UDim2.new(0, 160, 0, 28), + size = UDim2.new(0, 200, 0, 28), value = self.state.address, onValueChange = function(newValue) self:setState({ @@ -181,23 +127,15 @@ function ConnectPanel:render() LayoutOrder = 1, BackgroundTransparency = 1, TextXAlignment = Enum.TextXAlignment.Left, - Font = Enum.Font.SourceSansBold, - TextSize = FORM_TEXT_SIZE, + Font = Theme.TitleFont, + TextSize = 20, Text = "Port", - TextColor3 = TEXT_COLOR, - - [Roact.Change.AbsoluteSize] = function(rbx) - self:updateLabelSize("port", rbx.AbsoluteSize) - end, - }, { - Sizing = e("UISizeConstraint", { - MinSize = self.labelSize, - }), + TextColor3 = Theme.AccentColor, }), Input = e(FormTextInput, { layoutOrder = 2, - size = UDim2.new(0, 70, 0, 28), + size = UDim2.new(0, 65, 0, 28), value = self.state.port, onValueChange = function(newValue) self:setState({ @@ -212,7 +150,7 @@ function ConnectPanel:render() fitAxes = "Y", containerProps = { BackgroundTransparency = 1, - LayoutOrder = 3, + LayoutOrder = 2, Size = UDim2.new(1, 0, 0, 0), }, layoutProps = { @@ -247,7 +185,65 @@ function ConnectPanel:render() end end, }), - }) + }), + + Footer = e(FitList, { + fitAxes = "Y", + containerKind = "ImageLabel", + containerProps = { + Image = RoundBox.asset, + ImageRectOffset = RoundBox.offset + Vector2.new(0, RoundBox.size.Y / 2), + ImageRectSize = RoundBox.size * Vector2.new(1, 0.5), + SliceCenter = RoundBox.center, + ScaleType = Enum.ScaleType.Slice, + ImageColor3 = Theme.SecondaryColor, + Size = UDim2.new(1, 0, 0, 0), + LayoutOrder = 3, + BackgroundTransparency = 1, + + [Roact.Change.AbsoluteSize] = function(rbx) + self.setFooterSize(rbx.AbsoluteSize) + end, + }, + layoutProps = { + FillDirection = Enum.FillDirection.Horizontal, + HorizontalAlignment = Enum.HorizontalAlignment.Center, + }, + paddingProps = { + 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 = self.footerRestSize, + }, { + Logo = e("ImageLabel", { + Image = Assets.Images.Logo, + Size = UDim2.new(0, 60, 0, 40), + ScaleType = Enum.ScaleType.Fit, + BackgroundTransparency = 1, + Position = UDim2.new(0, 0, 1, 0), + AnchorPoint = Vector2.new(0, 1), + }), + }), + + Version = e(FitText, { + Font = Theme.TitleFont, + TextSize = 18, + Text = Version.display(Config.version), + TextXAlignment = Enum.TextXAlignment.Right, + TextColor3 = Theme.LightTextColor, + BackgroundTransparency = 1, + + [Roact.Change.AbsoluteSize] = function(rbx) + self.setFooterVersionSize(rbx.AbsoluteSize) + end, + }), + }), }) end diff --git a/plugin/src/Components/ConnectionActivePanel.lua b/plugin/src/Components/ConnectionActivePanel.lua index b1d766b6..e0a8da26 100644 --- a/plugin/src/Components/ConnectionActivePanel.lua +++ b/plugin/src/Components/ConnectionActivePanel.lua @@ -1,38 +1,66 @@ local Roact = require(script:FindFirstAncestor("Rojo").Roact) -local Assets = require(script.Parent.Parent.Assets) +local Plugin = script:FindFirstAncestor("Plugin") -local FitList = require(script.Parent.FitList) -local FitText = require(script.Parent.FitText) +local Theme = require(Plugin.Theme) +local Assets = require(Plugin.Assets) + +local FitList = require(Plugin.Components.FitList) +local FitText = require(Plugin.Components.FitText) local e = Roact.createElement local RoundBox = Assets.Slices.RoundBox +local WhiteCross = Assets.Sprites.WhiteCross -local ConnectionActivePanel = Roact.Component:extend("ConnectionActivePanel") +local function ConnectionActivePanel(props) + local stopSession = props.stopSession -function ConnectionActivePanel:render() return e(FitList, { - containerKind = "ImageButton", + containerKind = "ImageLabel", containerProps = { Image = RoundBox.asset, - ImageRectOffset = RoundBox.offset, - ImageRectSize = RoundBox.size, - SliceCenter = RoundBox.center, + ImageRectOffset = RoundBox.offset + Vector2.new(0, RoundBox.size.Y / 2), + ImageRectSize = RoundBox.size * Vector2.new(1, 0.5), + SliceCenter = Rect.new(4, 4, 4, 4), ScaleType = Enum.ScaleType.Slice, BackgroundTransparency = 1, Position = UDim2.new(0.5, 0, 0, 0), AnchorPoint = Vector2.new(0.5, 0), }, + layoutProps = { + FillDirection = Enum.FillDirection.Horizontal, + VerticalAlignment = Enum.VerticalAlignment.Center, + }, }, { Text = e(FitText, { Padding = Vector2.new(12, 6), - Font = Enum.Font.SourceSans, + Font = Theme.ButtonFont, TextSize = 18, Text = "Rojo Connected", - TextColor3 = Color3.new(0.05, 0.05, 0.05), + TextColor3 = Theme.PrimaryColor, BackgroundTransparency = 1, }), + + CloseContainer = e("ImageButton", { + Size = UDim2.new(0, 30, 0, 30), + BackgroundTransparency = 1, + + [Roact.Event.Activated] = function() + stopSession() + end, + }, { + CloseImage = e("ImageLabel", { + Size = UDim2.new(0, 16, 0, 16), + Position = UDim2.new(0.5, 0, 0.5, 0), + AnchorPoint = Vector2.new(0.5, 0.5), + Image = WhiteCross.asset, + ImageRectOffset = WhiteCross.offset, + ImageRectSize = WhiteCross.size, + ImageColor3 = Theme.PrimaryColor, + BackgroundTransparency = 1, + }), + }), }) end diff --git a/plugin/src/Components/FitList.lua b/plugin/src/Components/FitList.lua index aa14fc03..e86e185a 100644 --- a/plugin/src/Components/FitList.lua +++ b/plugin/src/Components/FitList.lua @@ -46,10 +46,6 @@ function FitList:render() error("Invalid fitAxes value") end - if fitAxes ~= "XY" then - print("combinedSize", combinedSize) - end - self.setSize(combinedSize) end, }, layoutProps)), diff --git a/plugin/src/Components/FormButton.lua b/plugin/src/Components/FormButton.lua index 2833e04e..845fd06b 100644 --- a/plugin/src/Components/FormButton.lua +++ b/plugin/src/Components/FormButton.lua @@ -50,10 +50,10 @@ local function FormButton(props) Text = e(FitText, { Kind = "TextLabel", Text = text, - TextSize = 22, + TextSize = 18, TextColor3 = textColor, Font = Theme.ButtonFont, - Padding = Vector2.new(14, 6), + Padding = Vector2.new(16, 6), BackgroundTransparency = 1, }), }) diff --git a/plugin/src/Components/FormTextInput.lua b/plugin/src/Components/FormTextInput.lua index 63142b8a..07765919 100644 --- a/plugin/src/Components/FormTextInput.lua +++ b/plugin/src/Components/FormTextInput.lua @@ -32,10 +32,10 @@ local function FormTextInput(props) Size = UDim2.new(1, -12, 1, -12), Position = UDim2.new(0.5, 0, 0.5, 0), AnchorPoint = Vector2.new(0.5, 0.5), - Font = Enum.Font.SourceSans, + Font = Theme.InputFont, ClearTextOnFocus = false, TextXAlignment = Enum.TextXAlignment.Left, - TextSize = 20, + TextSize = 18, Text = value, TextColor3 = Theme.PrimaryColor, diff --git a/plugin/src/Theme.lua b/plugin/src/Theme.lua index 2129f063..1b860387 100644 --- a/plugin/src/Theme.lua +++ b/plugin/src/Theme.lua @@ -1,10 +1,13 @@ local Theme = { - ButtonFont = Enum.Font.SourceSansSemibold, - TitleFont = Enum.Font.SourceSansSemibold, - MainFont = Enum.Font.SourceSans, + ButtonFont = Enum.Font.GothamSemibold, + InputFont = Enum.Font.Gotham, + TitleFont = Enum.Font.GothamBold, + MainFont = Enum.Font.Gotham, + AccentColor = Color3.fromRGB(136, 0, 27), PrimaryColor = Color3.fromRGB(20, 20, 20), - SecondaryColor = Color3.fromRGB(240, 240, 240), + SecondaryColor = Color3.fromRGB(235, 235, 235), + LightTextColor = Color3.fromRGB(140, 140, 140), } setmetatable(Theme, { diff --git a/plugin/src/joinBindings.lua b/plugin/src/joinBindings.lua new file mode 100644 index 00000000..1dca84a6 --- /dev/null +++ b/plugin/src/joinBindings.lua @@ -0,0 +1,34 @@ +--[[ + joinBindings is a crazy hack that allows combining multiple Roact bindings + in the same spirit as `map`. + + It's implemented in terms of Roact internals that will probably break at + some point; please don't do that or use this module in your own code! +]] + +local Binding = require(script:FindFirstAncestor("Rojo").Roact.Binding) + +local function evaluate(fun, bindings) + local input = {} + + for index, binding in ipairs(bindings) do + input[index] = binding:getValue() + end + + return fun(unpack(input, 1, #bindings)) +end + +local function joinBindings(bindings, joinFunction) + local initialValue = evaluate(joinFunction, bindings) + local binding, setValue = Binding.create(initialValue) + + for _, binding in ipairs(bindings) do + Binding.subscribe(binding, function() + setValue(evaluate(joinFunction, bindings)) + end) + end + + return binding +end + +return joinBindings \ No newline at end of file