@rbxts/centurion-ui 1.0.8 → 2.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -15
- package/centurion.luau +10 -0
- package/package.json +13 -23
- package/src/analyse/cursor.luau +25 -0
- package/src/analyse/highlight.luau +91 -0
- package/src/analyse/init.luau +318 -0
- package/src/analyse/leventine.luau +298 -0
- package/src/analyse/match.luau +39 -0
- package/src/analyse/suggest.luau +41 -0
- package/src/app/header.luau +128 -0
- package/src/app/history.luau +258 -0
- package/src/app/init.luau +699 -0
- package/src/app/suggestions.luau +419 -0
- package/src/button.luau +13 -0
- package/src/components/background.luau +37 -0
- package/src/components/container.luau +33 -0
- package/src/components/corner.luau +11 -0
- package/src/components/divider.luau +28 -0
- package/src/components/flex.luau +108 -0
- package/src/components/gap.luau +25 -0
- package/src/components/image.luau +33 -0
- package/src/components/padding.luau +59 -0
- package/src/components/stroke.luau +20 -0
- package/src/components/text.luau +57 -0
- package/src/components/textbox.luau +186 -0
- package/src/fade.luau +23 -0
- package/src/init.luau +142 -0
- package/src/input.luau +16 -0
- package/src/px.luau +68 -0
- package/src/rich.luau +14 -0
- package/src/state.luau +33 -0
- package/src/theme.luau +70 -0
- package/src/ts/index.d.ts +60 -0
- package/src/ts/init.luau +5 -0
- package/src/types.luau +85 -0
- package/vide/init.luau +8 -0
- package/vide/src/action.luau +25 -0
- package/vide/src/apply.luau +162 -0
- package/vide/src/batch.luau +23 -0
- package/vide/src/branch.luau +40 -0
- package/vide/src/changed.luau +18 -0
- package/vide/src/cleanup.luau +43 -0
- package/vide/src/context.luau +74 -0
- package/vide/src/create.luau +107 -0
- package/vide/src/defaults.luau +113 -0
- package/vide/src/derive.luau +18 -0
- package/vide/src/effect.luau +12 -0
- package/vide/src/flags.luau +12 -0
- package/vide/src/graph.luau +321 -0
- package/vide/src/implicit_effect.luau +125 -0
- package/vide/src/indexes.luau +121 -0
- package/vide/src/init.luau +10 -0
- package/vide/src/lib.luau +120 -0
- package/vide/src/mount.luau +11 -0
- package/vide/src/read.luau +5 -0
- package/vide/src/root.luau +35 -0
- package/vide/src/show.luau +36 -0
- package/vide/src/source.luau +31 -0
- package/vide/src/spring.luau +328 -0
- package/vide/src/switch.luau +114 -0
- package/vide/src/timeout.luau +27 -0
- package/vide/src/untrack.luau +25 -0
- package/vide/src/values.luau +131 -0
- package/out/app/centurion-app.d.ts +0 -3
- package/out/app/centurion-app.luau +0 -86
- package/out/app/index.d.ts +0 -32
- package/out/app/init.luau +0 -105
- package/out/components/history/history-line.d.ts +0 -9
- package/out/components/history/history-line.luau +0 -88
- package/out/components/history/history-list.d.ts +0 -11
- package/out/components/history/history-list.luau +0 -67
- package/out/components/history/index.d.ts +0 -1
- package/out/components/history/init.luau +0 -7
- package/out/components/index.d.ts +0 -2
- package/out/components/init.luau +0 -10
- package/out/components/suggestions/badge.d.ts +0 -16
- package/out/components/suggestions/badge.luau +0 -40
- package/out/components/suggestions/index.d.ts +0 -1
- package/out/components/suggestions/init.luau +0 -7
- package/out/components/suggestions/main-suggestion.d.ts +0 -9
- package/out/components/suggestions/main-suggestion.luau +0 -232
- package/out/components/suggestions/suggestion-list.d.ts +0 -8
- package/out/components/suggestions/suggestion-list.luau +0 -96
- package/out/components/suggestions/suggestions.d.ts +0 -2
- package/out/components/suggestions/suggestions.luau +0 -64
- package/out/components/suggestions/types.d.ts +0 -6
- package/out/components/suggestions/types.luau +0 -2
- package/out/components/suggestions/util.d.ts +0 -1
- package/out/components/suggestions/util.luau +0 -22
- package/out/components/terminal/command.d.ts +0 -6
- package/out/components/terminal/command.luau +0 -74
- package/out/components/terminal/index.d.ts +0 -1
- package/out/components/terminal/init.luau +0 -7
- package/out/components/terminal/suggestion.d.ts +0 -26
- package/out/components/terminal/suggestion.luau +0 -205
- package/out/components/terminal/terminal-text-field/index.d.ts +0 -1
- package/out/components/terminal/terminal-text-field/init.luau +0 -7
- package/out/components/terminal/terminal-text-field/suggestion.d.ts +0 -5
- package/out/components/terminal/terminal-text-field/suggestion.luau +0 -124
- package/out/components/terminal/terminal-text-field/terminal-text-field.d.ts +0 -13
- package/out/components/terminal/terminal-text-field/terminal-text-field.luau +0 -278
- package/out/components/terminal/terminal.d.ts +0 -2
- package/out/components/terminal/terminal.luau +0 -304
- package/out/components/ui/frame.d.ts +0 -17
- package/out/components/ui/frame.luau +0 -32
- package/out/components/ui/group.d.ts +0 -15
- package/out/components/ui/group.luau +0 -29
- package/out/components/ui/layer.d.ts +0 -8
- package/out/components/ui/layer.luau +0 -26
- package/out/components/ui/outline.d.ts +0 -15
- package/out/components/ui/outline.luau +0 -116
- package/out/components/ui/padding.d.ts +0 -10
- package/out/components/ui/padding.luau +0 -19
- package/out/components/ui/scrolling-frame.d.ts +0 -14
- package/out/components/ui/scrolling-frame.luau +0 -44
- package/out/components/ui/text-field.d.ts +0 -12
- package/out/components/ui/text-field.luau +0 -60
- package/out/components/ui/text.d.ts +0 -17
- package/out/components/ui/text.luau +0 -61
- package/out/constants/options.d.ts +0 -2
- package/out/constants/options.luau +0 -27
- package/out/constants/text.d.ts +0 -3
- package/out/constants/text.luau +0 -9
- package/out/constants/util.d.ts +0 -1
- package/out/constants/util.luau +0 -7
- package/out/hooks/use-client.d.ts +0 -2
- package/out/hooks/use-client.luau +0 -17
- package/out/hooks/use-event.d.ts +0 -14
- package/out/hooks/use-event.luau +0 -58
- package/out/hooks/use-px.d.ts +0 -19
- package/out/hooks/use-px.luau +0 -78
- package/out/index.d.ts +0 -2
- package/out/init.luau +0 -10
- package/out/palette.d.ts +0 -47
- package/out/palette.luau +0 -42
- package/out/store.d.ts +0 -12
- package/out/store.luau +0 -26
- package/out/types.d.ts +0 -44
- package/out/types.luau +0 -2
- package/out/utils/string.d.ts +0 -5
- package/out/utils/string.luau +0 -25
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
local vide = require("../../vide")
|
|
2
|
+
|
|
3
|
+
local create = vide.create
|
|
4
|
+
local read = vide.read
|
|
5
|
+
|
|
6
|
+
type Can<T> = T | () -> T
|
|
7
|
+
type Padding = {
|
|
8
|
+
read padding: Can<number>?,
|
|
9
|
+
read x: Can<number>?,
|
|
10
|
+
read y: Can<number>?,
|
|
11
|
+
read left: Can<number>?,
|
|
12
|
+
read right: Can<number>?,
|
|
13
|
+
read top: Can<number>?,
|
|
14
|
+
read bottom: Can<number>?,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
local function padding(props: number | () -> number | Padding)
|
|
18
|
+
if typeof(props) == "number" or typeof(props) == "function" then
|
|
19
|
+
return create "UIPadding" {
|
|
20
|
+
PaddingLeft = function()
|
|
21
|
+
return UDim.new(0, read(props))
|
|
22
|
+
end,
|
|
23
|
+
PaddingRight = function()
|
|
24
|
+
return UDim.new(0, read(props))
|
|
25
|
+
end,
|
|
26
|
+
PaddingTop = function()
|
|
27
|
+
return UDim.new(0, read(props))
|
|
28
|
+
end,
|
|
29
|
+
PaddingBottom = function()
|
|
30
|
+
return UDim.new(0, read(props))
|
|
31
|
+
end,
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
local pad = props.padding or 0
|
|
36
|
+
local x = props.x or pad
|
|
37
|
+
local y = props.y or pad
|
|
38
|
+
local left = props.left or x
|
|
39
|
+
local right = props.right or x
|
|
40
|
+
local top = props.top or y
|
|
41
|
+
local bottom = props.bottom or y
|
|
42
|
+
|
|
43
|
+
return create "UIPadding" {
|
|
44
|
+
PaddingLeft = function()
|
|
45
|
+
return UDim.new(0, read(left))
|
|
46
|
+
end,
|
|
47
|
+
PaddingRight = function()
|
|
48
|
+
return UDim.new(0, read(right))
|
|
49
|
+
end,
|
|
50
|
+
PaddingTop = function()
|
|
51
|
+
return UDim.new(0, read(top))
|
|
52
|
+
end,
|
|
53
|
+
PaddingBottom = function()
|
|
54
|
+
return UDim.new(0, read(bottom))
|
|
55
|
+
end,
|
|
56
|
+
}
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
return padding
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
local fade = require("../fade")
|
|
2
|
+
local vide = require("../../vide")
|
|
3
|
+
|
|
4
|
+
local create = vide.create
|
|
5
|
+
|
|
6
|
+
type Can<T> = T | () -> T
|
|
7
|
+
type Stroke = {
|
|
8
|
+
read color: Can<Color3>?,
|
|
9
|
+
read thickness: Can<number>?,
|
|
10
|
+
read transparency: Can<number>?,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return function(props: Stroke)
|
|
14
|
+
return create "UIStroke" {
|
|
15
|
+
ApplyStrokeMode = Enum.ApplyStrokeMode.Border,
|
|
16
|
+
Color = props.color,
|
|
17
|
+
Thickness = props.thickness or 1,
|
|
18
|
+
Transparency = fade.fade(props.transparency),
|
|
19
|
+
}
|
|
20
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
local fade = require("../fade")
|
|
2
|
+
local px = require("../px")
|
|
3
|
+
local state = require("../state")
|
|
4
|
+
local theme = require("../theme")
|
|
5
|
+
local types = require("../types")
|
|
6
|
+
local vide = require("../../vide")
|
|
7
|
+
|
|
8
|
+
local create = vide.create
|
|
9
|
+
local read = vide.read :: (<T>(() -> T) -> T) & (<T>(T) -> T)
|
|
10
|
+
|
|
11
|
+
type Can<T> = T | () -> T
|
|
12
|
+
type Text = {
|
|
13
|
+
read size: Can<UDim2>?,
|
|
14
|
+
read auto: Can<Enum.AutomaticSize | "X" | "Y" | "XY">?,
|
|
15
|
+
read order: Can<number>?,
|
|
16
|
+
|
|
17
|
+
read text: Can<string>,
|
|
18
|
+
read weight: Can<Enum.FontWeight>?,
|
|
19
|
+
read text_size: Can<number>?,
|
|
20
|
+
read text_style: Can<types.TextStyle>?,
|
|
21
|
+
read xalignment: Can<Enum.TextXAlignment>?,
|
|
22
|
+
read wrapped: Can<boolean>?,
|
|
23
|
+
read rich_text: Can<boolean>?,
|
|
24
|
+
read zindex: Can<number>?,
|
|
25
|
+
read transparency: Can<number>?,
|
|
26
|
+
|
|
27
|
+
[number]: unknown,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return function(props: Text)
|
|
31
|
+
return create "TextLabel" {
|
|
32
|
+
Size = props.size,
|
|
33
|
+
AutomaticSize = props.auto,
|
|
34
|
+
LayoutOrder = props.order,
|
|
35
|
+
|
|
36
|
+
Text = props.text,
|
|
37
|
+
TextSize = props.text_size or px(state.text_size),
|
|
38
|
+
TextTransparency = fade.fade(props.transparency),
|
|
39
|
+
TextColor3 = function()
|
|
40
|
+
return theme.text_color(state.theme(), props.text_style and read(props.text_style) or "normal")
|
|
41
|
+
end,
|
|
42
|
+
FontFace = function()
|
|
43
|
+
local f: Font = state.font()
|
|
44
|
+
local weight = read(props.weight) or Enum.FontWeight.Regular
|
|
45
|
+
return Font.new(f.Family, weight)
|
|
46
|
+
end,
|
|
47
|
+
TextWrapped = props.wrapped,
|
|
48
|
+
TextXAlignment = props.xalignment,
|
|
49
|
+
RichText = props.rich_text,
|
|
50
|
+
ZIndex = props.zindex,
|
|
51
|
+
|
|
52
|
+
AutoLocalize = false,
|
|
53
|
+
BackgroundTransparency = 1,
|
|
54
|
+
|
|
55
|
+
unpack(props),
|
|
56
|
+
}
|
|
57
|
+
end
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
local GuiService = game:GetService("GuiService")
|
|
2
|
+
local UserInputService = game:GetService("UserInputService")
|
|
3
|
+
|
|
4
|
+
local fade = require("../fade")
|
|
5
|
+
local px = require("../px")
|
|
6
|
+
local state = require("../state")
|
|
7
|
+
local theme = require("../theme")
|
|
8
|
+
local types = require("../types")
|
|
9
|
+
local vide = require("../../vide")
|
|
10
|
+
|
|
11
|
+
local create = vide.create
|
|
12
|
+
local changed = vide.changed
|
|
13
|
+
local source = vide.source
|
|
14
|
+
local effect = vide.effect
|
|
15
|
+
local read = vide.read :: (<T>(() -> T) -> T) & (<T>(T) -> T)
|
|
16
|
+
|
|
17
|
+
type Can<T> = T | () -> T
|
|
18
|
+
type TextBoxProps = {
|
|
19
|
+
read width: Can<number>?,
|
|
20
|
+
read height: Can<number>?,
|
|
21
|
+
|
|
22
|
+
read text: Can<string>,
|
|
23
|
+
read text_size: Can<number>?,
|
|
24
|
+
read text_style: Can<types.TextStyle>?,
|
|
25
|
+
read wrapped: Can<boolean>?,
|
|
26
|
+
read weight: Can<Enum.FontWeight>?,
|
|
27
|
+
read rich_text: Can<boolean>?,
|
|
28
|
+
read background_color: Can<Color3>?,
|
|
29
|
+
read background_transparency: Can<number>?,
|
|
30
|
+
read placeholder: Can<string>?,
|
|
31
|
+
read focused: Can<boolean>?,
|
|
32
|
+
read xalignment: Can<Enum.TextXAlignment>?,
|
|
33
|
+
read multiline: Can<boolean>?,
|
|
34
|
+
read editable: Can<boolean>?,
|
|
35
|
+
read transparency: Can<number>?,
|
|
36
|
+
-- whether confirming the console keyboard submits, rather than only committing the text
|
|
37
|
+
read submit_on_keyboard_return: boolean?,
|
|
38
|
+
-- receives a function that opens the keyboard, even if the textbox is already focused without it
|
|
39
|
+
read bind_open_keyboard: ((open: () -> ()) -> ())?,
|
|
40
|
+
|
|
41
|
+
read update_text: ((string) -> ())?,
|
|
42
|
+
read update_focused: ((boolean) -> ())?,
|
|
43
|
+
read enter: (string) -> (),
|
|
44
|
+
|
|
45
|
+
[number]: unknown,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return function(props: TextBoxProps)
|
|
49
|
+
local raw_text = source ""
|
|
50
|
+
-- set while focus is briefly released to reopen the touch keyboard
|
|
51
|
+
local reattaching = false
|
|
52
|
+
|
|
53
|
+
local function submit()
|
|
54
|
+
if not props.focused then
|
|
55
|
+
return
|
|
56
|
+
end
|
|
57
|
+
props.enter(raw_text())
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
local textbox: TextBox
|
|
61
|
+
textbox = create "TextBox" {
|
|
62
|
+
Size = function()
|
|
63
|
+
return UDim2.fromOffset(read(props.width) or 0, read(props.height) or 0)
|
|
64
|
+
end,
|
|
65
|
+
AutomaticSize = Enum.AutomaticSize.XY,
|
|
66
|
+
|
|
67
|
+
Text = props.text,
|
|
68
|
+
PlaceholderText = props.placeholder,
|
|
69
|
+
TextSize = props.text_size or px(state.text_size),
|
|
70
|
+
TextTransparency = fade.fade(props.transparency),
|
|
71
|
+
TextColor3 = function()
|
|
72
|
+
return theme.text_color(state.theme(), props.text_style and read(props.text_style) or "normal")
|
|
73
|
+
end,
|
|
74
|
+
TextXAlignment = props.xalignment,
|
|
75
|
+
TextEditable = props.editable,
|
|
76
|
+
TextWrapped = props.wrapped,
|
|
77
|
+
MultiLine = props.multiline,
|
|
78
|
+
FontFace = function()
|
|
79
|
+
local f: Font = state.font()
|
|
80
|
+
local weight = read(props.weight) or Enum.FontWeight.Regular
|
|
81
|
+
return Font.new(f.Family, weight)
|
|
82
|
+
end,
|
|
83
|
+
RichText = props.rich_text,
|
|
84
|
+
PlaceholderColor3 = function()
|
|
85
|
+
return state.theme().subtext
|
|
86
|
+
end,
|
|
87
|
+
|
|
88
|
+
BackgroundColor3 = props.background_color,
|
|
89
|
+
BackgroundTransparency = props.background_transparency or 1,
|
|
90
|
+
AutoLocalize = false,
|
|
91
|
+
|
|
92
|
+
if props.update_text then changed("Text", props.update_text) else nil,
|
|
93
|
+
changed("Text", raw_text),
|
|
94
|
+
|
|
95
|
+
Focused = function()
|
|
96
|
+
if not props.update_focused then
|
|
97
|
+
return
|
|
98
|
+
end
|
|
99
|
+
props.update_focused(true)
|
|
100
|
+
end,
|
|
101
|
+
|
|
102
|
+
FocusLost = function(enter)
|
|
103
|
+
if reattaching then
|
|
104
|
+
return
|
|
105
|
+
end
|
|
106
|
+
if props.update_focused then
|
|
107
|
+
props.update_focused(false)
|
|
108
|
+
end
|
|
109
|
+
if not enter then
|
|
110
|
+
return
|
|
111
|
+
end
|
|
112
|
+
submit()
|
|
113
|
+
end,
|
|
114
|
+
|
|
115
|
+
-- consoles don't fire enter through FocusLost, so this workaround is required
|
|
116
|
+
-- Roblox have shown some interest in fixing this, so it should be removed in that case to prevent duplicate submissions
|
|
117
|
+
ReturnPressedFromOnScreenKeyboard = if GuiService:IsTenFootInterface()
|
|
118
|
+
then function()
|
|
119
|
+
if props.submit_on_keyboard_return ~= false then
|
|
120
|
+
submit()
|
|
121
|
+
else
|
|
122
|
+
-- the textbox can stay focused once the keyboard closes, so release it explicitly
|
|
123
|
+
textbox:ReleaseFocus(false)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
else nil,
|
|
127
|
+
|
|
128
|
+
unpack(props),
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
-- releases focus without reporting it, so that it can be captured again
|
|
132
|
+
local function detach()
|
|
133
|
+
reattaching = true
|
|
134
|
+
textbox:ReleaseFocus(false)
|
|
135
|
+
task.wait()
|
|
136
|
+
reattaching = false
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
local function capture()
|
|
140
|
+
if textbox:IsFocused() then
|
|
141
|
+
-- tapping a button on touch devices can leave the textbox focused
|
|
142
|
+
-- without the keyboard open, so release it and capture it again
|
|
143
|
+
if
|
|
144
|
+
UserInputService.OnScreenKeyboardVisible
|
|
145
|
+
or UserInputService.PreferredInput ~= Enum.PreferredInput.Touch
|
|
146
|
+
then
|
|
147
|
+
return
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
detach()
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
if read(props.focused) then
|
|
154
|
+
textbox:CaptureFocus()
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
if props.bind_open_keyboard then
|
|
159
|
+
props.bind_open_keyboard(function()
|
|
160
|
+
task.defer(function()
|
|
161
|
+
if textbox:IsFocused() then
|
|
162
|
+
detach()
|
|
163
|
+
end
|
|
164
|
+
textbox:CaptureFocus()
|
|
165
|
+
end)
|
|
166
|
+
end)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
if props.focused ~= nil then
|
|
170
|
+
effect(function()
|
|
171
|
+
local value = read(props.focused)
|
|
172
|
+
if textbox:IsFocused() == value then
|
|
173
|
+
return
|
|
174
|
+
end
|
|
175
|
+
task.defer(function()
|
|
176
|
+
if value then
|
|
177
|
+
capture()
|
|
178
|
+
else
|
|
179
|
+
textbox:ReleaseFocus(false)
|
|
180
|
+
end
|
|
181
|
+
end)
|
|
182
|
+
end)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
return textbox
|
|
186
|
+
end
|
package/src/fade.luau
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
local vide = require("../vide")
|
|
2
|
+
|
|
3
|
+
local read = vide.read
|
|
4
|
+
|
|
5
|
+
-- how visible the current subtree is, from 0 (hidden) to 1 (shown). Lets the
|
|
6
|
+
-- console fade as a whole without a CanvasGroup, which would soften text
|
|
7
|
+
local opacity = vide.context(function()
|
|
8
|
+
return 1
|
|
9
|
+
end :: () -> number)
|
|
10
|
+
|
|
11
|
+
-- combines a transparency with the surrounding opacity
|
|
12
|
+
local function fade(transparency: (number | () -> number)?): () -> number
|
|
13
|
+
local current = opacity()
|
|
14
|
+
return function()
|
|
15
|
+
local value = read(transparency) or 0
|
|
16
|
+
return 1 - (1 - value) * current()
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
opacity = opacity,
|
|
22
|
+
fade = fade,
|
|
23
|
+
}
|
package/src/init.luau
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
local Players = game:GetService("Players")
|
|
2
|
+
|
|
3
|
+
local app = require("@self/app")
|
|
4
|
+
local centurion = require("./centurion")
|
|
5
|
+
local px = require("@self/px")
|
|
6
|
+
local state = require("@self/state")
|
|
7
|
+
local theme = require("@self/theme")
|
|
8
|
+
local types = require("@self/types")
|
|
9
|
+
local vide = require("./vide")
|
|
10
|
+
|
|
11
|
+
local mounted = false
|
|
12
|
+
|
|
13
|
+
local function mount(keys: { Enum.KeyCode }?)
|
|
14
|
+
if mounted then
|
|
15
|
+
return
|
|
16
|
+
end
|
|
17
|
+
mounted = true
|
|
18
|
+
|
|
19
|
+
state.activation_keys(keys or { Enum.KeyCode.F2 })
|
|
20
|
+
|
|
21
|
+
vide.mount(function()
|
|
22
|
+
px.mount()
|
|
23
|
+
return vide.create "ScreenGui" {
|
|
24
|
+
Name = "Centurion",
|
|
25
|
+
ResetOnSpawn = false,
|
|
26
|
+
ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
|
|
27
|
+
|
|
28
|
+
app(),
|
|
29
|
+
}
|
|
30
|
+
end, Players.LocalPlayer:WaitForChild("PlayerGui"))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
local function set_opt<T>(source: () -> T, value: T?)
|
|
34
|
+
if value == nil then
|
|
35
|
+
return
|
|
36
|
+
end
|
|
37
|
+
source(value)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
local function configure(options: types.OptionsPartial)
|
|
41
|
+
set_opt(state.hide_on_lost_focus, options.hide_on_lost_focus)
|
|
42
|
+
set_opt(state.activation_keys, options.activation_keys)
|
|
43
|
+
set_opt(state.theme, options.theme)
|
|
44
|
+
set_opt(state.icon, options.icon)
|
|
45
|
+
set_opt(state.font, options.font)
|
|
46
|
+
set_opt(state.transparency, options.transparency)
|
|
47
|
+
|
|
48
|
+
set_opt(state.text_size, options.text_size)
|
|
49
|
+
set_opt(state.subtext_size, options.subtext_size)
|
|
50
|
+
|
|
51
|
+
set_opt(state.anchor, options.anchor)
|
|
52
|
+
set_opt(state.position, options.position)
|
|
53
|
+
set_opt(state.width, options.width)
|
|
54
|
+
|
|
55
|
+
set_opt(state.max_suggestions, options.max_suggestions)
|
|
56
|
+
set_opt(state.format_date, options.format_date)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
local function clear()
|
|
60
|
+
state.logs({})
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
local function open()
|
|
64
|
+
state.opened(true)
|
|
65
|
+
state.focused(true)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
local function close()
|
|
69
|
+
state.opened(false)
|
|
70
|
+
state.focused(false)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
local function toggle()
|
|
74
|
+
if state.opened() then
|
|
75
|
+
close()
|
|
76
|
+
else
|
|
77
|
+
open()
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
local function is_open(): boolean
|
|
82
|
+
return state.opened()
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
local function register_commands(options: { exclude: { string }?, prefix: string? }?)
|
|
86
|
+
options = options or {}
|
|
87
|
+
|
|
88
|
+
local cmd = function<T...>(name: string, cmd_data: centurion.Command<T...>)
|
|
89
|
+
if options.exclude and table.find(options.exclude, name) then
|
|
90
|
+
return
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
local cmd_name = name
|
|
94
|
+
if options.prefix then
|
|
95
|
+
cmd_name = options.prefix .. " " .. cmd_name
|
|
96
|
+
end
|
|
97
|
+
centurion.register_command(cmd_name, cmd_data)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
cmd("clear", {
|
|
101
|
+
description = "Clear the command history",
|
|
102
|
+
callback = function()
|
|
103
|
+
clear()
|
|
104
|
+
return ""
|
|
105
|
+
end,
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
local theme_names: { types.Theme } = {}
|
|
109
|
+
for name in pairs(theme.themes) do
|
|
110
|
+
table.insert(theme_names, name)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
local centurion_theme = centurion.register_type("centurion-theme", centurion.create_enum(theme_names))
|
|
114
|
+
cmd("theme", {
|
|
115
|
+
description = "Change the terminal theme",
|
|
116
|
+
arguments = function()
|
|
117
|
+
return centurion_theme("theme", "The name of the theme to switch to")
|
|
118
|
+
end,
|
|
119
|
+
callback = function(ctx, theme_name)
|
|
120
|
+
local data = theme.themes[theme_name]
|
|
121
|
+
if not data then
|
|
122
|
+
ctx.error("Theme '" .. theme_name .. "' does not exist.")
|
|
123
|
+
return
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
state.theme(data)
|
|
127
|
+
return `Theme changed to {theme_name}`
|
|
128
|
+
end,
|
|
129
|
+
})
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
mount = mount,
|
|
134
|
+
configure = configure,
|
|
135
|
+
register_commands = register_commands,
|
|
136
|
+
clear = clear,
|
|
137
|
+
open = open,
|
|
138
|
+
close = close,
|
|
139
|
+
toggle = toggle,
|
|
140
|
+
is_open = is_open,
|
|
141
|
+
themes = theme.themes,
|
|
142
|
+
}
|
package/src/input.luau
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
local UserInputService = game:GetService("UserInputService")
|
|
2
|
+
|
|
3
|
+
local vide = require("../vide")
|
|
4
|
+
|
|
5
|
+
local cleanup = vide.cleanup
|
|
6
|
+
local source = vide.source
|
|
7
|
+
|
|
8
|
+
local function preferred_input(): () -> Enum.PreferredInput
|
|
9
|
+
local preferred = source(UserInputService.PreferredInput)
|
|
10
|
+
cleanup(UserInputService:GetPropertyChangedSignal("PreferredInput"):Connect(function()
|
|
11
|
+
preferred(UserInputService.PreferredInput)
|
|
12
|
+
end))
|
|
13
|
+
return preferred
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
return preferred_input
|
package/src/px.luau
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
local vide = require("../vide")
|
|
2
|
+
|
|
3
|
+
local source = vide.source
|
|
4
|
+
local read = vide.read
|
|
5
|
+
local cleanup = vide.cleanup
|
|
6
|
+
|
|
7
|
+
export type Mode = "normal" | "even" | "scale" | "floor" | "ceil"
|
|
8
|
+
|
|
9
|
+
local BASE_RESOLUTION = Vector2.new(1920, 1080)
|
|
10
|
+
local MIN_SCALE = 0.5
|
|
11
|
+
local DOMINANT_AXIS = 0.5
|
|
12
|
+
|
|
13
|
+
local scale = source(1)
|
|
14
|
+
|
|
15
|
+
local function convert(value: number, mode: Mode?): number
|
|
16
|
+
return if mode == "even"
|
|
17
|
+
then math.round(value * scale() * 0.5) * 2
|
|
18
|
+
elseif mode == "scale" then value * scale()
|
|
19
|
+
elseif mode == "floor" then math.floor(value * scale())
|
|
20
|
+
elseif mode == "ceil" then math.ceil(value * scale())
|
|
21
|
+
else math.round(value * scale())
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
local function px_raw<T>(value: T | () -> T, mode: Mode? | () -> Mode?): T
|
|
25
|
+
local value_raw, mode_raw = read(value), read(mode)
|
|
26
|
+
|
|
27
|
+
if typeof(value_raw) == "number" then
|
|
28
|
+
return convert(value_raw, mode_raw) :: any
|
|
29
|
+
elseif typeof(value_raw) == "UDim" then
|
|
30
|
+
return UDim.new(value_raw.Scale, convert(value_raw.Offset, mode_raw)) :: any
|
|
31
|
+
elseif typeof(value_raw) == "UDim2" then
|
|
32
|
+
return UDim2.new(
|
|
33
|
+
value_raw.X.Scale,
|
|
34
|
+
convert(value_raw.X.Offset, mode_raw),
|
|
35
|
+
value_raw.Y.Scale,
|
|
36
|
+
convert(value_raw.Y.Offset, mode_raw)
|
|
37
|
+
) :: any
|
|
38
|
+
else
|
|
39
|
+
error("px: unsupported type")
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
local function px<T>(value: T | () -> T, mode: Mode? | () -> Mode?): () -> T
|
|
44
|
+
return function()
|
|
45
|
+
return px_raw(value, mode)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
local function mount()
|
|
50
|
+
local camera = workspace.CurrentCamera
|
|
51
|
+
|
|
52
|
+
local function update()
|
|
53
|
+
local width = math.log(camera.ViewportSize.X / BASE_RESOLUTION.X, 2)
|
|
54
|
+
local height = math.log(camera.ViewportSize.Y / BASE_RESOLUTION.Y, 2)
|
|
55
|
+
local centered = width + (height - width) * DOMINANT_AXIS
|
|
56
|
+
scale(math.max(2 ^ centered, MIN_SCALE))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
update()
|
|
60
|
+
|
|
61
|
+
cleanup(camera:GetPropertyChangedSignal("ViewportSize"):Connect(update))
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
return setmetatable({ mount = mount, convert = convert, get = px_raw }, {
|
|
65
|
+
__call = function<T>(_, value: T | () -> T, mode: Mode? | () -> Mode?): () -> T
|
|
66
|
+
return px(value, mode)
|
|
67
|
+
end,
|
|
68
|
+
})
|
package/src/rich.luau
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
-- helpers for building RichText strings
|
|
2
|
+
|
|
3
|
+
local function escape(text: string): string
|
|
4
|
+
return (text:gsub("&", "&"):gsub("<", "<"):gsub(">", ">"):gsub('"', """):gsub("'", "'"))
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
local function color(text: string, value: Color3): string
|
|
8
|
+
return `<font color="#{value:ToHex()}">{text}</font>`
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
escape = escape,
|
|
13
|
+
color = color,
|
|
14
|
+
}
|
package/src/state.luau
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
local theme = require("./theme")
|
|
2
|
+
local types = require("./types")
|
|
3
|
+
local vide = require("../vide")
|
|
4
|
+
|
|
5
|
+
local source = vide.source
|
|
6
|
+
|
|
7
|
+
return {
|
|
8
|
+
opened = source(false),
|
|
9
|
+
focused = source(false),
|
|
10
|
+
logs = source({} :: { types.Log }),
|
|
11
|
+
|
|
12
|
+
-- options
|
|
13
|
+
activation_keys = source({}),
|
|
14
|
+
hide_on_lost_focus = source(true),
|
|
15
|
+
theme = source(theme.themes.mocha),
|
|
16
|
+
font = source(Font.fromId(16658246179)),
|
|
17
|
+
title = source("Centurion"),
|
|
18
|
+
icon = source("rbxassetid://115292290730914"),
|
|
19
|
+
transparency = source(0.2),
|
|
20
|
+
format_date = source(function(log: types.Log): string
|
|
21
|
+
local dateTime = DateTime.fromUnixTimestamp(log.response.timestamp):FormatLocalTime("LT", "en-us")
|
|
22
|
+
local dateParts = dateTime:split(" ")
|
|
23
|
+
return `<b>{dateParts[1]}</b> {dateParts[2]}`
|
|
24
|
+
end),
|
|
25
|
+
max_suggestions = source(5),
|
|
26
|
+
|
|
27
|
+
text_size = source(28),
|
|
28
|
+
subtext_size = source(24),
|
|
29
|
+
|
|
30
|
+
anchor = source(Vector2.zero),
|
|
31
|
+
position = source(UDim2.new()),
|
|
32
|
+
width = source(UDim.new(1, 0)),
|
|
33
|
+
}
|
package/src/theme.luau
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
local types = require("./types")
|
|
2
|
+
|
|
3
|
+
local function text_color(theme: types.Theme, style: types.TextStyle)
|
|
4
|
+
return if style == "normal"
|
|
5
|
+
then theme.text
|
|
6
|
+
elseif style == "error" then theme.error
|
|
7
|
+
elseif style == "subtext" then theme.subtext
|
|
8
|
+
elseif style == "bg" then theme.background
|
|
9
|
+
elseif style == "highlight" then theme.highlight
|
|
10
|
+
else theme.text
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
-- subtle outline color derived from the theme, so custom themes don't need an extra field
|
|
14
|
+
local function border(theme: types.Theme)
|
|
15
|
+
return theme.surface:Lerp(theme.text, 0.15)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
local themes = {
|
|
19
|
+
mocha = {
|
|
20
|
+
background = Color3.fromRGB(30, 30, 46),
|
|
21
|
+
surface = Color3.fromRGB(49, 50, 68),
|
|
22
|
+
text = Color3.fromRGB(205, 214, 244),
|
|
23
|
+
subtext = Color3.fromRGB(166, 173, 200),
|
|
24
|
+
highlight = Color3.fromRGB(137, 180, 250),
|
|
25
|
+
success = Color3.fromRGB(166, 227, 161),
|
|
26
|
+
error = Color3.fromRGB(243, 139, 168),
|
|
27
|
+
} :: types.Theme,
|
|
28
|
+
macchiato = {
|
|
29
|
+
background = Color3.fromRGB(36, 39, 58),
|
|
30
|
+
surface = Color3.fromRGB(54, 58, 79),
|
|
31
|
+
text = Color3.fromRGB(202, 211, 245),
|
|
32
|
+
subtext = Color3.fromRGB(165, 173, 203),
|
|
33
|
+
highlight = Color3.fromRGB(138, 173, 244),
|
|
34
|
+
success = Color3.fromRGB(166, 218, 149),
|
|
35
|
+
error = Color3.fromRGB(237, 135, 150),
|
|
36
|
+
} :: types.Theme,
|
|
37
|
+
frappe = {
|
|
38
|
+
background = Color3.fromRGB(48, 52, 70),
|
|
39
|
+
surface = Color3.fromRGB(65, 69, 89),
|
|
40
|
+
text = Color3.fromRGB(198, 208, 245),
|
|
41
|
+
subtext = Color3.fromRGB(165, 173, 206),
|
|
42
|
+
highlight = Color3.fromRGB(140, 170, 238),
|
|
43
|
+
success = Color3.fromRGB(166, 209, 137),
|
|
44
|
+
error = Color3.fromRGB(231, 130, 132),
|
|
45
|
+
} :: types.Theme,
|
|
46
|
+
latte = {
|
|
47
|
+
background = Color3.fromRGB(230, 233, 239),
|
|
48
|
+
surface = Color3.fromRGB(220, 224, 232),
|
|
49
|
+
text = Color3.fromRGB(76, 79, 105),
|
|
50
|
+
subtext = Color3.fromRGB(92, 95, 119),
|
|
51
|
+
highlight = Color3.fromRGB(30, 102, 245),
|
|
52
|
+
success = Color3.fromRGB(64, 160, 43),
|
|
53
|
+
error = Color3.fromRGB(210, 15, 57),
|
|
54
|
+
} :: types.Theme,
|
|
55
|
+
roblox = {
|
|
56
|
+
background = Color3.fromRGB(17, 18, 22),
|
|
57
|
+
surface = Color3.fromRGB(31, 32, 36),
|
|
58
|
+
text = Color3.fromRGB(255, 255, 255),
|
|
59
|
+
subtext = Color3.fromRGB(187, 188, 190),
|
|
60
|
+
highlight = Color3.fromRGB(51, 95, 255),
|
|
61
|
+
success = Color3.fromRGB(57, 197, 130),
|
|
62
|
+
error = Color3.fromRGB(240, 68, 51),
|
|
63
|
+
} :: types.Theme,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
text_color = text_color,
|
|
68
|
+
border = border,
|
|
69
|
+
themes = themes,
|
|
70
|
+
}
|