@ably/ui 7.10.0 → 8.0.0-dev.43132fe
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/core/Meganav/component.css +5 -1
- package/core/Meganav/component.js +2 -1
- package/core/Meganav/component.js.LICENSE.txt +7 -0
- package/core/Meganav.jsx +7905 -2809
- package/core/MeganavContentPlatform.jsx +27 -20
- package/core/MeganavContentWhyAbly.jsx +1 -1
- package/core/MeganavControl/component.js +1 -1
- package/core/MeganavControl.jsx +5 -3
- package/core/MeganavItemsDesktop.jsx +5 -3
- package/core/MeganavItemsMobile.jsx +188 -11
- package/core/MeganavItemsSignedIn.jsx +259 -7
- package/core/MeganavSearch/component.js +1 -0
- package/core/MeganavSearch.jsx +504 -0
- package/core/MeganavSearchAutocomplete/component.js +2 -0
- package/core/MeganavSearchAutocomplete/component.js.LICENSE.txt +7 -0
- package/core/MeganavSearchAutocomplete.jsx +117 -0
- package/core/MeganavSearchPanel/component.js +1 -0
- package/core/MeganavSearchPanel.jsx +455 -0
- package/core/MeganavSearchSuggestions/component.js +1 -0
- package/core/MeganavSearchSuggestions.jsx +366 -0
- package/core/fonts/.DS_Store +0 -0
- package/core/fonts/source-code-pro.css +3 -0
- package/core/images/.DS_Store +0 -0
- package/core/scripts.js +1 -1
- package/core/styles.css +18 -36
- package/package.json +2 -1
- package/preview/vendor/bundle/ruby/3.0.0/bundler/gems/ably-ui-abffd210ec0f/preview/log/.keep +0 -0
- package/preview/vendor/bundle/ruby/3.0.0/bundler/gems/ably-ui-abffd210ec0f/preview/tmp/.keep +0 -0
- package/preview/vendor/bundle/ruby/3.0.0/bundler/gems/ably-ui-abffd210ec0f/preview/tmp/pids/.keep +0 -0
- package/src/.DS_Store +0 -0
- package/src/core/.DS_Store +0 -0
- package/src/core/Code/component.css +1 -3
- package/src/core/Meganav/component.css +5 -1
- package/src/core/Meganav/component.html.erb +10 -5
- package/src/core/Meganav/component.js +11 -1
- package/src/core/Meganav/component.jsx +15 -7
- package/src/core/MeganavContentPlatform/component.html.erb +24 -18
- package/src/core/MeganavContentPlatform/component.jsx +25 -20
- package/src/core/MeganavControl/component.html.erb +2 -2
- package/src/core/MeganavControl/component.js +37 -12
- package/src/core/MeganavControl/component.jsx +3 -2
- package/src/core/MeganavControl/component.rb +3 -1
- package/src/core/MeganavItemsMobile/component.html.erb +30 -2
- package/src/core/MeganavItemsMobile/component.jsx +33 -2
- package/src/core/MeganavItemsSignedIn/component.html.erb +6 -2
- package/src/core/MeganavItemsSignedIn/component.jsx +7 -2
- package/src/core/MeganavSearch/component.html.erb +15 -0
- package/src/core/MeganavSearch/component.js +0 -0
- package/src/core/MeganavSearch/component.jsx +33 -0
- package/src/core/MeganavSearch/component.rb +13 -0
- package/src/core/MeganavSearchAutocomplete/component.html.erb +6 -0
- package/src/core/MeganavSearchAutocomplete/component.js +177 -0
- package/src/core/MeganavSearchAutocomplete/component.jsx +14 -0
- package/src/core/MeganavSearchAutocomplete/component.rb +6 -0
- package/src/core/MeganavSearchPanel/component.html.erb +22 -0
- package/src/core/MeganavSearchPanel/component.js +0 -0
- package/src/core/MeganavSearchPanel/component.jsx +39 -0
- package/src/core/MeganavSearchPanel/component.rb +13 -0
- package/src/core/MeganavSearchSuggestions/component.html.erb +22 -0
- package/src/core/MeganavSearchSuggestions/component.js +123 -0
- package/src/core/MeganavSearchSuggestions/component.jsx +49 -0
- package/src/core/MeganavSearchSuggestions/component.rb +18 -0
- package/src/core/fonts/.DS_Store +0 -0
- package/src/core/fonts/source-code-pro.css +3 -0
- package/src/core/images/.DS_Store +0 -0
- package/src/core/remote-blogs-posts.js +1 -1
- package/src/core/remote-session-data.js +1 -1
- package/src/core/styles/properties.css +6 -3
- package/src/core/styles/text.css +12 -16
- package/src/core/styles.components.css +0 -15
- package/src/reset/.DS_Store +0 -0
- package/tailwind.config.js +14 -4
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { queryId } from "../dom-query";
|
|
2
|
+
import AddSearchClient from "addsearch-js-client";
|
|
3
|
+
|
|
4
|
+
const init = ({ input, container, listContainer, clear, client }) => {
|
|
5
|
+
client.setAnalyticsTag("Meganav autocomplete");
|
|
6
|
+
client.setThrottleTime(400);
|
|
7
|
+
|
|
8
|
+
const clearResults = () => {
|
|
9
|
+
container.classList.add("hidden");
|
|
10
|
+
listContainer.innerHTML = "";
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const toggleClearBtn = (query) => {
|
|
14
|
+
if ((query || "").length > 0 && clear) {
|
|
15
|
+
clear.classList.remove("invisible");
|
|
16
|
+
} else if (clear) {
|
|
17
|
+
clear.classList.add("invisible");
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const markQueryInSuggestion = (suggestionValue, query) => {
|
|
22
|
+
return suggestionValue.replace(
|
|
23
|
+
query.toLowerCase(),
|
|
24
|
+
`<span class="font-light">${query}</span>`
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const navigateToUrl = (q) => (window.location = `/search?q=${q}`);
|
|
29
|
+
|
|
30
|
+
const focusNext = (index) => {
|
|
31
|
+
const nextSuggestion = listContainer.querySelector(
|
|
32
|
+
`[data-suggestion-index="${index + 1}"]`
|
|
33
|
+
);
|
|
34
|
+
if (!nextSuggestion) return;
|
|
35
|
+
nextSuggestion.focus();
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const focusPrevious = (index) => {
|
|
39
|
+
const previousIndex = index - 1;
|
|
40
|
+
|
|
41
|
+
const previousSuggestion = listContainer.querySelector(
|
|
42
|
+
`[data-suggestion-index="${previousIndex}"]`
|
|
43
|
+
);
|
|
44
|
+
if (!previousSuggestion) return;
|
|
45
|
+
previousSuggestion.focus();
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const renderResults =
|
|
49
|
+
(query) =>
|
|
50
|
+
(results = {}) => {
|
|
51
|
+
toggleClearBtn(query);
|
|
52
|
+
|
|
53
|
+
// Prevent invalid access error when key is invalid
|
|
54
|
+
if (!Array.isArray(results.suggestions)) {
|
|
55
|
+
clearResults();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Prevent key error from invalid key
|
|
60
|
+
if (results.suggestions.length === 0) {
|
|
61
|
+
clearResults();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const items = results.suggestions.map((suggestion, index) => {
|
|
66
|
+
const li = document.createElement("li");
|
|
67
|
+
const button = document.createElement("button");
|
|
68
|
+
button.type = "button";
|
|
69
|
+
|
|
70
|
+
button.classList.add(
|
|
71
|
+
"ui-text-menu2",
|
|
72
|
+
"font-medium",
|
|
73
|
+
"p-8",
|
|
74
|
+
"w-full",
|
|
75
|
+
"text-left",
|
|
76
|
+
"rounded",
|
|
77
|
+
"hover:text-gui-hover",
|
|
78
|
+
"focus:outline-gui-focus",
|
|
79
|
+
"hover:bg-light-grey"
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
button.innerHTML = markQueryInSuggestion(suggestion.value, query);
|
|
83
|
+
|
|
84
|
+
button.dataset.suggestionIndex = index;
|
|
85
|
+
|
|
86
|
+
button.addEventListener("click", () => {
|
|
87
|
+
navigateToUrl(suggestion.value);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
button.addEventListener("keydown", (e) => {
|
|
91
|
+
const key = e.key;
|
|
92
|
+
|
|
93
|
+
if (key === "ArrowDown") {
|
|
94
|
+
focusNext(index);
|
|
95
|
+
} else if (key === "ArrowUp" && index - 1 < 0) {
|
|
96
|
+
input.focus();
|
|
97
|
+
} else if (key === "ArrowUp" && index - 1 >= 0) {
|
|
98
|
+
focusPrevious(index);
|
|
99
|
+
} else if (key === "Enter" || key === "Space") {
|
|
100
|
+
navigateToUrl(suggestion.value);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
li.appendChild(button);
|
|
105
|
+
return li;
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
listContainer.innerHTML = "";
|
|
109
|
+
items.forEach((item) => listContainer.appendChild(item));
|
|
110
|
+
container.classList.remove("hidden");
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const keyupHandler = (e) => {
|
|
114
|
+
const query = e.target.value;
|
|
115
|
+
const key = e.key;
|
|
116
|
+
|
|
117
|
+
if (key === "ArrowDown") {
|
|
118
|
+
focusNext(0);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!query) {
|
|
123
|
+
clearResults();
|
|
124
|
+
} else {
|
|
125
|
+
client.suggestions(query, renderResults(query));
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
let clearHandler;
|
|
130
|
+
if (clear) {
|
|
131
|
+
clearHandler = () => {
|
|
132
|
+
input.value = "";
|
|
133
|
+
clear.classList.add("invisible");
|
|
134
|
+
clearResults();
|
|
135
|
+
};
|
|
136
|
+
clear.addEventListener("click", clearHandler);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
input.addEventListener("keyup", keyupHandler);
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
teardown: () => {
|
|
143
|
+
input.removeEventListener("keyup", keyupHandler);
|
|
144
|
+
if (clear) clear.removeEventListener("click", clearHandler);
|
|
145
|
+
},
|
|
146
|
+
clear: () => {
|
|
147
|
+
input.value = "";
|
|
148
|
+
clearResults();
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export default (apiKey) => {
|
|
154
|
+
if (!apiKey) {
|
|
155
|
+
console.log(`No AddSearch API key provided, skipping search suggestions.`);
|
|
156
|
+
return [];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const client = new AddSearchClient(apiKey);
|
|
160
|
+
|
|
161
|
+
return [
|
|
162
|
+
queryId("meganav-search-input"),
|
|
163
|
+
queryId("meganav-mobile-search-input"),
|
|
164
|
+
]
|
|
165
|
+
.filter((i) => i)
|
|
166
|
+
.map((input) => {
|
|
167
|
+
const parent = input.parentNode;
|
|
168
|
+
const container = queryId(
|
|
169
|
+
"meganav-search-autocomplete-container",
|
|
170
|
+
parent
|
|
171
|
+
);
|
|
172
|
+
const listContainer = queryId("meganav-search-autocomplete-list", parent);
|
|
173
|
+
const clear = queryId("meganav-search-input-clear", parent);
|
|
174
|
+
|
|
175
|
+
return init({ input, container, listContainer, client, clear });
|
|
176
|
+
});
|
|
177
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
const MeganavSearchAutocomplete = () => {
|
|
4
|
+
return (
|
|
5
|
+
<div
|
|
6
|
+
className="absolute w-full mt-8 z-10 hidden shadow-container rounded-lg bg-white border border-mid-grey"
|
|
7
|
+
data-id="meganav-search-autocomplete-container"
|
|
8
|
+
>
|
|
9
|
+
<ol className="m-16" data-id="meganav-search-autocomplete-list"></ol>
|
|
10
|
+
</div>
|
|
11
|
+
);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default MeganavSearchAutocomplete;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<section class="ui-meganav-content grid-cols-12">
|
|
2
|
+
<div class="col-span-8">
|
|
3
|
+
<div class="mb-32">
|
|
4
|
+
<%= tag.form class: "flex items-start", action: abs_url("/search"), method: "get" do %>
|
|
5
|
+
<div class="relative w-full">
|
|
6
|
+
<%= render(AblyUi::Core::Icon.new(name: "icon-gui-search", size: "1.5rem", color: "text-cool-black", additional_css:"absolute top-12 left-16")) %>
|
|
7
|
+
<input type="search" name="q" class="ui-input pl-48 h-48" placeholder="Search" autocomplete="off" data-id="meganav-search-input" />
|
|
8
|
+
|
|
9
|
+
<%= render(AblyUi::Core::MeganavSearchAutocomplete.new) %>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<button type="submit" class="ui-btn-secondary flex-shrink-0 ml-8 sm:ml-16 md:ml-24 xl:ml-32">
|
|
13
|
+
Search
|
|
14
|
+
</button>
|
|
15
|
+
<% end %>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div class="col-span-12">
|
|
20
|
+
<%= render(AblyUi::Core::MeganavSearchSuggestions.new(url_base: url_base)) %>
|
|
21
|
+
</div>
|
|
22
|
+
</section>
|
|
File without changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import T from "prop-types";
|
|
3
|
+
|
|
4
|
+
import Icon from "../Icon/component.jsx";
|
|
5
|
+
import MeganavSearchSuggestions from "../MeganavSearchSuggestions/component.jsx";
|
|
6
|
+
import MeganavSearchAutocomplete from "../MeganavSearchAutocomplete/component.jsx";
|
|
7
|
+
|
|
8
|
+
const MeganavSearchPanel = ({ absUrl }) => {
|
|
9
|
+
return (
|
|
10
|
+
<section className="ui-meganav-content grid-cols-12">
|
|
11
|
+
<div className="col-span-8">
|
|
12
|
+
<div className="mb-32">
|
|
13
|
+
<form className="flex items-start" action={absUrl("/search")} method="get">
|
|
14
|
+
<div className="relative w-full">
|
|
15
|
+
<Icon name="icon-gui-search" color="text-cool-black" size="1.5rem" additionalCSS="absolute top-12 left-16" />
|
|
16
|
+
<input type="search" name="q" className="ui-input pl-48 h-48" placeholder="Search" autoComplete="off" data-id="meganav-search-input" />
|
|
17
|
+
|
|
18
|
+
<MeganavSearchAutocomplete />
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<button type="submit" className="ui-btn-secondary flex-shrink-0 ml-8 sm:ml-16 md:ml-24 xl:ml-32">
|
|
22
|
+
Search
|
|
23
|
+
</button>
|
|
24
|
+
</form>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div className="col-span-12">
|
|
29
|
+
<MeganavSearchSuggestions displaySupportLink={true} absUrl={absUrl} />
|
|
30
|
+
</div>
|
|
31
|
+
</section>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
MeganavSearchPanel.propTypes = {
|
|
36
|
+
absUrl: T.func,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default MeganavSearchPanel;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<p class="ui-text-overline2 text-cool-black py-12">Popular pages</p>
|
|
2
|
+
|
|
3
|
+
<div class="flex justify-between items-center overflow-hidden">
|
|
4
|
+
<ul class="flex transition-transform">
|
|
5
|
+
<li class="py-12 pr-8 flex-shrink-0">
|
|
6
|
+
<%= link_to 'How does Ably work?', abs_url("/docs/how-ably-works"), class: "ui-text-p2 hover:text-gui-hover active:text-gui-active focus:text-gui-focus" %>
|
|
7
|
+
</li>
|
|
8
|
+
<li class="py-12 px-8 flex-shrink-0">
|
|
9
|
+
<%= link_to 'Quickstart guide', abs_url("/docs/quick-start-guide"), class: "ui-text-p2 hover:text-gui-hover active:text-gui-active focus:text-gui-focus" %>
|
|
10
|
+
</li>
|
|
11
|
+
<li class="py-12 px-8 flex-shrink-0">
|
|
12
|
+
<%= link_to 'Publish/Subscribe Messaging', abs_url("/docs/core-features/pubsub"), class: "ui-text-p2 hover:text-gui-hover active:text-gui-active focus:text-gui-focus" %>
|
|
13
|
+
</li>
|
|
14
|
+
<li class="py-12 pl-8 flex-shrink-0">
|
|
15
|
+
<%= link_to 'Platform', abs_url("/docs/how-ably-works"), class: "ui-text-p2 hover:text-gui-hover active:text-gui-active focus:text-gui-focus" %>
|
|
16
|
+
</li>
|
|
17
|
+
</ul>
|
|
18
|
+
|
|
19
|
+
<% if display_support_link? %>
|
|
20
|
+
<%= render(AblyUi::Core::FeaturedLink.new(url: abs_url("/support"), text_size: "text-p2")) do %>Support<% end %>
|
|
21
|
+
<% end %>
|
|
22
|
+
</div>
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { queryId } from "../dom-query";
|
|
2
|
+
|
|
3
|
+
const DRAG_BUFFER = 5;
|
|
4
|
+
|
|
5
|
+
const getTranslateX = (node) =>
|
|
6
|
+
new DOMMatrix(window.getComputedStyle(node).transform).e;
|
|
7
|
+
|
|
8
|
+
const updateTranslateX = (node, value) =>
|
|
9
|
+
(node.style.transform = `translateX(${value}px)`);
|
|
10
|
+
|
|
11
|
+
const dragLeftBoundary = (translateX, threshold) => translateX >= threshold;
|
|
12
|
+
|
|
13
|
+
const dragRightBoundary = (translateX, itemsWidth, windowWidth, threshold) =>
|
|
14
|
+
Math.abs(translateX - windowWidth + threshold) > itemsWidth;
|
|
15
|
+
|
|
16
|
+
const getDistance = (e, touchStartX) =>
|
|
17
|
+
e.changedTouches[0]?.clientX - touchStartX;
|
|
18
|
+
|
|
19
|
+
const withinBuffer = (distance) => Math.abs(distance) < DRAG_BUFFER;
|
|
20
|
+
|
|
21
|
+
const MeganavSearchSuggestions = () => {
|
|
22
|
+
const suggestionsToggle = queryId("meganav-mobile-search-input");
|
|
23
|
+
const suggestions = queryId("meganav-mobile-search-suggestions");
|
|
24
|
+
const list = suggestions.querySelector("ul");
|
|
25
|
+
const listItems = list.querySelectorAll("li");
|
|
26
|
+
|
|
27
|
+
const itemsTotalWidth = Array.from(listItems)
|
|
28
|
+
.map((item) => item.getBoundingClientRect().width)
|
|
29
|
+
.reduce((acc, val) => acc + val, 0);
|
|
30
|
+
|
|
31
|
+
const dragLeft = (distance, threshold) => {
|
|
32
|
+
const currentTranslateX = getTranslateX(list);
|
|
33
|
+
const translateX = Math.round(currentTranslateX + distance);
|
|
34
|
+
if (dragLeftBoundary(translateX, threshold)) return;
|
|
35
|
+
updateTranslateX(list, translateX);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const dragLeftEnd = (distance, threshold) => {
|
|
39
|
+
const currentTranslateX = getTranslateX(list);
|
|
40
|
+
let translateX = Math.round(currentTranslateX + distance);
|
|
41
|
+
|
|
42
|
+
if (dragLeftBoundary(translateX, threshold)) {
|
|
43
|
+
translateX = 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
updateTranslateX(list, translateX);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const dragRight = (distance, threshold) => {
|
|
50
|
+
const listWidth = list.getBoundingClientRect().width;
|
|
51
|
+
const currentTranslateX = getTranslateX(list);
|
|
52
|
+
const translateX = Math.round(currentTranslateX + distance);
|
|
53
|
+
|
|
54
|
+
if (dragRightBoundary(translateX, itemsTotalWidth, listWidth, threshold)) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
updateTranslateX(list, translateX);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const dragRightEnd = (distance, threshold) => {
|
|
62
|
+
const listWidth = list.getBoundingClientRect().width;
|
|
63
|
+
const currentTranslateX = getTranslateX(list);
|
|
64
|
+
let translateX = Math.round(currentTranslateX + distance);
|
|
65
|
+
|
|
66
|
+
if (dragRightBoundary(translateX, itemsTotalWidth, listWidth, threshold)) {
|
|
67
|
+
translateX = -(itemsTotalWidth - listWidth + threshold);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
updateTranslateX(list, translateX);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
let touchStartX;
|
|
74
|
+
|
|
75
|
+
const touchstartHandler = (e) => {
|
|
76
|
+
touchStartX = e.touches[0]?.clientX;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const touchmoveHandler = (e) => {
|
|
80
|
+
const distance = getDistance(e, touchStartX);
|
|
81
|
+
if (withinBuffer(distance)) return;
|
|
82
|
+
distance > 0 ? dragLeft(distance, 24) : dragRight(distance, 96);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const touchendHandler = (e) => {
|
|
86
|
+
const distance = getDistance(e, touchStartX);
|
|
87
|
+
if (withinBuffer(distance)) return;
|
|
88
|
+
distance > 0 ? dragLeftEnd(distance, 24) : dragRightEnd(distance, 48);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const focusSuggestionsHandler = () => {
|
|
92
|
+
suggestions.classList.add("max-h-96");
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const blurSuggestionsHandler = (e) => {
|
|
96
|
+
if (e.relatedTarget === suggestions.querySelectorAll("a")[0]) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
suggestions.classList.remove("max-h-96");
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
suggestionsToggle.addEventListener("focus", focusSuggestionsHandler);
|
|
103
|
+
suggestionsToggle.addEventListener("blur", blurSuggestionsHandler);
|
|
104
|
+
suggestions.addEventListener("touchstart", touchstartHandler);
|
|
105
|
+
suggestions.addEventListener("touchmove", touchmoveHandler);
|
|
106
|
+
suggestions.addEventListener("touchend", touchendHandler);
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
teardown: () => {
|
|
110
|
+
suggestionsToggle.removeEventListener("focus", focusSuggestionsHandler);
|
|
111
|
+
suggestionsToggle.removeEventListener("blur", blurSuggestionsHandler);
|
|
112
|
+
suggestions.removeEventListener("touchstart", touchstartHandler);
|
|
113
|
+
suggestions.removeEventListener("touchmove", touchmoveHandler);
|
|
114
|
+
suggestions.removeEventListener("touchend", touchendHandler);
|
|
115
|
+
},
|
|
116
|
+
clear: () => {
|
|
117
|
+
suggestions.classList.remove("max-h-96");
|
|
118
|
+
list.style.transform = `translateX(0px)`;
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export default MeganavSearchSuggestions;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import T from "prop-types";
|
|
3
|
+
|
|
4
|
+
import FeaturedLink from "../FeaturedLink/component.jsx";
|
|
5
|
+
|
|
6
|
+
const MeganavSearchSuggestions = ({ absUrl, displaySupportLink }) => {
|
|
7
|
+
return (
|
|
8
|
+
<>
|
|
9
|
+
<p className="ui-text-overline2 text-cool-black py-12">Popular pages</p>
|
|
10
|
+
|
|
11
|
+
<div className="flex justify-between items-center overflow-hidden">
|
|
12
|
+
<ul className="flex transition-transform">
|
|
13
|
+
<li className="py-12 pr-8 flex-shrink-0">
|
|
14
|
+
<a href={absUrl("/docs/how-ably-works")} className="ui-text-p2 hover:text-gui-hover active:text-gui-active focus:text-gui-focus">
|
|
15
|
+
How does Ably work?
|
|
16
|
+
</a>
|
|
17
|
+
</li>
|
|
18
|
+
<li className="py-12 px-8 flex-shrink-0">
|
|
19
|
+
<a href={absUrl("/docs/quick-start-guide")} className="ui-text-p2 hover:text-gui-hover active:text-gui-active focus:text-gui-focus">
|
|
20
|
+
Quickstart guide
|
|
21
|
+
</a>
|
|
22
|
+
</li>
|
|
23
|
+
<li className="py-12 px-8 flex-shrink-0">
|
|
24
|
+
<a href={absUrl("/docs/core-features/pubsub")} className="ui-text-p2 hover:text-gui-hover active:text-gui-active focus:text-gui-focus">
|
|
25
|
+
Publish/Subscribe Messaging
|
|
26
|
+
</a>
|
|
27
|
+
</li>
|
|
28
|
+
<li className="py-12 pl-8 flex-shrink-0">
|
|
29
|
+
<a href={absUrl("/platform")} className="ui-text-p2 hover:text-gui-hover active:text-gui-active focus:text-gui-focus">
|
|
30
|
+
Platform
|
|
31
|
+
</a>
|
|
32
|
+
</li>
|
|
33
|
+
</ul>
|
|
34
|
+
{displaySupportLink ? (
|
|
35
|
+
<FeaturedLink url={absUrl("/support")} textSize="text-p2">
|
|
36
|
+
Support
|
|
37
|
+
</FeaturedLink>
|
|
38
|
+
) : null}
|
|
39
|
+
</div>
|
|
40
|
+
</>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
MeganavSearchSuggestions.propTypes = {
|
|
45
|
+
absUrl: T.func,
|
|
46
|
+
displaySupportLink: T.bool,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default MeganavSearchSuggestions;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module AblyUi
|
|
2
|
+
module Core
|
|
3
|
+
class MeganavSearchSuggestions < ViewComponent::Base
|
|
4
|
+
include Util
|
|
5
|
+
|
|
6
|
+
attr_reader :url_base
|
|
7
|
+
|
|
8
|
+
def initialize(url_base:, display_support_link: true)
|
|
9
|
+
@url_base = url_base
|
|
10
|
+
@display_support_link = display_support_link
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def display_support_link?
|
|
14
|
+
@display_support_link
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
Binary file
|
|
Binary file
|
|
@@ -15,9 +15,10 @@
|
|
|
15
15
|
--color-charcoal-grey: #292831;
|
|
16
16
|
--color-gui-default: #0073e6;
|
|
17
17
|
--color-gui-hover: #0867c4;
|
|
18
|
-
--color-gui-focus: #
|
|
18
|
+
--color-gui-focus: #0073e6;
|
|
19
|
+
--color-gui-focus-outline: #80b9f2;
|
|
19
20
|
--color-gui-active: #074095;
|
|
20
|
-
--color-gui-
|
|
21
|
+
--color-gui-visited: #4887c2;
|
|
21
22
|
--color-gui-unavailable: #a8a8a8;
|
|
22
23
|
--color-gui-error: #fb0c0c;
|
|
23
24
|
--color-gui-success: #11cb24;
|
|
@@ -117,7 +118,9 @@
|
|
|
117
118
|
|
|
118
119
|
--spacing-0: 0px;
|
|
119
120
|
--spacing-1: 1px;
|
|
121
|
+
--spacing-2: 0.125rem;
|
|
120
122
|
--spacing-4: 0.25rem;
|
|
123
|
+
--spacing-6: 0.375rem;
|
|
121
124
|
--spacing-8: 0.5rem;
|
|
122
125
|
--spacing-12: 0.75rem;
|
|
123
126
|
--spacing-14: 0.875rem;
|
|
@@ -155,7 +158,7 @@
|
|
|
155
158
|
/* In components, when looking at implementing viewport margin and spacing between elements,
|
|
156
159
|
the values in the comments can be used as guide as they represent the grid the elements (should) sit on.
|
|
157
160
|
alternatively, look for ui-grid-* helpers. */
|
|
158
|
-
--bp-xs:
|
|
161
|
+
--bp-xs: 428px; /* gutters 8px, side-margin 24px */
|
|
159
162
|
--bp-sm: 768px; /* gutters 16px, side-margin 32px */
|
|
160
163
|
--bp-md: 1040px; /* gutters 24px, side-margin 40px, meganav desktop */
|
|
161
164
|
--bp-lg: 1280px; /* gutters 24px, side-margin 64px */
|
package/src/core/styles/text.css
CHANGED
|
@@ -30,17 +30,17 @@
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
.ui-text-p1 {
|
|
33
|
-
@apply font-sans font-light text-
|
|
33
|
+
@apply font-sans font-light text-charcoal-grey;
|
|
34
34
|
@apply text-p1;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
.ui-text-p2 {
|
|
38
|
-
@apply font-sans font-light text-
|
|
38
|
+
@apply font-sans font-light text-charcoal-grey;
|
|
39
39
|
@apply text-p2;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
.ui-text-p3 {
|
|
43
|
-
@apply font-sans font-light text-
|
|
43
|
+
@apply font-sans font-light text-charcoal-grey;
|
|
44
44
|
@apply text-p3;
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -146,21 +146,17 @@
|
|
|
146
146
|
@apply list-square;
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
/* visited needs to come before :hover et all else it overrides them */
|
|
150
|
-
.ui-link:visited {
|
|
151
|
-
@apply text-gui-viewed;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
149
|
.ui-link {
|
|
155
|
-
@apply
|
|
156
|
-
text-
|
|
157
|
-
text-
|
|
158
|
-
|
|
159
|
-
text-decoration-thickness: 0.125rem;
|
|
150
|
+
@apply visited:text-gui-visited;
|
|
151
|
+
@apply hover:text-gui-hover active:text-gui-active disabled:text-gui-unavailable;
|
|
152
|
+
@apply focus:text-gui-focus focus:outline-gui-focus;
|
|
153
|
+
@apply underline;
|
|
160
154
|
}
|
|
161
155
|
|
|
162
|
-
.ui-link
|
|
163
|
-
@apply
|
|
164
|
-
text-
|
|
156
|
+
.ui-link-neutral {
|
|
157
|
+
@apply visited:text-dark-grey;
|
|
158
|
+
@apply hover:text-dark-grey active:text-cool-black disabled:text-gui-unavailable;
|
|
159
|
+
@apply focus:text-gui-focus focus:outline-gui-focus-neutral;
|
|
160
|
+
@apply underline;
|
|
165
161
|
}
|
|
166
162
|
}
|
|
@@ -24,21 +24,6 @@
|
|
|
24
24
|
stroke: var(--color-dark-grey);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
/* Extend how tailwind does group hover for icons */
|
|
28
|
-
.group {
|
|
29
|
-
&:hover {
|
|
30
|
-
.group-hover\:icon-gui-hover {
|
|
31
|
-
stroke: var(--color-gui-hover);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
&:focus {
|
|
36
|
-
.group-focus\:icon-gui-focus {
|
|
37
|
-
stroke: var(--color-gui-focus);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
27
|
.ui-version-tag {
|
|
43
28
|
@apply inline-block absolute align-top uppercase font-bold whitespace-nowrap;
|
|
44
29
|
|
|
Binary file
|