Skip to content

Commit be8b211

Browse files
authored
Toolbar hide button, search imoprovements and visual polish (#470)
https://github.com/user-attachments/assets/81c184ee-eeaa-4391-a213-103409d7fa27 - Add button to hide the toolbar current session - Add button to open the Reflag webapp - Don't use blurred transparency for toolbar background, simplify transitions - Improve search: write No flags found when no flags are loaded instead of No flags matching "null" found - Improve search: better consistently handle lowercased flag keys and search query - Improve search: always list flags that start with search query first
1 parent 0443d1c commit be8b211

File tree

13 files changed

+240
-124
lines changed

13 files changed

+240
-124
lines changed

packages/browser-sdk/example/typescript/app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ReflagClient, CheckEvent, RawFlags } from "../../src";
22

3-
const urlParams = new URLSearchParams(window.location.search);
3+
const urlParams = new URLSearchParams(window?.location?.search);
44
const publishableKey = urlParams.get("publishableKey");
55
const flagKey = urlParams.get("flagKey") ?? "huddles";
66

packages/browser-sdk/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<meta name="color-scheme" content="light dark" />
88
<title>Reflag Browser SDK</title>
99
</head>
10-
<body style="background-color: black">
10+
<body style="background-color: white">
1111
<div id="app"></div>
1212
<span id="loading">Loading...</span>
1313

