Skip to content

Commit

Permalink
Taking a pass over UI components (#20)
Browse files Browse the repository at this point in the history
- Factored out networking to "wrapper" components
- Added stories for each component
- Stories are removed from prod builds
  • Loading branch information
vocksel authored Jan 21, 2024
1 parent 93c6ba5 commit 9ef93d3
Show file tree
Hide file tree
Showing 17 changed files with 362 additions and 36 deletions.
3 changes: 2 additions & 1 deletion .justfile
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ _get-plugin-name:
jq -r .name {{ plugin_root / "default.project.json" }}

_prune:
rm -rf {{ plugin_build / "**/*.spec.lua" }}
rm -rf {{ plugin_build / "**/*.spec.luau" }}
rm -rf {{ plugin_build / "**/*.story.luau" }}

_build target output:
-rm -rf {{ plugin_build }}
Expand Down
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
"testez.d.lua"
],
"luau-lsp.require.mode": "relativeToFile",
"luau-lsp.ignoreGlobs": [
"**/_Index/**",
"**/build/**"
],
"luau-lsp.require.directoryAliases": {
"@lune/": "~/.lune/.typedefs/0.7.11/",
"@root/": "plugin/src",
Expand Down
4 changes: 2 additions & 2 deletions plugin/src/components/App.luau
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
local React = require("@pkg/React")
local types = require("@root/types")
local Home = require("./Home")
local HomeWrapper = require("./HomeWrapper")
local ThemeDetailsWrapper = require("./ThemeDetailsWrapper")

local useCallback = React.useCallback
Expand Down Expand Up @@ -31,7 +31,7 @@ local function App(_props: Props)

return React.createElement("Folder", nil, {
Home = if view == "Home"
then React.createElement(Home, {
then React.createElement(HomeWrapper, {
onViewExtension = onViewExtension,
})
else nil,
Expand Down
8 changes: 8 additions & 0 deletions plugin/src/components/App.story.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
local React = require("@pkg/React")
local App = require("./App")

return {
story = function()
return React.createElement(App)
end,
}
74 changes: 74 additions & 0 deletions plugin/src/components/ExtensionsList.story.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
local React = require("@pkg/React")
local types = require("@root/types")
local ExtensionsList = require("./ExtensionsList")

-- TODO: Just use a real web response
local function createMockExtension(name: string): types.PublishedExtension
return {
categories = {},
deploymentType = 0,
displayName = name,
extensionId = "1",
extensionName = name,
flags = "",
installationTargets = {},
lastUpdated = tostring(DateTime.now()),
longDescription = "",
presentInConflictList = "",
publishedDate = tostring(DateTime.now()),
publisher = {
displayName = "OnlyTwentyCharacters",
domain = "",
flags = "",
isDomainVerified = false,
publisherId = "",
publisherName = "",
},
releaseDate = tostring(DateTime.now()),
sharedWith = {},
shortDescription = "",
statistics = {},
tags = {},
versions = {
{
version = "1.2.3",
versionDescription = "",
assetUri = "",
fallbackAssetUri = "",
files = {},
flags = 0,
badges = {},
targetPlatform = "",
lastUpdated = "",
properties = {},
validationResultMessage = "",
},
},
}
end

local controls = {
numExtensions = 10,
}

type Props = {
controls: {
numExtensions: number,
},
}

return {
controls = controls,
story = function(props: Props)
local extensions = {}
print(props.controls.numExtensions)
for i = 1, props.controls.numExtensions do
table.insert(extensions, createMockExtension(`Extension {i}`))
end

return React.createElement(ExtensionsList, {
extensions = extensions,
onView = print,
})
end,
}
49 changes: 16 additions & 33 deletions plugin/src/components/Home.luau
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
local React = require("@pkg/React")
local fetchVisualStudioExtensions = require("@root/requests/fetchVisualStudioExtensions")
local types = require("@root/types")
local LoadingSpinner = require("./LoadingSpinner")
local ExtensionsList = require("./ExtensionsList")
Expand All @@ -9,50 +8,34 @@ type PublishedExtension = types.PublishedExtension
type ExtensionTheme = types.ExtensionTheme

local useCallback = React.useCallback
local useEffect = React.useEffect
local useState = React.useState
local useMemo = React.useMemo

local PADDING = UDim.new(0, 8)

export type Props = {
extensions: { PublishedExtension },
onSearch: (searchTerm: string) -> (),
onViewExtension: (extension: PublishedExtension) -> (),
searchTerm: string?,
err: string?,
}

local function Home(props: Props)
local isLoading, setIsLoading = useState(true)
local extensions, setExtensions = useState({} :: { PublishedExtension })
local searchTerm, setSearchTerm = useState("")
local err, setErr = useState(nil :: string?)
local isLoading = useMemo(function()
return #props.extensions == 0 and not props.err
end, { props.extensions, props.err })

local onSearch = useCallback(function(rbx: TextBox, enterPressed: boolean)
if enterPressed then
setSearchTerm(rbx.Text)
props.onSearch(rbx.Text)
end
end, {})

useEffect(function()
setErr(nil)
setIsLoading(true)
fetchVisualStudioExtensions({
-- page = page, -- TODO: Increment the page when scrolling to the bottom of the list
pageSize = 20,
searchTerm = if searchTerm ~= "" then searchTerm else "theme",
})
:andThen(function(newExtensions)
setExtensions(newExtensions)
end)
:catch(function()
setErr(`No extensions found. Please try again later`)
end)
:finally(function()
setIsLoading(false)
end)
end, { searchTerm })

return React.createElement("ScrollingFrame", {
Size = UDim2.fromScale(1, 1),
Size = UDim2.fromScale(1, 0),
AutomaticSize = Enum.AutomaticSize.Y,
BackgroundTransparency = 1,
CanvasSize = UDim2.fromScale(0, 0),
CanvasSize = UDim2.fromScale(1, 0),
AutomaticCanvasSize = Enum.AutomaticSize.Y,
}, {
Layout = React.createElement("UIListLayout", {
Expand All @@ -74,7 +57,7 @@ local function Home(props: Props)
BackgroundTransparency = 1,
}, {
Input = React.createElement("TextBox", {
Text = searchTerm,
Text = if props.searchTerm then props.searchTerm else "",
PlaceholderText = "Search themes...",
Size = UDim2.fromScale(1, 0),
TextColor3 = Color3.fromRGB(255, 255, 255),
Expand All @@ -95,12 +78,12 @@ local function Home(props: Props)
}),
}),

ErrorMessage = if err
ErrorMessage = if props.err
then React.createElement("TextLabel", {
LayoutOrder = getLayoutOrder(),
AutomaticSize = Enum.AutomaticSize.XY,
BackgroundTransparency = 1,
Text = err,
Text = props.err,
TextSize = 16,
Font = Enum.Font.GothamMedium,
TextXAlignment = Enum.TextXAlignment.Left,
Expand Down Expand Up @@ -130,7 +113,7 @@ local function Home(props: Props)
else {
ExtensionList = if not isLoading
then React.createElement(ExtensionsList, {
extensions = extensions,
extensions = props.extensions,
onView = props.onViewExtension,
})
else nil,
Expand Down
51 changes: 51 additions & 0 deletions plugin/src/components/Home.story.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
local React = require("@pkg/React")
local stories = require("./stories")
local Home = require("./Home")

return {
story = stories({
{
name = "Primary",
story = function()
return React.createElement(Home, {
extensions = {
{
extensionName = "theme",
displayName = "Theme",
publisher = {
publisherName = "OnlyTwentyCharacters",
},
versions = {
{
version = "1.2.3",
},
},
},
},
onViewExtension = print,
})
end,
},

{
name = "Loading",
story = function()
return React.createElement(Home, {
extensions = {},
onViewExtension = print,
})
end,
},

{
name = "Network error",
story = function()
return React.createElement(Home, {
extensions = {},
err = "Network error occurred",
onViewExtension = print,
})
end,
},
}),
}
44 changes: 44 additions & 0 deletions plugin/src/components/HomeWrapper.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
local React = require("@pkg/React")
local fetchVisualStudioExtensions = require("@root/requests/fetchVisualStudioExtensions")
local types = require("@root/types")
local Home = require("./Home")

type PublishedExtension = types.PublishedExtension

local useEffect = React.useEffect
local useState = React.useState

export type Props = {
onViewExtension: (extension: PublishedExtension) -> (),
}

local function HomeWrapper(props: Props)
local extensions, setExtensions = useState({} :: { PublishedExtension })
local searchTerm, setSearchTerm = useState(nil :: string?)
local err, setErr = useState(nil :: string?)

useEffect(function()
setErr(nil)
fetchVisualStudioExtensions({
-- page = page, -- TODO: Increment the page when scrolling to the bottom of the list
pageSize = 20,
searchTerm = if searchTerm then searchTerm else "theme",
})
:andThen(function(newExtensions)
setExtensions(newExtensions)
end)
:catch(function()
setErr(`No extensions found. Please try again later`)
end)
end, { searchTerm })

return React.createElement(Home, {
extensions = extensions,
err = err,
searchTerm = searchTerm,
onSearch = setSearchTerm,
onViewExtension = props.onViewExtension,
})
end

return HomeWrapper
10 changes: 10 additions & 0 deletions plugin/src/components/HomeWrapper.story.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
local React = require("@pkg/React")
local HomeWrapper = require("./HomeWrapper")

return {
story = function()
return React.createElement(HomeWrapper, {
onViewExtension = print,
})
end,
}
8 changes: 8 additions & 0 deletions plugin/src/components/LoadingSpinner.story.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
local React = require("@pkg/React")
local LoadingSpinner = require("./LoadingSpinner")

return {
story = function()
return React.createElement(LoadingSpinner)
end,
}
27 changes: 27 additions & 0 deletions plugin/src/components/ThemeDetails.story.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
local React = require("@pkg/React")
local ThemeDetails = require("./ThemeDetails")
local themesSnapshot = require("@root/requests/snapshots/get-v1-themes")

return {
story = function()
return React.createElement(ThemeDetails, {
extension = {
extensionName = "theme-monokai-pro-vscode",
displayName = "Monokai Pro",
publisher = {
publisherName = "monokai",
},
versions = {
{
version = "1.2.2",
},
},
},
themes = themesSnapshot,
onBack = function()
print("go back")
end,
studio = {},
})
end,
}
24 changes: 24 additions & 0 deletions plugin/src/components/ThemeDetailsWrapper.story.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
local React = require("@pkg/React")
local ThemeDetailsWrapper = require("./ThemeDetailsWrapper")

return {
story = function()
return React.createElement(ThemeDetailsWrapper, {
extension = {
extensionName = "theme-monokai-pro-vscode",
displayName = "Monokai Pro",
publisher = {
publisherName = "monokai",
},
versions = {
{
version = "1.2.2",
},
},
},
onBack = function()
print("go back")
end,
})
end,
}
Loading

0 comments on commit 9ef93d3

Please sign in to comment.