giphy: Use GIPHY web SDK to allow inserting GIFs in compose box.

We use GIPHY web SDK to create popover containing GIFs in a
grid format. Simply clicking on the GIFs will insert the GIF in the compose
box.

We add GIPHY logo to compose box action icons which opens the GIPHY
picker popover containing GIFs with "Powered by GIPHY"
attribution.
This commit is contained in:
Aman Agrawal 2021-03-19 12:21:18 +00:00 committed by Tim Abbott
parent f00c13d303
commit 5e83965e80
32 changed files with 638 additions and 14 deletions

View File

@ -0,0 +1,47 @@
# GIPHY GIF integration
This page documents the server-level configuration required to enable
GIPHY integration to [add GIFs in your message][help-center-giphy] on
a self-hosted Zulip server.
To enable this integration, you need to get a production API key from
[GIPHY](https://developers.giphy.com/).
## Apply for API key
1. [Create a GIPHY account](https://giphy.com/join).
1. Create a GIPHY API Key by clicking “Create an App” on the
[Developer Dashboard][giphy-dashboard].
1. Choose **SDK** as product type and click **Next Step**.
1. Enter a name and a description for your app and click on **Create
New App**. The hostname for your Zulip server is a fine name.
1. You will receive a beta API key. Apply for a production API key
by following the steps mentioned by GIPHY on the same page.
You can then configure your Zulip server to use GIPHY API as
follows:
1. In `/etc/zulip/settings.py`, enter your GIPHY API key as
`GIPHY_API_KEY`.
GIPHY API keys are not secrets -- GIPHY expects every browser or
other client connecting to your Zulip server will receive a copy --
which is why they are configured in `settings.py` and not
`zulip-secrets.conf`.
1. Restart the Zulip server with
`/home/zulip/deployments/current/scripts/restart-server`.
Congratulations! You've configured the GIPHY integration for your
Zulip server. Your users can now use the integration as described in
[the help center article][help-center-giphy]. (A browser reload may
be required).
[help-center-giphy]: https://zulip.com/help/animated-gifs-from-giphy
[giphy-dashboard]: https://developers.giphy.com/dashboard/

View File

@ -22,3 +22,4 @@ Zulip in production
deployment deployment
email-gateway email-gateway
video-calls video-calls
giphy-gif-integration

View File

@ -11,6 +11,8 @@
"@babel/preset-env": "^7.5.5", "@babel/preset-env": "^7.5.5",
"@babel/preset-typescript": "^7.3.3", "@babel/preset-typescript": "^7.3.3",
"@babel/register": "^7.6.2", "@babel/register": "^7.6.2",
"@giphy/js-components": "^4.3.1",
"@giphy/js-fetch-api": "^2.4.0",
"@uppy/core": "^1.7.1", "@uppy/core": "^1.7.1",
"@uppy/progress-bar": "^1.3.4", "@uppy/progress-bar": "^1.3.4",
"@uppy/xhr-upload": "^1.4.2", "@uppy/xhr-upload": "^1.4.2",

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

View File

@ -16,6 +16,7 @@ import * as compose from "./compose";
import * as compose_actions from "./compose_actions"; import * as compose_actions from "./compose_actions";
import * as compose_state from "./compose_state"; import * as compose_state from "./compose_state";
import * as emoji_picker from "./emoji_picker"; import * as emoji_picker from "./emoji_picker";
import * as giphy from "./giphy";
import * as hash_util from "./hash_util"; import * as hash_util from "./hash_util";
import * as hotspots from "./hotspots"; import * as hotspots from "./hotspots";
import {i18n} from "./i18n"; import {i18n} from "./i18n";
@ -656,6 +657,49 @@ export function initialize() {
// COMPOSE // COMPOSE
// Allow inserting GIFs in compose box using enter keypress.
$("body").on("keydown", ".giphy-gif", convert_enter_to_click);
$("#compose_giphy_logo").on("click", (e) => {
e.preventDefault();
e.stopPropagation();
if ($("#giphy_grid_in_popover").length) {
$("#compose_box_giphy_grid").popover("hide");
return;
}
$("#compose_box_giphy_grid").popover("show");
let gifs_grid = giphy.renderGIPHYGrid($("#giphy_grid_in_popover .popover-content")[0]);
$("body").on(
"keyup",
"#giphy-search-query",
// Use debounce to create a 300ms interval between
// every search. This makes the UX of searching pleasant
// by allowing user to finish typing before search
// is executed.
_.debounce(() => {
// GIPHY popover may have been hidden by the
// time this function is called.
if (gifs_grid) {
gifs_grid.remove();
gifs_grid = giphy.update_grid_with_search_term();
}
}, 300),
);
$(document).one("compose_canceled.zulip compose_finished.zulip", () => {
$("#compose_box_giphy_grid").popover("hide");
});
// Focus on search box by default.
// This is specially helpful for users
// navigating via keybaord.
$("#giphy-search-query").trigger("focus");
});
$("body").on("keydown", "#compose_giphy_logo", convert_enter_to_click);
// NB: This just binds to current elements, and won't bind to elements // NB: This just binds to current elements, and won't bind to elements
// created after ready() is called. // created after ready() is called.
$("#compose-send-status .compose-send-status-close").on("click", () => { $("#compose-send-status .compose-send-status-close").on("click", () => {

99
static/js/giphy.js Normal file
View File

@ -0,0 +1,99 @@
import {renderGrid} from "@giphy/js-components";
import {GiphyFetch} from "@giphy/js-fetch-api";
import $ from "jquery";
import _ from "lodash";
import render_giphy_picker from "../templates/giphy_picker.hbs";
import render_giphy_picker_mobile from "../templates/giphy_picker_mobile.hbs";
import * as compose_ui from "./compose_ui";
import {page_params} from "./page_params";
const giphy_fetch = new GiphyFetch(page_params.giphy_api_key);
let search_term = "";
function fetchGifs(offset) {
const config = {
offset,
limit: 25,
// Default rating to 'g' until we can make this configurable.
rating: "g",
// We don't pass random_id here, for privacy reasons.
};
if (search_term === "") {
// Get the trending gifs by default.
return giphy_fetch.trending(config);
}
return giphy_fetch.search(search_term, config);
}
export function renderGIPHYGrid(targetEl) {
const render = () =>
// See https://github.com/Giphy/giphy-js/blob/master/packages/components/README.md#grid
// for detailed documentation.
renderGrid(
{
width: 300,
fetchGifs,
columns: 3,
gutter: 6,
noLink: true,
// Hide the creator attribution that appears over a
// GIF; nice in principle but too distracting.
hideAttribution: true,
onGifClick: (props) => {
$("#compose_box_giphy_grid").popover("hide");
compose_ui.insert_syntax_and_focus(`[](${props.images.downsized_medium.url})`);
},
onGifVisible: (gif, e) => {
// Set tabindex for all the GIFs that
// are visible to the user. This allows
// user to navigate the GIFs using tab.
// TODO: Remove this after https://github.com/Giphy/giphy-js/issues/174
// is closed.
e.target.tabIndex = 0;
},
},
targetEl,
);
// Limit the rate at which we do queries to the GIPHY API to
// one per 300ms, in line with animation timing, basically to avoid
// content appearing while the user is typing.
const resizeRender = _.throttle(render, 300);
window.addEventListener("resize", resizeRender, false);
const remove = render();
return {
remove: () => {
remove();
window.removeEventListener("resize", resizeRender, false);
},
};
}
let template = render_giphy_picker();
if (window.innerWidth <= 768) {
// Show as modal in the center for small screens.
template = render_giphy_picker_mobile();
}
$("#compose_box_giphy_grid").popover({
animation: true,
placement: "top",
html: true,
trigger: "manual",
template,
});
export function update_grid_with_search_term() {
const search_elem = $("#giphy-search-query");
// GIPHY popover may have been hidden by the
// time this function is called.
if (search_elem.length) {
search_term = search_elem[0].value;
return renderGIPHYGrid($("#giphy_grid_in_popover .popover-content")[0]);
}
// Return undefined to stop searching.
return undefined;
}

View File

@ -275,6 +275,13 @@ export function process_escape_key(e) {
} }
if (compose_state.composing()) { if (compose_state.composing()) {
// Hide GIPHY popover if it's open.
if ($("#giphy_grid_in_popover").length) {
$("#compose_box_giphy_grid").popover("hide");
$("#compose-textarea").trigger("focus");
return true;
}
// Check for errors in compose box; close errors if they exist // Check for errors in compose box; close errors if they exist
if ($("#compose-send-status").css("display") !== "none") { if ($("#compose-send-status").css("display") !== "none") {
$("#compose-send-status").hide(); $("#compose-send-status").hide();

View File

@ -398,6 +398,12 @@ input.recipient_box {
display: inline-block; display: inline-block;
} }
#compose_box_giphy_grid img {
width: auto;
height: 14px;
vertical-align: top;
}
a.message-control-button { a.message-control-button {
display: block; display: block;
opacity: 0.4; opacity: 0.4;

View File

@ -449,6 +449,57 @@ ul {
} }
} }
.popover.top .arrow::after {
left: -1px;
}
#giphy_grid_in_popover {
/* 300px of GIPHY grid + 15px scroll bar width */
width: 315px;
.giphy-gif {
cursor: pointer;
}
.giphy-gif-img:focus {
/* Red outline for clear visibility
* of which image is in foucs.
*/
outline-color: hsl(0, 100%, 50%);
}
.search-box {
display: flex;
position: sticky;
input {
flex-grow: 1;
margin: 5px;
}
}
.popover-content {
overflow: auto;
height: 200px;
}
.popover-footer {
text-align: center;
img {
width: 120px;
}
}
}
@media (max-width: 768px) {
#giphy_grid_in_popover {
position: static;
top: 0 !important;
left: 0 !important;
}
}
.user_info_status_text { .user_info_status_text {
opacity: 0.8; opacity: 0.8;
padding: 2px 0 3px 0; padding: 2px 0 3px 0;

View File

@ -0,0 +1,12 @@
<div class="popover" id="giphy_grid_in_popover">
<div class="arrow"></div>
<div class="popover-inner">
<div class="search-box">
<input type="text" tabindex=0 id="giphy-search-query" class="search-query" placeholder="{{t 'Search GIFs' }}">
</div>
<div class="popover-content"></div>
<div class="popover-footer">
<img src="/static/images/GIPHY_attribution.png" alt="{{t 'GIPHY attribution' }}">
</div>
</div>
</div>

View File

@ -0,0 +1,3 @@
<div class='popover-flex'>
{{> giphy_picker }}
</div>

View File

@ -10,6 +10,11 @@ below features are supported.
## Changes in Zulip 4.0 ## Changes in Zulip 4.0
**Feature level 47**
* [`POST /register`](/api/register-queue): Added a new `giphy_api_key`
field, which is required to fetch GIFs using the GIPHY API.
**Feature level 46** **Feature level 46**
* [`GET /messages`](/api/get-messages) and [`GET * [`GET /messages`](/api/get-messages) and [`GET

View File

@ -101,6 +101,11 @@
<a role="button" id="undo_markdown_preview" class="message-control-button fa fa-edit" aria-label="{{ _('Write') }}" tabindex=0 style="display:none;" title="{{ _('Write') }}"></a> <a role="button" id="undo_markdown_preview" class="message-control-button fa fa-edit" aria-label="{{ _('Write') }}" tabindex=0 style="display:none;" title="{{ _('Write') }}"></a>
<a role="button" class="message-control-button fa fa-video-camera video_link" aria-label="{{ _('Add video call') }}" tabindex=0 title="{{ _('Add video call') }}"></a> <a role="button" class="message-control-button fa fa-video-camera video_link" aria-label="{{ _('Add video call') }}" tabindex=0 title="{{ _('Add video call') }}"></a>
<a role="button" class="message-control-button fa fa-smile-o" aria-label="{{_('Add emoji')}}" id="emoji_map" tabindex=0 title="{{ _('Add emoji') }}"></a> <a role="button" class="message-control-button fa fa-smile-o" aria-label="{{_('Add emoji')}}" id="emoji_map" tabindex=0 title="{{ _('Add emoji') }}"></a>
{% if giphy_api_available %}
<a role="button" class="message-control-button" aria-label="{{_('Add GIF')}}" id="compose_box_giphy_grid" title="{{ _('Add GIF') }}">
<img id="compose_giphy_logo" tabindex=0 src="/static/images/GIPHY_logo.png">
</a>
{% endif %}
<a class="message-control-link drafts-link" href="#drafts" title="{{ _('Drafts') }} (d)">{{ _('Drafts') }}</a> <a class="message-control-link drafts-link" href="#drafts" title="{{ _('Drafts') }} (d)">{{ _('Drafts') }}</a>
<a role="button" class="message-control-link" tabindex=0 data-overlay-trigger="message-formatting">{{ _('Help') }}</a> <a role="button" class="message-control-link" tabindex=0 data-overlay-trigger="message-formatting">{{ _('Help') }}</a>
<span id="sending-indicator"></span> <span id="sending-indicator"></span>

View File

@ -287,6 +287,13 @@
on-premises installation at any time. on-premises installation at any time.
</p> </p>
</a> </a>
<a class="feature-block" href="/help/animated-gifs-from-giphy" target="_blank" rel="noopener noreferrer">
<h3>GIPHY INTEGRATION</h3>
<p>
Enjoy animated GIFs with Zulip's native GIPHY
integration.
</p>
</a>
<a class="feature-block" href="https://github.com/zulip/zulip/" target="_blank" rel="noopener noreferrer"> <a class="feature-block" href="https://github.com/zulip/zulip/" target="_blank" rel="noopener noreferrer">
<h3>YOUR FEATURE HERE</h3> <h3>YOUR FEATURE HERE</h3>
<p>Zulip is open source, so if something important for <p>Zulip is open source, so if something important for

View File

@ -0,0 +1,32 @@
# Animated GIFs from GIPHY
Zulip integrates with [GIPHY](https://giphy.com), allowing you to
conveniently search for animated GIFs and include them in your
messages.
Be thoughtful when using this feature! Animated GIFs can be fun, but
they can also distract from the content of a conversation.
1. First, [open the compose box](/help/open-the-compose-box).
1. **Click the GIPHY logo** at the bottom of the compose box. This
opens the GIPHY search tool.
1. Use the search tool to find a GIF you'd like to use.
1. **Click on an image** to insert a link to the GIF in the compose box.
1. Send the message. Zulip will display the GIF like any other linked
image.
You can [preview the
message](/help/preview-your-message-before-sending) before sending to
see what the message will look like.
## Troubleshooting
* If you don't see the GIPHY icon, this is likely because you are
using a self-hosted Zulip server that has not [configured the GIPHY
integration][configure-giphy].
[configure-giphy]: https://zulip.readthedocs.io/en/latest/production/giphy-gif-integration.html
* If your GIFs only appear as links after sending them, this is likely
because the organization has disabled [previews of linked
images](/help/allow-image-link-previews).

View File

@ -37,6 +37,7 @@
* [Mention a user or group](/help/mention-a-user-or-group) * [Mention a user or group](/help/mention-a-user-or-group)
* [Edit or delete a message](/help/edit-or-delete-a-message) * [Edit or delete a message](/help/edit-or-delete-a-message)
* [Message a stream by email](/help/message-a-stream-by-email) * [Message a stream by email](/help/message-a-stream-by-email)
* [Add GIFs in your message](/help/animated-gifs-from-giphy)
## Reading messages ## Reading messages
* [Reading strategies](/help/reading-strategies) * [Reading strategies](/help/reading-strategies)

View File

@ -0,0 +1,14 @@
# GIPHY GIF integration
Send animated GIFs with your message using GIPHY integration.
![](/static/images/GIPHY_zulip.png)
GIPHY is enabled by default in Zulip Cloud. If the you're on a
self-hosted server where the [GIPHY integration][help-center-giphy]
isn't already configured, see the [configuration
instructions][configure-giphy] to enable it.
[help-center-giphy]: /help/animated-gifs-from-giphy
[configure-giphy]: https://zulip.readthedocs.io/en/latest/production/giphy-gif-integration.html

View File

@ -157,6 +157,9 @@ IGNORED_PHRASES = [
r"your-organization-url", r"your-organization-url",
# Used in invite modal # Used in invite modal
r"or", r"or",
# Used in GIPHY popover.
r"GIFs",
r"GIPHY",
] ]
# Sort regexes in descending order of their lengths. As a result, the # Sort regexes in descending order of their lengths. As a result, the

View File

@ -63,6 +63,7 @@ EXEMPT_FILES = {
"static/js/feedback_widget.js", "static/js/feedback_widget.js",
"static/js/floating_recipient_bar.js", "static/js/floating_recipient_bar.js",
"static/js/gear_menu.js", "static/js/gear_menu.js",
"static/js/giphy.js",
"static/js/global.d.ts", "static/js/global.d.ts",
"static/js/hashchange.js", "static/js/hashchange.js",
"static/js/hbs.d.ts", "static/js/hbs.d.ts",

View File

@ -30,7 +30,7 @@ DESKTOP_WARNING_VERSION = "5.2.0"
# #
# Changes should be accompanied by documentation explaining what the # Changes should be accompanied by documentation explaining what the
# new level means in templates/zerver/api/changelog.md. # new level means in templates/zerver/api/changelog.md.
API_FEATURE_LEVEL = 46 API_FEATURE_LEVEL = 47
# Bump the minor PROVISION_VERSION to indicate that folks should provision # Bump the minor PROVISION_VERSION to indicate that folks should provision
# only when going from an old version of the code to a newer version. Bump # only when going from an old version of the code to a newer version. Bump
@ -45,4 +45,4 @@ API_FEATURE_LEVEL = 46
# historical commits sharing the same major version, in which case a # historical commits sharing the same major version, in which case a
# minor version bump suffices. # minor version bump suffices.
PROVISION_VERSION = "135.0" PROVISION_VERSION = "135.1"

265
yarn.lock
View File

@ -197,7 +197,7 @@
dependencies: dependencies:
"@babel/types" "^7.13.0" "@babel/types" "^7.13.0"
"@babel/helper-module-imports@^7.12.13": "@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.13":
version "7.12.13" version "7.12.13"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz#ec67e4404f41750463e455cc3203f6a32e93fcb0" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz#ec67e4404f41750463e455cc3203f6a32e93fcb0"
integrity sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g== integrity sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g==
@ -876,10 +876,10 @@
pirates "^4.0.0" pirates "^4.0.0"
source-map-support "^0.5.16" source-map-support "^0.5.16"
"@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.8.4": "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4":
version "7.13.9" version "7.13.10"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.9.tgz#97dbe2116e2630c489f22e0656decd60aaa1fcee" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d"
integrity sha512-aY2kU+xgJ3dJ1eU6FMB9EH8dIe8dmusF1xEku52joLvw6eAFN0AI+WxCLDnpev2LEejWBAy2sBvBOBAjI3zmvA== integrity sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==
dependencies: dependencies:
regenerator-runtime "^0.13.4" regenerator-runtime "^0.13.4"
@ -923,6 +923,62 @@
dependencies: dependencies:
commander "^2.15.1" commander "^2.15.1"
"@emotion/cache@^10.0.27":
version "10.0.29"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0"
integrity sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==
dependencies:
"@emotion/sheet" "0.9.4"
"@emotion/stylis" "0.8.5"
"@emotion/utils" "0.11.3"
"@emotion/weak-memoize" "0.2.5"
"@emotion/hash@0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
"@emotion/memoize@0.7.4":
version "0.7.4"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb"
integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==
"@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16":
version "0.11.16"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad"
integrity sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==
dependencies:
"@emotion/hash" "0.8.0"
"@emotion/memoize" "0.7.4"
"@emotion/unitless" "0.7.5"
"@emotion/utils" "0.11.3"
csstype "^2.5.7"
"@emotion/sheet@0.9.4":
version "0.9.4"
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5"
integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==
"@emotion/stylis@0.8.5":
version "0.8.5"
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04"
integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==
"@emotion/unitless@0.7.5":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
"@emotion/utils@0.11.3":
version "0.11.3"
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.11.3.tgz#a759863867befa7e583400d322652a3f44820924"
integrity sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==
"@emotion/weak-memoize@0.2.5":
version "0.2.5"
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
"@eslint/eslintrc@^0.4.0": "@eslint/eslintrc@^0.4.0":
version "0.4.0" version "0.4.0"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.0.tgz#99cc0a0584d72f1df38b900fb062ba995f395547" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.0.tgz#99cc0a0584d72f1df38b900fb062ba995f395547"
@ -938,6 +994,62 @@
minimatch "^3.0.4" minimatch "^3.0.4"
strip-json-comments "^3.1.1" strip-json-comments "^3.1.1"
"@giphy/js-analytics@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@giphy/js-analytics/-/js-analytics-3.0.0.tgz#7d7a65faaa3fb997406da4a682f76ad79d392c04"
integrity sha512-WeiU+MVyc7vQD6VTztBl1ZAByTKqOpHRxlZHR3PQjzasc1damHooNcHyHqd8PrjYC3Ag/t/3IuFzsFWVh/dDNA==
dependencies:
"@giphy/js-types" "^3.1.0"
"@giphy/js-util" "^2.2.0"
append-query "^2.1.0"
throttle-debounce "^2.3.0"
"@giphy/js-brand@^2.0.2":
version "2.0.2"
resolved "https://registry.yarnpkg.com/@giphy/js-brand/-/js-brand-2.0.2.tgz#bd40f63b1de9cb60b4116a78daa8b6c523e6954e"
integrity sha512-q2zDuVaDgobc5o9ucoFdYArrVKfyKXo0/jddvVgAazACLEPycAcxfqdyc98TRELwTVcmN/e0ULfLjim2lq3WXw==
dependencies:
emotion "10.0.27"
"@giphy/js-components@^4.3.1":
version "4.3.1"
resolved "https://registry.yarnpkg.com/@giphy/js-components/-/js-components-4.3.1.tgz#93aaf3aa2d85c2cfc21f6a6d1d06df6a026f2040"
integrity sha512-DByKMgivmuJFrt5zUNnn5r4dtfqhjAj9H76/r15rEXJdtSXz+mdbp89yt0DTQnPQJMP93X1owaFu2PBA9UX/Cg==
dependencies:
"@giphy/js-analytics" "^3.0.0"
"@giphy/js-brand" "^2.0.2"
"@giphy/js-fetch-api" "^2.4.0"
"@giphy/js-types" "^3.1.0"
"@giphy/js-util" "^2.2.0"
bricks.js "^1.8.0"
emotion "10.0.27"
intersection-observer "^0.11.0"
preact "10.4.8"
throttle-debounce "^2.3.0"
"@giphy/js-fetch-api@^2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@giphy/js-fetch-api/-/js-fetch-api-2.4.0.tgz#e96c7a2599b720d3e40ea409d8e4c4a692aa4611"
integrity sha512-xiMHnv81XZjgut4yrkHB5QHDWGNhVHoyMDb3kQBy5H0NruwtQ+aM5BE9xbP+XQlxt3eRnPRJcLy5ORk9+K0fIQ==
dependencies:
"@giphy/js-types" "^3.1.0"
"@giphy/js-util" "^2.2.0"
qs "^6.9.4"
"@giphy/js-types@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@giphy/js-types/-/js-types-3.1.0.tgz#cfddcfeb7d389542fc2ffc147bbe122760cfa3b6"
integrity sha512-/gzA5Ny6tYVSXHndBzoIPx2t0Lu0UkbvCxb4g+KWEwQslWmak/2vZcO2X6jdIObHkN/8ejFIXr5Od40Namhtvw==
"@giphy/js-util@^2.2.0":
version "2.2.0"
resolved "https://registry.yarnpkg.com/@giphy/js-util/-/js-util-2.2.0.tgz#887f957e497ec7a956db5bc271259a02e7cbeffd"
integrity sha512-3EHFgOCtAwyV+yild+2YhGB9I+Ht1rXZw+kAuL4+9Ypy+oOwsK++iSdeAw6dY/nddzm91Ch3KB1rP1DBvU+JuA==
dependencies:
"@giphy/js-types" "^3.1.0"
dompurify "^2.2.2"
uuid "^8.3.0"
"@istanbuljs/load-nyc-config@^1.0.0": "@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
@ -1924,6 +2036,13 @@ append-buffer@^1.0.2:
dependencies: dependencies:
buffer-equal "^1.0.0" buffer-equal "^1.0.0"
append-query@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/append-query/-/append-query-2.1.0.tgz#c3392d2ddf8c70d3f582a14b051b12333da540bf"
integrity sha512-v9YXX6No91QkRA31IvTjl+1kFU+A0DaOzZpCNR7Q/ZoPSXlo5a4W2eS0qos6AKvCKL4MnNna78xgqIG8NRvQwg==
dependencies:
extend "^2.0.0"
append-transform@^2.0.0: append-transform@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-2.0.0.tgz#99d9d29c7b38391e6f428d28ce136551f0b77e12" resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-2.0.0.tgz#99d9d29c7b38391e6f428d28ce136551f0b77e12"
@ -2214,6 +2333,31 @@ babel-plugin-dynamic-import-node@^2.3.3:
dependencies: dependencies:
object.assign "^4.1.0" object.assign "^4.1.0"
babel-plugin-emotion@^10.0.27:
version "10.2.2"
resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz#a1fe3503cff80abfd0bdda14abd2e8e57a79d17d"
integrity sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@emotion/hash" "0.8.0"
"@emotion/memoize" "0.7.4"
"@emotion/serialize" "^0.11.16"
babel-plugin-macros "^2.0.0"
babel-plugin-syntax-jsx "^6.18.0"
convert-source-map "^1.5.0"
escape-string-regexp "^1.0.5"
find-root "^1.1.0"
source-map "^0.5.7"
babel-plugin-macros@^2.0.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138"
integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==
dependencies:
"@babel/runtime" "^7.7.2"
cosmiconfig "^6.0.0"
resolve "^1.12.0"
babel-plugin-polyfill-corejs2@^0.1.4: babel-plugin-polyfill-corejs2@^0.1.4:
version "0.1.10" version "0.1.10"
resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.1.10.tgz#a2c5c245f56c0cac3dbddbf0726a46b24f0f81d1" resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.1.10.tgz#a2c5c245f56c0cac3dbddbf0726a46b24f0f81d1"
@ -2243,6 +2387,11 @@ babel-plugin-rewire-ts@^1.4.0:
resolved "https://registry.yarnpkg.com/babel-plugin-rewire-ts/-/babel-plugin-rewire-ts-1.4.0.tgz#6c814d5aa3ef3d8c0d0c7a27891877fb28930e5b" resolved "https://registry.yarnpkg.com/babel-plugin-rewire-ts/-/babel-plugin-rewire-ts-1.4.0.tgz#6c814d5aa3ef3d8c0d0c7a27891877fb28930e5b"
integrity sha512-XVyyWMIx1fNSG42vbUaAro1LANLs/fBW6KurYaeoVjS2U8zLCaow7LKll6zjs1cwcqcbZK2v59zVouPs+JAqxw== integrity sha512-XVyyWMIx1fNSG42vbUaAro1LANLs/fBW6KurYaeoVjS2U8zLCaow7LKll6zjs1cwcqcbZK2v59zVouPs+JAqxw==
babel-plugin-syntax-jsx@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=
bail@^1.0.0: bail@^1.0.0:
version "1.0.5" version "1.0.5"
resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776"
@ -2467,6 +2616,13 @@ braces@^3.0.1, braces@~3.0.2:
dependencies: dependencies:
fill-range "^7.0.1" fill-range "^7.0.1"
bricks.js@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/bricks.js/-/bricks.js-1.8.0.tgz#8fdeb3c0226af251f4d5727a7df7f9ac0092b4b2"
integrity sha1-j96zwCJq8lH01XJ6fff5rACStLI=
dependencies:
knot.js "^1.1.5"
brorand@^1.0.1, brorand@^1.1.0: brorand@^1.0.1, brorand@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
@ -3472,6 +3628,17 @@ cosmiconfig@^5.0.0:
js-yaml "^3.13.1" js-yaml "^3.13.1"
parse-json "^4.0.0" parse-json "^4.0.0"
cosmiconfig@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982"
integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==
dependencies:
"@types/parse-json" "^4.0.0"
import-fresh "^3.1.0"
parse-json "^5.0.0"
path-type "^4.0.0"
yaml "^1.7.2"
cosmiconfig@^7.0.0: cosmiconfig@^7.0.0:
version "7.0.0" version "7.0.0"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3"
@ -3496,6 +3663,16 @@ create-ecdh@^4.0.0:
bn.js "^4.1.0" bn.js "^4.1.0"
elliptic "^6.5.3" elliptic "^6.5.3"
create-emotion@^10.0.27:
version "10.0.27"
resolved "https://registry.yarnpkg.com/create-emotion/-/create-emotion-10.0.27.tgz#cb4fa2db750f6ca6f9a001a33fbf1f6c46789503"
integrity sha512-fIK73w82HPPn/RsAij7+Zt8eCE8SptcJ3WoRMfxMtjteYxud8GDTKKld7MYwAX2TVhrw29uR1N/bVGxeStHILg==
dependencies:
"@emotion/cache" "^10.0.27"
"@emotion/serialize" "^0.11.15"
"@emotion/sheet" "0.9.4"
"@emotion/utils" "0.11.3"
create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
@ -3796,6 +3973,11 @@ cssstyle@^2.2.0:
dependencies: dependencies:
cssom "~0.3.6" cssom "~0.3.6"
csstype@^2.5.7:
version "2.6.16"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.16.tgz#544d69f547013b85a40d15bff75db38f34fe9c39"
integrity sha512-61FBWoDHp/gRtsoDkq/B1nWrCUG/ok1E3tUrcNbZjsE9Cxd9yzUirjS3+nAATB8U4cTtaQmAHbNndoFz5L6C9Q==
cubic-hermite@^1.0.0: cubic-hermite@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/cubic-hermite/-/cubic-hermite-1.0.0.tgz#84e3b2f272b31454e8393b99bb6aed45168c14e5" resolved "https://registry.yarnpkg.com/cubic-hermite/-/cubic-hermite-1.0.0.tgz#84e3b2f272b31454e8393b99bb6aed45168c14e5"
@ -4262,6 +4444,11 @@ domino@^2.1.6:
resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.6.tgz#fe4ace4310526e5e7b9d12c7de01b7f485a57ffe" resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.6.tgz#fe4ace4310526e5e7b9d12c7de01b7f485a57ffe"
integrity sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ== integrity sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ==
dompurify@^2.2.2:
version "2.2.7"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.2.7.tgz#a5f055a2a471638680e779bd08fc334962d11fd8"
integrity sha512-jdtDffdGNY+C76jvodNTu9jt5yYj59vuTUyx+wXdzcSwAGTYZDAQkQ7Iwx9zcGrA4ixC1syU4H3RZROqRxokxg==
domutils@^1.5.1, domutils@^1.7.0: domutils@^1.5.1, domutils@^1.7.0:
version "1.7.0" version "1.7.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
@ -4422,6 +4609,14 @@ emojis-list@^3.0.0:
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
emotion@10.0.27:
version "10.0.27"
resolved "https://registry.yarnpkg.com/emotion/-/emotion-10.0.27.tgz#f9ca5df98630980a23c819a56262560562e5d75e"
integrity sha512-2xdDzdWWzue8R8lu4G76uWX5WhyQuzATon9LmNeCy/2BHVC6dsEpfhN1a0qhELgtDVdjyEA6J8Y/VlI5ZnaH0g==
dependencies:
babel-plugin-emotion "^10.0.27"
create-emotion "^10.0.27"
encodeurl@~1.0.2: encodeurl@~1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
@ -4972,6 +5167,11 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
assign-symbols "^1.0.0" assign-symbols "^1.0.0"
is-extendable "^1.0.1" is-extendable "^1.0.1"
extend@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-2.0.2.tgz#1b74985400171b85554894459c978de6ef453ab7"
integrity sha512-AgFD4VU+lVLP6vjnlNfF7OeInLTyeyckCNPEsuxz1vi786UuK/nk6ynPuhn/h+Ju9++TQyr5EpLRI14fc1QtTQ==
extend@^3.0.0, extend@~3.0.2: extend@^3.0.0, extend@~3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
@ -6675,7 +6875,7 @@ import-fresh@^2.0.0:
caller-path "^2.0.0" caller-path "^2.0.0"
resolve-from "^3.0.0" resolve-from "^3.0.0"
import-fresh@^3.0.0, import-fresh@^3.2.1: import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1:
version "3.3.0" version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
@ -6777,6 +6977,11 @@ interpret@^1.2.0, interpret@^1.4.0:
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
intersection-observer@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.11.0.tgz#f4ea067070326f68393ee161cc0a2ca4c0040c6f"
integrity sha512-KZArj2QVnmdud9zTpKf279m2bbGfG+4/kn16UU0NL3pTVl52ZHiJ9IRNSsnn6jaHrL9EGLFM5eWjTx2fz/+zoQ==
interval-tree-1d@^1.0.1: interval-tree-1d@^1.0.1:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/interval-tree-1d/-/interval-tree-1d-1.0.3.tgz#8fdbde02b6b2c7dbdead636bcbed8e08710d85c1" resolved "https://registry.yarnpkg.com/interval-tree-1d/-/interval-tree-1d-1.0.3.tgz#8fdbde02b6b2c7dbdead636bcbed8e08710d85c1"
@ -7602,6 +7807,11 @@ klona@^2.0.4:
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0" resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0"
integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA== integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==
knot.js@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/knot.js/-/knot.js-1.1.5.tgz#28e72522f703f50fe98812fde224dd72728fef5d"
integrity sha1-KOclIvcD9Q/piBL94iTdcnKP710=
known-css-properties@^0.21.0: known-css-properties@^0.21.0:
version "0.21.0" version "0.21.0"
resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.21.0.tgz#15fbd0bbb83447f3ce09d8af247ed47c68ede80d" resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.21.0.tgz#15fbd0bbb83447f3ce09d8af247ed47c68ede80d"
@ -10010,6 +10220,11 @@ potpack@^1.0.1:
resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.1.tgz#d1b1afd89e4c8f7762865ec30bd112ab767e2ebf" resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.1.tgz#d1b1afd89e4c8f7762865ec30bd112ab767e2ebf"
integrity sha512-15vItUAbViaYrmaB/Pbw7z6qX2xENbFSTA7Ii4tgbPtasxm5v6ryKhKtL91tpWovDJzTiZqdwzhcFBCwiMVdVw== integrity sha512-15vItUAbViaYrmaB/Pbw7z6qX2xENbFSTA7Ii4tgbPtasxm5v6ryKhKtL91tpWovDJzTiZqdwzhcFBCwiMVdVw==
preact@10.4.8:
version "10.4.8"
resolved "https://registry.yarnpkg.com/preact/-/preact-10.4.8.tgz#8517b106cc5591eb675237c93da99ac052cf4756"
integrity sha512-uVLeEAyRsCkUEFhVHlOu17OxcrwC7+hTGZ08kBoLBiGHiZooUZuibQnphgMKftw/rqYntNMyhVCPqQhcyAGHag==
preact@8.2.9: preact@8.2.9:
version "8.2.9" version "8.2.9"
resolved "https://registry.yarnpkg.com/preact/-/preact-8.2.9.tgz#813ba9dd45e5d97c5ea0d6c86d375b3be711cc40" resolved "https://registry.yarnpkg.com/preact/-/preact-8.2.9.tgz#813ba9dd45e5d97c5ea0d6c86d375b3be711cc40"
@ -10195,6 +10410,13 @@ qs@6.7.0:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
qs@^6.9.4:
version "6.10.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.0.tgz#8b6519121ab291c316a3e4d49cecf6d13d8c7fe5"
integrity sha512-yjACOWijC6L/kmPZZAsVBNY2zfHSIbpdpL977quseu56/8BZ2LoF5axK2bGhbzhVKt7V9xgWTtpyLbxwIoER0Q==
dependencies:
side-channel "^1.0.4"
qs@~6.5.2: qs@~6.5.2:
version "6.5.2" version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
@ -10811,7 +11033,7 @@ resolve@^0.6.1:
resolved "https://registry.yarnpkg.com/resolve/-/resolve-0.6.3.tgz#dd957982e7e736debdf53b58a4dd91754575dd46" resolved "https://registry.yarnpkg.com/resolve/-/resolve-0.6.3.tgz#dd957982e7e736debdf53b58a4dd91754575dd46"
integrity sha1-3ZV5gufnNt699TtYpN2RdUV13UY= integrity sha1-3ZV5gufnNt699TtYpN2RdUV13UY=
resolve@^1.0.0, resolve@^1.1.5, resolve@^1.10.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.17.0: resolve@^1.0.0, resolve@^1.1.5, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.17.0:
version "1.20.0" version "1.20.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
@ -11225,6 +11447,15 @@ shebang-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
side-channel@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
dependencies:
call-bind "^1.0.0"
get-intrinsic "^1.0.2"
object-inspect "^1.9.0"
signal-exit@^3.0.0, signal-exit@^3.0.2: signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.3" version "3.0.3"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
@ -11426,7 +11657,7 @@ source-map@0.5.6:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
integrity sha1-dc449SvwczxafwwRjYEzSiu19BI= integrity sha1-dc449SvwczxafwwRjYEzSiu19BI=
source-map@^0.5.0, source-map@^0.5.6: source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7:
version "0.5.7" version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
@ -12225,6 +12456,11 @@ text-table@^0.2.0:
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
throttle-debounce@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.3.0.tgz#fd31865e66502071e411817e241465b3e9c372e2"
integrity sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==
through2-filter@^3.0.0: through2-filter@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254" resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254"
@ -12968,6 +13204,11 @@ uuid@^3.3.2, uuid@^3.3.3, uuid@^3.4.0:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
uuid@^8.3.0:
version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
v8-compile-cache@^2.0.3, v8-compile-cache@^2.1.1, v8-compile-cache@^2.2.0: v8-compile-cache@^2.0.3, v8-compile-cache@^2.1.1, v8-compile-cache@^2.2.0:
version "2.2.0" version "2.2.0"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132"
@ -13594,10 +13835,10 @@ yallist@^4.0.0:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yaml@^1.10.0: yaml@^1.10.0, yaml@^1.7.2:
version "1.10.0" version "1.10.2"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg== integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
yargs-parser@^13.1.2: yargs-parser@^13.1.2:
version "13.1.2" version "13.1.2"

View File

@ -444,6 +444,18 @@ def fetch_initial_state_data(
if want("video_calls"): if want("video_calls"):
state["has_zoom_token"] = settings_user.zoom_token is not None state["has_zoom_token"] = settings_user.zoom_token is not None
if want("giphy"):
# Normally, it would be a nasty security bug to send a
# server's API key to end users. However, GIPHY's API key
# security model is precisely to do that; every service
# publishes its API key (and GIPHY's client-side JS libraries
# require the API key to work). This security model makes
# sense because GIPHY API keys are all essentially equivalent
# in letting one search for GIFs; GIPHY only requires API keys
# to exist at all so that they can deactivate them in cases of
# abuse.
state["giphy_api_key"] = settings.GIPHY_API_KEY if settings.GIPHY_API_KEY else ""
return state return state

View File

@ -470,6 +470,14 @@ INTEGRATIONS: Dict[str, Integration] = {
"errbot": Integration( "errbot": Integration(
"errbot", "errbot", ["meta-integration", "bots"], doc="zerver/integrations/errbot.md" "errbot", "errbot", ["meta-integration", "bots"], doc="zerver/integrations/errbot.md"
), ),
"giphy": Integration(
"giphy",
"giphy",
display_name="GIPHY",
categories=["misc"],
doc="zerver/integrations/giphy.md",
logo="images/GIPHY_big_logo.png",
),
"git": Integration( "git": Integration(
"git", "git", ["version-control"], stream_name="commits", doc="zerver/integrations/git.md" "git", "git", ["version-control"], stream_name="commits", doc="zerver/integrations/git.md"
), ),

View File

@ -7115,6 +7115,19 @@ paths:
A boolean which signifies whether the user has a zoom token and has thus completed A boolean which signifies whether the user has a zoom token and has thus completed
OAuth flow for the [Zoom integration](/help/start-a-call). Clients need OAuth flow for the [Zoom integration](/help/start-a-call). Clients need
to know whether initiating Zoom OAuth is required before creating a Zoom call. to know whether initiating Zoom OAuth is required before creating a Zoom call.
giphy_api_key:
type: string
description: |
Present if `giphy` is present in `fetch_event_types`.
GIPHY's client-side SDKs needs this API key to use the GIPHY API.
GIPHY API keys are not secret (their main purpose appears to be
allowing GIPHY to block a problematic app). Please don't use our API
key for an app unrelated to Zulip.
Developers of clients should also read the
[GIPHY API TOS](https://support.giphy.com/hc/en-us/articles/360028134111-GIPHY-API-Terms-of-Service-)
before using this API key.
enable_desktop_notifications: enable_desktop_notifications:
type: boolean type: boolean
description: | description: |

View File

@ -882,6 +882,7 @@ class FetchQueriesTest(ZulipTestCase):
update_message_flags=5, update_message_flags=5,
user_status=1, user_status=1,
video_calls=0, video_calls=0,
giphy=0,
) )
wanted_event_types = {item[0][0] for item in want_mock.call_args_list} wanted_event_types = {item[0][0] for item in want_mock.call_args_list}

View File

@ -83,6 +83,7 @@ class HomeTest(ZulipTestCase):
"fluid_layout_width", "fluid_layout_width",
"full_name", "full_name",
"furthest_read_time", "furthest_read_time",
"giphy_api_key",
"has_mobile_devices", "has_mobile_devices",
"has_zoom_token", "has_zoom_token",
"high_contrast_mode", "high_contrast_mode",

View File

@ -243,6 +243,7 @@ def home_real(request: HttpRequest) -> HttpResponse:
"embedded": narrow_stream is not None, "embedded": narrow_stream is not None,
"invite_as": PreregistrationUser.INVITE_AS, "invite_as": PreregistrationUser.INVITE_AS,
"max_file_upload_size_mib": settings.MAX_FILE_UPLOAD_SIZE, "max_file_upload_size_mib": settings.MAX_FILE_UPLOAD_SIZE,
"giphy_api_available": bool(page_params["giphy_api_key"]),
}, },
) )
patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True) patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True)

View File

@ -133,6 +133,9 @@ MAX_FILE_UPLOAD_SIZE = 25
# Jitsi Meet video call integration; set to None to disable integration. # Jitsi Meet video call integration; set to None to disable integration.
JITSI_SERVER_URL = "https://meet.jit.si" JITSI_SERVER_URL = "https://meet.jit.si"
# GIPHY API key.
GIPHY_API_KEY = get_secret("giphy_api_key")
# Allow setting BigBlueButton settings in zulip-secrets.conf in # Allow setting BigBlueButton settings in zulip-secrets.conf in
# development; this is useful since there are no public BigBlueButton servers. # development; this is useful since there are no public BigBlueButton servers.
BIG_BLUE_BUTTON_URL = get_secret("big_blue_button_url", development_only=True) BIG_BLUE_BUTTON_URL = get_secret("big_blue_button_url", development_only=True)

View File

@ -563,6 +563,10 @@ SOCIAL_AUTH_SAML_SUPPORT_CONTACT = {
## system-level monitoring tools. ## system-level monitoring tools.
# LOGGING_SHOW_PID = False # LOGGING_SHOW_PID = False
#################
## Animated GIF integration powered by GIPHY. See:
## https://zulip.readthedocs.io/en/latest/production/giphy-gif-integration.html
# GIPHY_API_KEY = "<Your API key from GIPHY>"
################ ################
## Video call integrations. ## Video call integrations.