packages/browser-sdk/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@reflag/browser-sdk",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"packageManager": "[email protected]",
55
"license": "MIT",
66
"repository": {

packages/browser-sdk/src/toolbar/Flags.css

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
color: white;
55
width: 100%;
66
font-size: var(--text-size);
7+
height: 28px;
78

89
&::placeholder {
910
color: var(--gray500);
@@ -44,29 +45,19 @@
4445
}
4546

4647
.flag-row {
47-
opacity: 0;
48-
transform: translateY(-7px);
49-
transition-property: opacity, transform;
50-
transition-duration: 0.075s;
51-
transition-timing-function: cubic-bezier(0.75, -0.015, 0.565, 1.055);
52-
53-
&.show-on-open {
54-
opacity: 1;
55-
transform: translateY(0);
56-
/* stagger effect where first item (i=0) has no delay,
57-
and delay is based on item count (n) so total animation time always is 509ms */
58-
transition-delay: calc(0.05s * var(--i) / max(var(--n) - 1, 1));
59-
}
60-
6148
&.not-visible {
6249
visibility: hidden;
6350
}
6451
}
6552

66-
.flag-empty-cell {
67-
width: 100%;
53+
.flags-table-empty {
54+
position: absolute;
55+
top: 0;
56+
left: 0;
57+
right: 0;
6858
color: var(--gray500);
69-
padding: 6px 0;
59+
padding: 12px 12px;
60+
line-height: 1.5;
7061
}
7162

7263
.flag-name-cell {

packages/browser-sdk/src/toolbar/Flags.tsx

Lines changed: 46 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,50 @@
1-
import { h } from "preact";
2-
import { useEffect, useState } from "preact/hooks";
1+
import { Fragment, h } from "preact";
32

43
import { Switch } from "./Switch";
54
import { FlagItem } from "./Toolbar";
65

6+
const isFound = (flagKey: string, searchQuery: string | null) => {
7+
return flagKey.toLocaleLowerCase().includes(searchQuery ?? "");
8+
};
9+
710
export function FlagsTable({
811
flags,
912
searchQuery,
1013
appBaseUrl,
11-
isOpen,
1214
setIsEnabledOverride,
1315
}: {
1416
flags: FlagItem[];
1517
searchQuery: string | null;
1618
appBaseUrl: string;
17-
isOpen: boolean;
1819
setIsEnabledOverride: (key: string, isEnabled: boolean | null) => void;
1920
}) {
2021
const hasFlags = flags.length > 0;
2122
const hasShownFlags = flags.some((flag) =>
22-
flag.flagKey
23-
.toLocaleLowerCase()
24-
.includes(searchQuery?.toLocaleLowerCase() ?? ""),
23+
isFound(flag.flagKey, searchQuery),
2524
);
2625

2726
// List flags that match the search query first then alphabetically
2827
const searchedFlags =
2928
searchQuery === null
3029
? flags
3130
: [...flags].sort((a, b) => {
32-
const aMatches = a.flagKey.includes(searchQuery);
33-
const bMatches = b.flagKey.includes(searchQuery);
31+
const aMatches = isFound(a.flagKey, searchQuery);
32+
const bMatches = isFound(b.flagKey, searchQuery);
3433

3534
// If both match or both don't match, sort alphabetically
3635
if (aMatches === bMatches) {
36+
const aStartsWith = a.flagKey
37+
.toLocaleLowerCase()
38+
.startsWith(searchQuery);
39+
const bStartsWith = b.flagKey
40+
.toLocaleLowerCase()
41+
.startsWith(searchQuery);
42+
43+
// If one starts with search query and the other doesn't, prioritize the one that starts with it
44+
if (aStartsWith && !bStartsWith) return -1;
45+
if (bStartsWith && !aStartsWith) return 1;
46+
47+
// Otherwise sort alphabetically
3748
return a.flagKey.localeCompare(b.flagKey);
3849
}
3950

@@ -42,67 +53,51 @@ export function FlagsTable({
4253
});
4354

4455
return (
45-
<table class="flags-table" style={{ "--n": searchedFlags.length }}>
46-
<tbody>
47-
{(!hasFlags || !hasShownFlags) && (
48-
<tr>
49-
<td class="flag-empty-cell" colSpan={3}>
50-
No flags {!hasShownFlags ? `matching "${searchQuery} "` : ""}
51-
found
52-
</td>
53-
</tr>
54-
)}
55-
{searchedFlags.map((flag, index) => (
56-
<FlagRow
57-
key={flag.flagKey}
58-
appBaseUrl={appBaseUrl}
59-
flag={flag}
60-
index={index}
61-
isNotVisible={
62-
searchQuery !== null &&
63-
!flag.flagKey
64-
.toLocaleLowerCase()
65-
.includes(searchQuery.toLocaleLowerCase())
66-
}
67-
isOpen={isOpen}
68-
setEnabledOverride={(override) =>
69-
setIsEnabledOverride(flag.flagKey, override)
70-
}
71-
/>
72-
))}
73-
</tbody>
74-
</table>
56+
<Fragment>
57+
{(!hasFlags || !hasShownFlags) && (
58+
<div class="flags-table-empty">
59+
No flags {hasFlags ? `matching "${searchQuery}"` : "found"}
60+
</div>
61+
)}
62+
<table class="flags-table">
63+
<tbody>
64+
{searchedFlags.map((flag, index) => (
65+
<FlagRow
66+
key={flag.flagKey}
67+
appBaseUrl={appBaseUrl}
68+
flag={flag}
69+
index={index}
70+
isNotVisible={
71+
searchQuery !== null && !isFound(flag.flagKey, searchQuery)
72+
}
73+
setEnabledOverride={(override) =>
74+
setIsEnabledOverride(flag.flagKey, override)
75+
}
76+
/>
77+
))}
78+
</tbody>
79+
</table>
80+
</Fragment>
7581
);
7682
}
7783

7884
function FlagRow({
7985
setEnabledOverride,
8086
appBaseUrl,
8187
flag,
82-
isOpen,
8388
index,
8489
isNotVisible,
8590
}: {
8691
flag: FlagItem;
8792
appBaseUrl: string;
8893
setEnabledOverride: (isEnabled: boolean | null) => void;
89-
isOpen: boolean;
9094
index: number;
9195
isNotVisible: boolean;
9296
}) {
93-
const [showOnOpen, setShowOnOpen] = useState(isOpen);
94-
useEffect(() => {
95-
setShowOnOpen(isOpen);
96-
}, [isOpen]);
9797
return (
9898
<tr
9999
key={flag.flagKey}
100-
class={[
101-
"flag-row",
102-
showOnOpen ? "show-on-open" : undefined,
103-
isNotVisible ? "not-visible" : undefined,
104-
].join(" ")}
105-
style={{ "--i": index }}
100+
class={["flag-row", isNotVisible ? "not-visible" : undefined].join(" ")}
106101
>
107102
<td class="flag-name-cell">
108103
<a

packages/browser-sdk/src/toolbar/Switch.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
}
2525

2626
.switch-input:focus-visible + .switch-track {
27-
outline: none;
28-
box-shadow: 0 0 0 1px #fff;
27+
outline: 1px solid #fff;
28+
outline-offset: 1px;
2929
}
3030

3131
.switch[data-enabled="true"] .switch-track {

0 commit comments

Comments
 (0)