diff --git a/.luaurc b/.luaurc index 7f5d4a8..3e84f78 100644 --- a/.luaurc +++ b/.luaurc @@ -1,6 +1,6 @@ { "aliases": { - "lune": "~/.lune/.typedefs/0.8.0/", + "lune": "~/.lune/.typedefs/0.8.6/", "plugin": "plugin/src", "server": "server/src" } diff --git a/.vscode/settings.json b/.vscode/settings.json index 9cb3c0e..f11eff0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,7 +9,7 @@ "**/build/**" ], "luau-lsp.require.directoryAliases": { - "@lune/": "~/.lune/.typedefs/0.8.0/", + "@lune/": "~/.lune/.typedefs/0.8.6/", "@root/": "plugin/src", "@pkg/": "plugin/Packages", "@plugin/": "plugin/src", diff --git a/foreman.toml b/foreman.toml index 3f2d609..33d9237 100644 --- a/foreman.toml +++ b/foreman.toml @@ -1,11 +1,11 @@ [tools] -darklua = { source = "seaofvoices/darklua", version = "0.12.1" } +darklua = { source = "seaofvoices/darklua", version = "0.13.1" } luau-lsp = { source = "JohnnyMorganz/luau-lsp", version = "1.32.0" } -lune = { source = "lune-org/lune", version = "0.8.0" } -rojo = { source = "rojo-rbx/rojo", version = "7.2.1" } +lune = { source = "lune-org/lune", version = "0.8.6" } +rojo = { source = "rojo-rbx/rojo", version = "7.4.1" } run-in-roblox = { source = "rojo-rbx/run-in-roblox", version = "0.3.0" } -selene = { source = "kampfkarren/selene", version = "0.25.0" } -stylua = { source = "JohnnyMorganz/StyLua", version = "0.17.1" } +selene = { source = "Kampfkarren/selene", version = "0.27.1" } +stylua = { source = "JohnnyMorganz/StyLua", version = "0.20.0" } tarmac = { source = "Roblox/tarmac", version = "0.7.0" } wally = { source = "UpliftGames/wally", version = "0.3.2" } -wally-package-types = { source = "JohnnyMorganz/wally-package-types", version = "1.2.1" } +wally-package-types = { source = "JohnnyMorganz/wally-package-types", version = "1.3.2" } diff --git a/plugin/.luaurc b/plugin/.luaurc index 0b0cecf..851f91f 100644 --- a/plugin/.luaurc +++ b/plugin/.luaurc @@ -1,4 +1,5 @@ { + "languageMode": "strict", "aliases": { "pkg": "Packages", "root": "src" diff --git a/plugin/src/applyTheme.luau b/plugin/src/applyTheme.luau index 55bcb7c..5a2baa6 100644 --- a/plugin/src/applyTheme.luau +++ b/plugin/src/applyTheme.luau @@ -19,7 +19,9 @@ local function applyTheme(theme: types.ExtensionTheme, studio: Studio): string? end local success, result = pcall(function() - studio[name] = Color3.fromHex(color) + -- Casting to `any` to clear dynamic property access warning + -- since we're already in a pcall + (studio :: any)[name] = Color3.fromHex(color) end) if not success then diff --git a/plugin/src/components/App.luau b/plugin/src/components/App.luau index 3d10465..8c12187 100644 --- a/plugin/src/components/App.luau +++ b/plugin/src/components/App.luau @@ -16,9 +16,9 @@ export type Props = { } local function App(_props: Props) - local view, setView = useState("Home" :: View) - local extension, setExtension = useState(nil :: PublishedExtension?) - local searchTerm, setSearchTerm = useState(nil :: string?) + local view: View, setView = useState("Home" :: View) + local extension: PublishedExtension?, setExtension = useState(nil :: PublishedExtension?) + local searchTerm: string?, setSearchTerm = useState(nil :: string?) local onBack = useCallback(function() setExtension(nil) @@ -42,7 +42,7 @@ local function App(_props: Props) }) else nil, - ThemeDetails = if view == "ThemeDetails" + ThemeDetails = if view == "ThemeDetails" and extension then React.createElement(ThemeDetailsWrapper, { extension = extension, onBack = onBack, diff --git a/plugin/src/components/ExtensionsList.luau b/plugin/src/components/ExtensionsList.luau index 0e18f1d..b1bb926 100644 --- a/plugin/src/components/ExtensionsList.luau +++ b/plugin/src/components/ExtensionsList.luau @@ -16,7 +16,7 @@ local ACTION_BUTTON_WIDTH = 120 local PADDING = UDim.new(0, 8) local function ExtensionsList(props: Props) - local children = { + local children: { [string]: React.Node } = { Layout = React.createElement("UIListLayout", { Padding = PADDING, SortOrder = Enum.SortOrder.LayoutOrder, @@ -31,6 +31,9 @@ local function ExtensionsList(props: Props) for i, extension in props.extensions do local isEven = i % 2 == 0 local latestVersion = if extension.versions then extension.versions[1] else nil + local extensionName = if latestVersion + then `{extension.displayName} v{latestVersion.version}` + else extension.displayName children[extension.extensionName] = React.createElement("Frame", { LayoutOrder = i, @@ -68,7 +71,7 @@ local function ExtensionsList(props: Props) LayoutOrder = getLayoutOrder(), AutomaticSize = Enum.AutomaticSize.XY, BackgroundTransparency = 1, - Text = `{extension.displayName} v{latestVersion.version}`, + Text = extensionName, TextSize = 16, Font = Enum.Font.GothamMedium, TextXAlignment = Enum.TextXAlignment.Left, diff --git a/plugin/src/components/Home.luau b/plugin/src/components/Home.luau index eeeec4f..335a09c 100644 --- a/plugin/src/components/Home.luau +++ b/plugin/src/components/Home.luau @@ -25,7 +25,7 @@ export type Props = { local function Home(props: Props) local isLoading: boolean = useMemo(function() return #props.extensions == 0 and not props.err - end, { props.extensions, props.err }) + end, { props.extensions, props.err } :: { unknown }) local onSearch = useCallback(function(rbx: TextBox, enterPressed: boolean) if enterPressed and rbx.Text ~= "" then diff --git a/plugin/src/components/Home.story.luau b/plugin/src/components/Home.story.luau index 4acc6c0..07d19d7 100644 --- a/plugin/src/components/Home.story.luau +++ b/plugin/src/components/Home.story.luau @@ -20,9 +20,10 @@ return { version = "1.2.3", }, }, - }, + } :: any, }, onViewExtension = print, + onSearch = print, }) end, }, @@ -33,6 +34,7 @@ return { return React.createElement(Home, { extensions = {}, onViewExtension = print, + onSearch = print, }) end, }, @@ -44,6 +46,7 @@ return { extensions = {}, err = "Network error occurred", onViewExtension = print, + onSearch = print, }) end, }, diff --git a/plugin/src/components/HomeWrapper.luau b/plugin/src/components/HomeWrapper.luau index 33de1a9..886b59c 100644 --- a/plugin/src/components/HomeWrapper.luau +++ b/plugin/src/components/HomeWrapper.luau @@ -19,7 +19,7 @@ export type Props = { local function HomeWrapper(props: Props) local page, setPage = useState(1) local extensions, setExtensions = useState({} :: { PublishedExtension }) - local err, setErr = useState(nil :: string?) + local err: string?, setErr = useState(nil :: string?) local onFetchMore = useCallback(function() setPage(function(prev) diff --git a/plugin/src/components/LoadingSpinner.luau b/plugin/src/components/LoadingSpinner.luau index cba503e..101848e 100644 --- a/plugin/src/components/LoadingSpinner.luau +++ b/plugin/src/components/LoadingSpinner.luau @@ -28,7 +28,7 @@ local function LoadingSpinner(providedProps: Props) Image = "rbxasset://textures/DarkThemeLoadingCircle.png", Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, - Rotation = clock:map(function(n) + Rotation = clock:map(function(n: number) return n * (props.speed * SPEED_MULTIPLIER) end), }), diff --git a/plugin/src/components/ThemeDetails.luau b/plugin/src/components/ThemeDetails.luau index 3779199..45442f9 100644 --- a/plugin/src/components/ThemeDetails.luau +++ b/plugin/src/components/ThemeDetails.luau @@ -30,7 +30,7 @@ local function ThemeDetails(providedProps: Props) local props: InternalProps = Sift.Dictionary.join(defaultProps, providedProps) local latestVersion = if props.extension.versions then props.extension.versions[1] else nil - local themeVariants = { + local themeVariants: { [string]: React.Node } = { Layout = React.createElement("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, Padding = PADDING, diff --git a/plugin/src/components/ThemeDetails.story.luau b/plugin/src/components/ThemeDetails.story.luau index a195e7e..7196a6e 100644 --- a/plugin/src/components/ThemeDetails.story.luau +++ b/plugin/src/components/ThemeDetails.story.luau @@ -16,12 +16,11 @@ return { version = "1.2.2", }, }, - }, + } :: any, themes = themesSnapshot, onBack = function() print("go back") end, - studio = {}, }) end, } diff --git a/plugin/src/components/ThemeDetailsWrapper.luau b/plugin/src/components/ThemeDetailsWrapper.luau index 2cc8e85..1a237ee 100644 --- a/plugin/src/components/ThemeDetailsWrapper.luau +++ b/plugin/src/components/ThemeDetailsWrapper.luau @@ -14,7 +14,7 @@ export type Props = { onBack: () -> (), } -local function ThemeDetailsWrapper(props: Props) +local function ThemeDetailsWrapper(props: Props): React.Node local err, setErr = useState(nil :: string?) local themes, setThemes = useState(nil :: { types.ExtensionTheme }?) diff --git a/plugin/src/components/ThemeDetailsWrapper.story.luau b/plugin/src/components/ThemeDetailsWrapper.story.luau index ca0ecd3..0565904 100644 --- a/plugin/src/components/ThemeDetailsWrapper.story.luau +++ b/plugin/src/components/ThemeDetailsWrapper.story.luau @@ -15,7 +15,7 @@ return { version = "1.2.2", }, }, - }, + } :: any, onBack = function() print("go back") end, diff --git a/plugin/src/components/ThemeLabel.luau b/plugin/src/components/ThemeLabel.luau index ae387f7..bdaa799 100644 --- a/plugin/src/components/ThemeLabel.luau +++ b/plugin/src/components/ThemeLabel.luau @@ -18,7 +18,7 @@ export type Props = { local function ThemeLabel(props: Props) local previewedColors = useMemo(function() local colors = getThemeColors(props.theme) - local elements = {} + local elements: { [string]: React.Node } = {} local count = 0 for _, colorCode in colors.found do @@ -42,18 +42,18 @@ local function ThemeLabel(props: Props) end end - for i = 1, NUM_PREVIEW_COLORS do - local color = colors.found[i] - - if color then - elements[tostring(color)] = React.createElement("Frame", { - LayoutOrder = i, - BackgroundColor3 = color, - Size = UDim2.fromOffset(32, 32), - BorderSizePixel = 0, - }) - end - end + -- for i = 1, NUM_PREVIEW_COLORS do + -- local color = colors.found[i] + + -- if color then + -- elements[tostring(color)] = React.createElement("Frame", { + -- LayoutOrder = i, + -- BackgroundColor3 = color, + -- Size = UDim2.fromOffset(32, 32), + -- BorderSizePixel = 0, + -- }) + -- end + -- end return elements end, { props.theme }) diff --git a/plugin/src/components/ViewportTrigger.luau b/plugin/src/components/ViewportTrigger.luau index 156aee8..225bee0 100644 --- a/plugin/src/components/ViewportTrigger.luau +++ b/plugin/src/components/ViewportTrigger.luau @@ -25,7 +25,7 @@ export type Props = { } local function ViewportTrigger(props: Props) - local ref: { current: Frame? } = useRef() + local ref: { current: Frame? } = useRef(nil) local screen = useScreen(ref.current) local position: Vector2, setPosition = useState(Vector2.zero) @@ -45,7 +45,7 @@ local function ViewportTrigger(props: Props) end end return false - end, { position, screen }) + end, { position, screen } :: { unknown }) local wasInBounds = usePrevious(isInBounds) diff --git a/plugin/src/components/stories.luau b/plugin/src/components/stories.luau index d4aa01a..e3802c7 100644 --- a/plugin/src/components/stories.luau +++ b/plugin/src/components/stories.luau @@ -3,7 +3,7 @@ local getLayoutOrder = require("./getLayoutOrder") type Story = { name: string?, - story: (...any) -> Story, + story: (...any) -> React.Node, } local PADDING = 16 diff --git a/plugin/src/components/useCombinedSize.luau b/plugin/src/components/useCombinedSize.luau index c6bf0f9..c35703d 100644 --- a/plugin/src/components/useCombinedSize.luau +++ b/plugin/src/components/useCombinedSize.luau @@ -10,7 +10,7 @@ local useMemo = React.useMemo local useState = React.useState type SizeMap = { - [string]: number, + [string]: Vector2, } local function useCombinedSize() diff --git a/plugin/src/constants.luau b/plugin/src/constants.luau index 2854fcf..e113e39 100644 --- a/plugin/src/constants.luau +++ b/plugin/src/constants.luau @@ -1,135 +1,135 @@ -return { - PLUGIN_NAME = "Swatch", - - SERVER_URL = "https://swatch.vocksel.com", - - --[[ - This object maps Roblox Studio script editor colors to an array of - VSCode's base colors, as well as token colors. +--[[ + This object maps Roblox Studio script editor colors to an array of + VSCode's base colors, as well as token colors. - See the Studio object for valid script editor colors. - https://developer.roblox.com/en-us/api-reference/class/Studio + See the Studio object for valid script editor colors. + https://developer.roblox.com/en-us/api-reference/class/Studio - When examining a theme's json file, there is a `colors` object, and a - `tokenColors` array. Any key in the `colors` object can be used, and any - of the scopes for the token's can be used. + When examining a theme's json file, there is a `colors` object, and a + `tokenColors` array. Any key in the `colors` object can be used, and any + of the scopes for the token's can be used. - Precedence is left-to-right, so for example with "Text Color" if a match - is found for `string.unquoted`, then `variable` will not be used. - ]] - ROBLOX_VSCODE_THEME_MAP = { - ["Background Color"] = { - "editor.background", - }, - ["Selection Color"] = { - "foreground", - "editor.foreground", - }, - ["Selection Background Color"] = { - "editor.selectionBackground", - "selection.background", - }, - ["Error Color"] = { - "errorForeground", - "editorError.foreground", - }, - ["Warning Color"] = { - "editorWarning.foreground", - }, - ["Find Selection Background Color"] = { - "editor.findMatchBackground", - }, - ["Matching Word Background Color"] = { - "editor.selectionBackground", - }, - ["Whitespace Color"] = { - "editorLineNumber.activeForeground", - }, - ["Current Line Highlight Color"] = { - "editor.background", - }, - ["Ruler Color"] = { - "editorRuler.foreground", - }, - ["Bracket Color"] = { - "meta.brace", - "foreground", - "editor.foreground", - }, - ["Text Color"] = { - "string.unquoted", - "variable", - "variable.object", - "variable.other", - "variable.parameter", - "support", - }, - ["Operator Color"] = { - "keyword.operator", - "keyword", - }, - ["Number Color"] = { - "constant.numeric", - "constant", - }, - ["String Color"] = { - "string", - "string.quoted", - }, - ["Comment Color"] = { - "comment", - }, - ["Bool Color"] = { - "constant.language", - "constant", - }, - ['"nil" Color'] = { - "constant.language", - "constant", - }, - ["Function Name Color"] = { - "entity.name.function", - "variable.function", - "meta.function", - }, - ['"function" Color'] = { - "keyword", - "keyword.control", - "variable", - "variable.language", - "meta.function", - }, - ['"local" Color'] = { - "keyword", - }, - ['"self" Color'] = { - "variable.instance", - "variable.language", - "support", - "keyword", - "variable", - }, - ["Luau Keyword Color"] = { - "variable", - }, - ["Keyword Color"] = { - "keyword", - }, - ["Built-in Function Color"] = { - "support.function", - "entity.name", - "entity.other", - }, - ['"TODO" Color'] = { - "variable", - "keyword", - }, - ["Method Color"] = { - "entity.name.function", - "variable.function", - }, - ["Property Color"] = { - "variable", - }, + Precedence is left-to-right, so for example with "Text Color" if a match + is found for `string.unquoted`, then `variable` will not be used. +]] +local ROBLOX_VSCODE_THEME_MAP: { [string]: { string } } = { + ["Background Color"] = { + "editor.background", + }, + ["Selection Color"] = { + "foreground", + "editor.foreground", + }, + ["Selection Background Color"] = { + "editor.selectionBackground", + "selection.background", + }, + ["Error Color"] = { + "errorForeground", + "editorError.foreground", + }, + ["Warning Color"] = { + "editorWarning.foreground", + }, + ["Find Selection Background Color"] = { + "editor.findMatchBackground", + }, + ["Matching Word Background Color"] = { + "editor.selectionBackground", + }, + ["Whitespace Color"] = { + "editorLineNumber.activeForeground", + }, + ["Current Line Highlight Color"] = { + "editor.background", + }, + ["Ruler Color"] = { + "editorRuler.foreground", + }, + ["Bracket Color"] = { + "meta.brace", + "foreground", + "editor.foreground", + }, + ["Text Color"] = { + "string.unquoted", + "variable", + "variable.object", + "variable.other", + "variable.parameter", + "support", + }, + ["Operator Color"] = { + "keyword.operator", + "keyword", + }, + ["Number Color"] = { + "constant.numeric", + "constant", + }, + ["String Color"] = { + "string", + "string.quoted", }, + ["Comment Color"] = { + "comment", + }, + ["Bool Color"] = { + "constant.language", + "constant", + }, + ['"nil" Color'] = { + "constant.language", + "constant", + }, + ["Function Name Color"] = { + "entity.name.function", + "variable.function", + "meta.function", + }, + ['"function" Color'] = { + "keyword", + "keyword.control", + "variable", + "variable.language", + "meta.function", + }, + ['"local" Color'] = { + "keyword", + }, + ['"self" Color'] = { + "variable.instance", + "variable.language", + "support", + "keyword", + "variable", + }, + ["Luau Keyword Color"] = { + "variable", + }, + ["Keyword Color"] = { + "keyword", + }, + ["Built-in Function Color"] = { + "support.function", + "entity.name", + "entity.other", + }, + ['"TODO" Color'] = { + "variable", + "keyword", + }, + ["Method Color"] = { + "entity.name.function", + "variable.function", + }, + ["Property Color"] = { + "variable", + }, +} + +return { + PLUGIN_NAME = "Swatch", + SERVER_URL = "https://swatch.vocksel.com", + ROBLOX_VSCODE_THEME_MAP = ROBLOX_VSCODE_THEME_MAP, } diff --git a/plugin/src/getScopeColors.luau b/plugin/src/getScopeColors.luau index 58c0293..9543262 100644 --- a/plugin/src/getScopeColors.luau +++ b/plugin/src/getScopeColors.luau @@ -3,7 +3,7 @@ local Sift = require("@pkg/Sift") local function getScopeColors(theme): { [string]: string } - local colors = {} + local colors: { [string]: string } = {} for _, token in theme.tokenColors do local color = token.settings.foreground @@ -13,7 +13,7 @@ local function getScopeColors(theme): { [string]: string } -- some older themes, the scope can be a comma separated string -- denoting the list of scopes, so we have to handle both cases -- where the scope string is either a single scope, or many. - local scopes = {} + local scopes: { string } = {} if token.scope then if Sift.Array.is(token.scope) then scopes = token.scope diff --git a/plugin/src/getThemeColors.luau b/plugin/src/getThemeColors.luau index 2297b71..68112d6 100644 --- a/plugin/src/getThemeColors.luau +++ b/plugin/src/getThemeColors.luau @@ -2,9 +2,10 @@ local Sift = require("@pkg/Sift") local constants = require("@root/constants") +local types = require("@root/types") local getScopeColors = require("@root/getScopeColors") -local function getThemeColors(theme): { +local function getThemeColors(theme: types.ExtensionTheme): { found: { [string]: string }, missing: { string }, } @@ -35,10 +36,12 @@ local function getThemeColors(theme): { return token.scope == nil end) - local global = theme.tokenColors[index] + if index then + local global = theme.tokenColors[index] - if global and global.settings then - color = global.settings.foreground + if global and global.settings then + color = global.settings.foreground + end end end