Skip to content

Commit f1472d7

Browse files
fix(reactotron-app): Timeline empty state improvements (#1395 by @carlinisaacson)
#1359 - Timeline empty state improvements - Adds a button for the quick start guide - Adds a random developer joke Contributors: @carlinisaacson @trevor-coleman @darinwilson ![DD321274-A94C-42AF-BCAF-AB9A6996B126](https://github.com/infinitered/reactotron/assets/1761434/d1c2d3fb-38b2-4f0a-96f4-e021fc41fb46) --------- Co-authored-by: Frank Calise <[email protected]>
1 parent 39893d8 commit f1472d7

File tree

4 files changed

+134
-25
lines changed

4 files changed

+134
-25
lines changed

apps/reactotron-app/src/renderer/pages/timeline/index.tsx

+35-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useCallback, useContext, useMemo } from "react"
2-
import { clipboard } from "electron"
2+
import { clipboard, shell } from "electron"
33
import fs from "fs"
44
import debounce from "lodash.debounce"
55
import {
@@ -10,6 +10,7 @@ import {
1010
EmptyState,
1111
ReactotronContext,
1212
TimelineContext,
13+
RandomJoke,
1314
} from "reactotron-core-ui"
1415
import { MdSearch, MdDeleteSweep, MdFilterList, MdSwapVert, MdReorder } from "react-icons/md"
1516
import { FaTimes } from "react-icons/fa"
@@ -20,13 +21,11 @@ const Container = styled.div`
2021
flex-direction: column;
2122
width: 100%;
2223
`
23-
2424
const TimelineContainer = styled.div`
2525
height: 100%;
2626
overflow-y: auto;
2727
overflow-x: hidden;
2828
`
29-
3029
const SearchContainer = styled.div`
3130
display: flex;
3231
align-items: center;
@@ -48,6 +47,27 @@ const SearchInput = styled.input`
4847
color: ${(props) => props.theme.foregroundDark};
4948
font-size: 14px;
5049
`
50+
const HelpMessage = styled.div`
51+
margin: 0 40px;
52+
`
53+
const QuickStartButtonContainer = styled.div`
54+
display: flex;
55+
padding: 4px 8px;
56+
margin: 30px 20px;
57+
border-radius: 4px;
58+
cursor: pointer;
59+
background-color: ${(props) => props.theme.backgroundLighter};
60+
color: ${(props) => props.theme.foreground};
61+
align-items: center;
62+
justify-content: center;
63+
text-align: center;
64+
`
65+
const Divider = styled.div`
66+
height: 1px;
67+
background-color: ${(props) => props.theme.foregroundDark};
68+
margin: 40px 10px;
69+
`
70+
5171
export const ButtonContainer = styled.div`
5272
padding: 10px;
5373
cursor: pointer;
@@ -80,6 +100,10 @@ function Timeline() {
80100
sendCommand("state.action.dispatch", { action })
81101
}
82102

103+
function openDocs() {
104+
shell.openExternal("https://docs.infinite.red/reactotron/quick-start/react-native/")
105+
}
106+
83107
const { searchString, handleInputChange } = useDebouncedSearchInput(search, setSearch, 300)
84108

85109
return (
@@ -139,7 +163,14 @@ function Timeline() {
139163
<TimelineContainer>
140164
{filteredCommands.length === 0 ? (
141165
<EmptyState icon={MdReorder} title="No Activity">
142-
Once your app connects and starts sending events, they will appear here.
166+
<HelpMessage>
167+
Once your app connects and starts sending events, they will appear here.
168+
</HelpMessage>
169+
<QuickStartButtonContainer onClick={openDocs}>
170+
Check out the quick start guide here!
171+
</QuickStartButtonContainer>
172+
<Divider />
173+
<RandomJoke />
143174
</EmptyState>
144175
) : (
145176
filteredCommands.map((command) => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import React, { useEffect, useRef } from "react"
2+
import styled from "styled-components"
3+
4+
const JokeSetup = styled.div`
5+
font-size: 14px;
6+
color: ${(props) => props.theme.foregroundDark};
7+
font-weight: bold;
8+
`
9+
const JokePunchline = styled.div`
10+
font-size: 14px;
11+
color: ${(props) => props.theme.foregroundDark};
12+
font-style: italic;
13+
margin-top: 5px;
14+
`
15+
16+
const jokes = [
17+
{
18+
setup: "Why was the JavaScript developer sad?",
19+
punchline: "Because he didn't Node how to Express himself.",
20+
},
21+
{
22+
setup: "How does a debugger break up a fight?",
23+
punchline: "It steps in.",
24+
},
25+
{
26+
setup: "Why do programmers prefer dark mode?",
27+
punchline: "Because light attracts bugs!",
28+
},
29+
{
30+
setup: "Why did the developer go broke?",
31+
punchline: "Because he lost his domain in a bet!",
32+
},
33+
{
34+
setup: "Why did the programmer quit his job?",
35+
punchline: "Because he didn't get arrays!",
36+
},
37+
{
38+
setup: "How do you comfort a JavaScript bug?",
39+
punchline: "You console it.",
40+
},
41+
{
42+
setup: "Why don't programmers like nature?",
43+
punchline: "It has too many bugs.",
44+
},
45+
{
46+
setup: "What's a debugger's favorite music? ",
47+
punchline: "Break beats",
48+
},
49+
{
50+
setup: "Why don't debuggers get along with compilers?",
51+
punchline: "They always point out each other's mistakes.",
52+
},
53+
{
54+
setup: "Why was the debugger bad at hide and seek?",
55+
punchline: "It always showed where the bugs were hiding.",
56+
},
57+
]
58+
59+
export function RandomJoke() {
60+
const jokeRef = useRef(0)
61+
62+
useEffect(() => {
63+
const ref = Math.floor(Math.random() * jokes.length)
64+
jokeRef.current = ref
65+
}, [])
66+
67+
return (
68+
<>
69+
<JokeSetup>{jokes[jokeRef.current].setup}</JokeSetup>
70+
<JokePunchline>{jokes[jokeRef.current].punchline}</JokePunchline>
71+
</>
72+
)
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { RandomJoke } from "./RandomJoke"
2+
3+
export default RandomJoke

lib/reactotron-core-ui/src/index.ts

+23-21
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@
22
import theme from "./theme"
33

44
// Components
5+
import ActionButton from "./components/ActionButton"
56
import ContentView from "./components/ContentView"
67
import EmptyState from "./components/EmptyState"
78
import Header from "./components/Header"
89
import Modal from "./components/Modal"
10+
import RandomJoke from "./components/RandomJoke"
911
import ReactotronAppProvider from "./components/ReactotronAppProvider"
10-
import ActionButton from "./components/ActionButton"
11-
import Tooltip from "./components/Tooltip"
1212
import TimelineCommand from "./components/TimelineCommand"
1313
import TimelineCommandTabButton from "./components/TimelineCommandTabButton"
1414
import Timestamp from "./components/Timestamp"
15+
import Tooltip from "./components/Tooltip"
1516
import TreeView from "./components/TreeView"
1617

1718
// Contexts
@@ -35,36 +36,37 @@ import repairSerialization from "./utils/repair-serialization"
3536
import filterCommands from "./utils/filterCommands"
3637

3738
export {
38-
theme,
39+
// Contexts
40+
ActionButton,
3941
ContentView,
42+
CustomCommandsContext,
43+
CustomCommandsProvider,
44+
DispatchActionModal,
4045
EmptyState,
46+
filterCommands,
4147
Header,
4248
Modal,
49+
RandomJoke,
50+
ReactNativeContext,
51+
ReactNativeProvider,
4352
ReactotronAppProvider,
44-
ActionButton,
45-
Tooltip,
46-
TimelineCommand,
47-
timelineCommandResolver,
48-
TimelineCommandTabButton,
49-
DispatchActionModal,
50-
SnapshotRenameModal,
51-
SubscriptionAddModal,
52-
TimelineFilterModal,
53-
Timestamp,
54-
TreeView,
55-
repairSerialization,
56-
filterCommands,
57-
// Contexts
5853
ReactotronContext,
5954
ReactotronProvider,
60-
CustomCommandsContext,
61-
CustomCommandsProvider,
62-
ReactNativeContext,
63-
ReactNativeProvider,
55+
repairSerialization,
56+
SnapshotRenameModal,
6457
StateContext,
6558
StateProvider,
59+
SubscriptionAddModal,
60+
theme,
61+
TimelineCommand,
62+
timelineCommandResolver,
63+
TimelineCommandTabButton,
6664
TimelineContext,
65+
TimelineFilterModal,
6766
TimelineProvider,
67+
Timestamp,
68+
Tooltip,
69+
TreeView,
6870
}
6971

7072
export type { CustomCommand } from "./contexts/CustomCommands/useCustomCommands"

0 commit comments

Comments
 (0)