diff --git a/plugin/src/components/App.lua b/plugin/src/components/App.lua index f06b68b..bdb116a 100644 --- a/plugin/src/components/App.lua +++ b/plugin/src/components/App.lua @@ -1,10 +1,9 @@ local Root = script:FindFirstAncestor("rbxtheme") local React = require(Root.Packages.React) -local Sift = require(Root.Packages.Sift) local types = require(Root.types) local Home = require(Root.Components.Home) -local ThemeDetails = require(Root.Components.ThemeDetails) +local ThemeDetailsWrapper = require(Root.Components.ThemeDetailsWrapper) local useCallback = React.useCallback local useState = React.useState @@ -20,18 +19,15 @@ export type Props = { local function App(_props: Props) local view, setView = useState("Home" :: View) - local viewParams, setViewParams = useState({}) + local extension, setExtension = useState(nil :: PublishedExtension?) local onBack = useCallback(function() - setViewParams({}) + setExtension(nil) setView("Home") end, {}) - local onViewExtension = useCallback(function(extension: PublishedExtension, themes: { ExtensionTheme }) - setViewParams({ - extension = extension, - themes = themes, - }) + local onViewExtension = useCallback(function(selectedExtension: PublishedExtension) + setExtension(selectedExtension) setView("ThemeDetails") end, {}) @@ -43,12 +39,10 @@ local function App(_props: Props) else nil, ThemeDetails = if view == "ThemeDetails" - then React.createElement( - ThemeDetails, - Sift.Dictionary.join(viewParams, { - onBack = onBack, - }) - ) + then React.createElement(ThemeDetailsWrapper, { + extension = extension, + onBack = onBack, + }) else nil, }) end diff --git a/plugin/src/components/Home.lua b/plugin/src/components/Home.lua index 938900b..bdb3dd0 100644 --- a/plugin/src/components/Home.lua +++ b/plugin/src/components/Home.lua @@ -2,7 +2,6 @@ local Root = script:FindFirstAncestor("rbxtheme") local React = require(Root.Packages.React) local fetchVisualStudioExtensions = require(Root.fetchVisualStudioExtensions) -local fetchExtensionThemes = require(Root.fetchExtensionThemes) local types = require(Root.types) local LoadingSpinner = require(Root.Components.LoadingSpinner) local ExtensionsList = require(Root.Components.ExtensionsList) @@ -18,29 +17,14 @@ local useState = React.useState local PADDING = UDim.new(0, 8) export type Props = { - onViewExtension: (extension: PublishedExtension, themes: { Theme }) -> (), + onViewExtension: (extension: PublishedExtension) -> (), } local function Home(props: Props) local isLoading, setIsLoading = useState(true) local extensions, setExtensions = useState({} :: { PublishedExtension }) local searchTerm, setSearchTerm = useState("") - - local onView = useCallback(function(extension: PublishedExtension) - local latestVersion = extension.versions[1] - - if latestVersion then - fetchExtensionThemes(extension, latestVersion.version) - :andThen(function(themes) - props.onViewExtension(extension, themes) - end) - :catch(function(err) - warn("ERR:", err) - end) - else - warn("No latest version found for extension {extension.displayName}") - end - end, {}) + local err, setErr = useState(nil :: string?) local onSearch = useCallback(function(rbx: TextBox, enterPressed: boolean) if enterPressed then @@ -49,6 +33,7 @@ local function Home(props: Props) end, {}) useEffect(function() + setErr(nil) setIsLoading(true) fetchVisualStudioExtensions({ -- page = page, -- TODO: Increment the page when scrolling to the bottom of the list @@ -58,6 +43,9 @@ local function Home(props: Props) :andThen(function(newExtensions) setExtensions(newExtensions) end) + :catch(function() + setErr(`No extensions found. Please try again later`) + end) :finally(function() setIsLoading(false) end) @@ -109,6 +97,21 @@ local function Home(props: Props) }), }), + ErrorMessage = if err + then React.createElement("TextLabel", { + LayoutOrder = getLayoutOrder(), + AutomaticSize = Enum.AutomaticSize.XY, + BackgroundTransparency = 1, + Text = err, + TextSize = 16, + Font = Enum.Font.GothamMedium, + TextXAlignment = Enum.TextXAlignment.Left, + TextYAlignment = Enum.TextYAlignment.Top, + TextColor3 = Color3.fromRGB(255, 255, 255), + TextTruncate = Enum.TextTruncate.AtEnd, + }) + else nil, + ExtensionsListWrapper = React.createElement( "Frame", { @@ -130,7 +133,7 @@ local function Home(props: Props) ExtensionList = if not isLoading then React.createElement(ExtensionsList, { extensions = extensions, - onView = onView, + onView = props.onViewExtension, }) else nil, } diff --git a/plugin/src/components/ThemeDetailsWrapper.lua b/plugin/src/components/ThemeDetailsWrapper.lua new file mode 100644 index 0000000..913e29b --- /dev/null +++ b/plugin/src/components/ThemeDetailsWrapper.lua @@ -0,0 +1,59 @@ +local Root = script:FindFirstAncestor("rbxtheme") + +local React = require(Root.Packages.React) +local Sift = require(Root.Packages.Sift) +local styles = require(script.Parent.styles) +local LoadingSpinner = require(script.Parent.LoadingSpinner) +local ThemeDetails = require(script.Parent.ThemeDetails) +local fetchExtensionThemes = require(script.Parent.Parent.fetchExtensionThemes) +local types = require(script.Parent.Parent.types) + +local useState = React.useState +local useEffect = React.useEffect + +export type Props = { + extension: types.PublishedExtension, + onBack: () -> (), +} + +local function ThemeDetailsWrapper(props: Props) + local err, setErr = useState(nil :: string?) + local themes, setThemes = useState(nil :: { types.ExtensionTheme }?) + + useEffect(function() + if props.extension.versions then + local latestVersion = props.extension.versions[1] + + if latestVersion then + fetchExtensionThemes(props.extension, latestVersion.version) + :andThen(function(newThemes) + setThemes(newThemes) + end) + :catch(function() + setErr(`We couldn't find any themes for this extension. Sorry about that!`) + end) + else + setErr(`We couldn't find any themes for this extension. Sorry about that!`) + end + end + end, { props.extension }) + + if err then + return React.createElement( + "TextLabel", + Sift.Dictionary.join(styles.text, { + Text = err, + }) + ) + elseif themes then + return React.createElement(ThemeDetails, { + extension = props.extension, + themes = themes, + onBack = props.onBack, + }) + else + return React.createElement(LoadingSpinner) + end +end + +return ThemeDetailsWrapper diff --git a/plugin/src/components/styles.lua b/plugin/src/components/styles.lua new file mode 100644 index 0000000..5537e70 --- /dev/null +++ b/plugin/src/components/styles.lua @@ -0,0 +1,17 @@ +local styles = {} + +local BODY_TEXT_COLOR = Color3.fromHex("#ffffff") +local BODY_TEXT_SIZE = 16 +local BODY_TEXT_FONT = Enum.Font.GothamMedium + +styles.text = { + Text = "", + Size = UDim2.fromScale(0, 0), + AutomaticSize = Enum.AutomaticSize.XY, + TextColor3 = BODY_TEXT_COLOR, + TextSize = BODY_TEXT_SIZE, + Font = BODY_TEXT_FONT, + BackgroundTransparency = 1, +} + +return styles