mirror of
https://github.com/Redocly/redoc.git
synced 2025-11-24 19:45:14 +03:00
Merge d67f3e208f into d41fd46f7c
This commit is contained in:
commit
2df3cae454
27364
demo/big-openapi.json
27364
demo/big-openapi.json
File diff suppressed because one or more lines are too long
|
|
@ -1,11 +1,11 @@
|
||||||
import * as React from 'react';
|
\import * as React from 'react';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { RedocStandalone } from '../src';
|
import { RedocStandalone } from '../src';
|
||||||
import ComboBox from './ComboBox';
|
import ComboBox from './ComboBox';
|
||||||
import FileInput from './components/FileInput';
|
import FileInput from './components/FileInput';
|
||||||
|
|
||||||
const DEFAULT_SPEC = 'museum.yaml';
|
const DEFAULT_SPEC = 'big-openapi.json';
|
||||||
const NEW_VERSION_PETSTORE = 'openapi-3-1.yaml';
|
const NEW_VERSION_PETSTORE = 'openapi-3-1.yaml';
|
||||||
|
|
||||||
const demos = [
|
const demos = [
|
||||||
|
|
|
||||||
787
demo/museum.yaml
787
demo/museum.yaml
|
|
@ -1,787 +0,0 @@
|
||||||
openapi: 3.1.0
|
|
||||||
info:
|
|
||||||
title: Redocly Museum API
|
|
||||||
description: An imaginary, but delightful Museum API for interacting with museum services and information. Built with love by Redocly.
|
|
||||||
version: 1.0.0
|
|
||||||
contact:
|
|
||||||
email: team@redocly.com
|
|
||||||
url: 'https://redocly.com/docs/cli/'
|
|
||||||
x-logo:
|
|
||||||
url: 'https://redocly.github.io/redoc/museum-logo.png'
|
|
||||||
altText: Museum logo
|
|
||||||
license:
|
|
||||||
name: MIT
|
|
||||||
url: 'https://opensource.org/license/mit/ '
|
|
||||||
servers:
|
|
||||||
- url: 'https://api.fake-museum-example.com/v1'
|
|
||||||
paths:
|
|
||||||
/museum-hours:
|
|
||||||
get:
|
|
||||||
summary: Get museum hours
|
|
||||||
description: Get upcoming museum operating hours
|
|
||||||
operationId: getMuseumHours
|
|
||||||
tags:
|
|
||||||
- Operations
|
|
||||||
x-badges:
|
|
||||||
- name: 'Beta'
|
|
||||||
position: before
|
|
||||||
color: purple
|
|
||||||
parameters:
|
|
||||||
- $ref: '#/components/parameters/StartDate'
|
|
||||||
- $ref: '#/components/parameters/PaginationPage'
|
|
||||||
- $ref: '#/components/parameters/PaginationLimit'
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: Success
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/GetMuseumHoursResponse'
|
|
||||||
examples:
|
|
||||||
default:
|
|
||||||
summary: Museum opening hours
|
|
||||||
value:
|
|
||||||
- date: '2023-09-11'
|
|
||||||
timeOpen: '09:00'
|
|
||||||
timeClose: '18:00'
|
|
||||||
- date: '2023-09-12'
|
|
||||||
timeOpen: '09:00'
|
|
||||||
timeClose: '18:00'
|
|
||||||
- date: '2023-09-13'
|
|
||||||
timeOpen: '09:00'
|
|
||||||
timeClose: '18:00'
|
|
||||||
- date: '2023-09-17'
|
|
||||||
timeOpen: '09:00'
|
|
||||||
timeClose: '18:00'
|
|
||||||
closed:
|
|
||||||
summary: The museum is closed
|
|
||||||
value: []
|
|
||||||
|
|
||||||
'400':
|
|
||||||
description: Bad request
|
|
||||||
'404':
|
|
||||||
description: Not found
|
|
||||||
/special-events:
|
|
||||||
post:
|
|
||||||
security: []
|
|
||||||
operationId: CreateSpecialEvent
|
|
||||||
summary: Create special event
|
|
||||||
tags:
|
|
||||||
- Events
|
|
||||||
x-badges:
|
|
||||||
- name: 'Alpha'
|
|
||||||
color: purple
|
|
||||||
requestBody:
|
|
||||||
required: true
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/CreateSpecialEventRequest'
|
|
||||||
examples:
|
|
||||||
default_example:
|
|
||||||
$ref: '#/components/examples/CreateSpecialEventRequestExample'
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: success
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/SpecialEventResponse'
|
|
||||||
examples:
|
|
||||||
default_example:
|
|
||||||
$ref: '#/components/examples/CreateSpecialEventResponseExample'
|
|
||||||
'400':
|
|
||||||
description: Bad request
|
|
||||||
'404':
|
|
||||||
description: Not found
|
|
||||||
get:
|
|
||||||
summary: List special events
|
|
||||||
description: Return a list of upcoming special events at the museum.
|
|
||||||
security: []
|
|
||||||
operationId: listSpecialEvents
|
|
||||||
x-badges:
|
|
||||||
- name: 'Gamma'
|
|
||||||
tags:
|
|
||||||
- Events
|
|
||||||
parameters:
|
|
||||||
- name: startDate
|
|
||||||
in: query
|
|
||||||
description: The starting date to retrieve future operating hours from. Defaults to today's date.
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
format: date
|
|
||||||
example: 2023-02-23
|
|
||||||
- name: endDate
|
|
||||||
in: query
|
|
||||||
description: The end of a date range to retrieve special events for. Defaults to 7 days after `startDate`.
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
format: date
|
|
||||||
example: 2023-04-18
|
|
||||||
- name: page
|
|
||||||
in: query
|
|
||||||
description: The page number to retrieve.
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
default: 1
|
|
||||||
example: 2
|
|
||||||
- name: limit
|
|
||||||
in: query
|
|
||||||
description: The number of days per page.
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
default: 10
|
|
||||||
maximum: 30
|
|
||||||
example: 15
|
|
||||||
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: Success
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/ListSpecialEventsResponse'
|
|
||||||
examples:
|
|
||||||
default_example:
|
|
||||||
$ref: '#/components/examples/ListSpecialEventsResponseExample'
|
|
||||||
'400':
|
|
||||||
description: Bad request
|
|
||||||
'404':
|
|
||||||
description: Not found
|
|
||||||
/special-events/{eventId}:
|
|
||||||
get:
|
|
||||||
summary: Get special event
|
|
||||||
description: Get details about a special event.
|
|
||||||
operationId: getSpecialEvent
|
|
||||||
tags:
|
|
||||||
- Events
|
|
||||||
parameters:
|
|
||||||
- $ref: '#/components/parameters/EventId'
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: Success
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/SpecialEventResponse'
|
|
||||||
examples:
|
|
||||||
default_example:
|
|
||||||
$ref: '#/components/examples/GetSpecialEventResponseExample'
|
|
||||||
'400':
|
|
||||||
description: Bad request
|
|
||||||
'404':
|
|
||||||
description: Not found
|
|
||||||
patch:
|
|
||||||
summary: Update special event
|
|
||||||
description: Update the details of a special event
|
|
||||||
operationId: updateSpecialEvent
|
|
||||||
tags:
|
|
||||||
- Events
|
|
||||||
parameters:
|
|
||||||
- $ref: '#/components/parameters/EventId'
|
|
||||||
requestBody:
|
|
||||||
required: true
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/UpdateSpecialEventRequest'
|
|
||||||
examples:
|
|
||||||
default_example:
|
|
||||||
$ref: '#/components/examples/UpdateSpecialEventRequestExample'
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: Success
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/SpecialEventResponse'
|
|
||||||
examples:
|
|
||||||
default_example:
|
|
||||||
$ref: '#/components/examples/UpdateSpecialEventResponseExample'
|
|
||||||
'400':
|
|
||||||
description: Bad request
|
|
||||||
'404':
|
|
||||||
description: Not found
|
|
||||||
delete:
|
|
||||||
summary: Delete special event
|
|
||||||
description: Delete a special event from the collection. Allows museum to cancel planned events.
|
|
||||||
operationId: deleteSpecialEvent
|
|
||||||
tags:
|
|
||||||
- Events
|
|
||||||
parameters:
|
|
||||||
- $ref: '#/components/parameters/EventId'
|
|
||||||
responses:
|
|
||||||
'204':
|
|
||||||
description: Success - no content
|
|
||||||
'400':
|
|
||||||
description: Bad request
|
|
||||||
'401':
|
|
||||||
description: Unauthorized
|
|
||||||
'404':
|
|
||||||
description: Not found
|
|
||||||
/tickets:
|
|
||||||
post:
|
|
||||||
summary: Buy museum tickets
|
|
||||||
description: Purchase museum tickets for general entry or special events.
|
|
||||||
operationId: buyMuseumTickets
|
|
||||||
tags:
|
|
||||||
- Tickets
|
|
||||||
requestBody:
|
|
||||||
required: true
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/BuyMuseumTicketsRequest'
|
|
||||||
examples:
|
|
||||||
general_entry:
|
|
||||||
$ref: '#/components/examples/BuyGeneralTicketsRequestExample'
|
|
||||||
event_entry:
|
|
||||||
$ref: '#/components/examples/BuyEventTicketsRequestExample'
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: Success
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/BuyMuseumTicketsResponse'
|
|
||||||
examples:
|
|
||||||
general_entry:
|
|
||||||
$ref: '#/components/examples/BuyGeneralTicketsResponseExample'
|
|
||||||
event_entry:
|
|
||||||
$ref: '#/components/examples/BuyEventTicketsResponseExample'
|
|
||||||
'400':
|
|
||||||
description: Bad request
|
|
||||||
'404':
|
|
||||||
description: Not found
|
|
||||||
/tickets/{ticketId}/qr:
|
|
||||||
get:
|
|
||||||
summary: Get ticket QR code
|
|
||||||
description: Return an image of your ticket with scannable QR code. Used for event entry.
|
|
||||||
operationId: getTicketCode
|
|
||||||
tags:
|
|
||||||
- Tickets
|
|
||||||
parameters:
|
|
||||||
- $ref: '#/components/parameters/TicketId'
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: Scannable event ticket in image format
|
|
||||||
content:
|
|
||||||
image/png:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/GetTicketCodeResponse'
|
|
||||||
'400':
|
|
||||||
description: Bad request
|
|
||||||
'404':
|
|
||||||
description: Not found
|
|
||||||
components:
|
|
||||||
schemas:
|
|
||||||
SpecialEvent:
|
|
||||||
description: Request payload for creating new special events at the museum.
|
|
||||||
properties:
|
|
||||||
name:
|
|
||||||
description: Name of the special event
|
|
||||||
type: string
|
|
||||||
example: Fossil lecture
|
|
||||||
location:
|
|
||||||
description: Location where the special event is held
|
|
||||||
type: string
|
|
||||||
example: Lecture theatre
|
|
||||||
eventDescription:
|
|
||||||
description: Description of the special event
|
|
||||||
type: string
|
|
||||||
example: Our panel of experts will share their favorite fossils and explain why they are so great.
|
|
||||||
dates:
|
|
||||||
description: List of planned dates for the special event
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
format: date
|
|
||||||
example: 2024-03-29
|
|
||||||
price:
|
|
||||||
description: Price of a ticket for the special event
|
|
||||||
type: number
|
|
||||||
format: float
|
|
||||||
example: 12.50
|
|
||||||
|
|
||||||
TicketType:
|
|
||||||
description: Type of ticket being purchased. Use `general` for regular museum entry and `event` for tickets to special events.
|
|
||||||
type: string
|
|
||||||
enum:
|
|
||||||
- event
|
|
||||||
- general
|
|
||||||
x-enumDescriptions:
|
|
||||||
event: Special event ticket
|
|
||||||
general: General museum entry ticket
|
|
||||||
example: event
|
|
||||||
Date:
|
|
||||||
type: string
|
|
||||||
format: date
|
|
||||||
example: 2023-10-29
|
|
||||||
Email:
|
|
||||||
description: Email address for ticket purchaser.
|
|
||||||
type: string
|
|
||||||
format: email
|
|
||||||
example: museum-lover@example.com
|
|
||||||
Phone:
|
|
||||||
description: Phone number for the ticket purchaser (optional).
|
|
||||||
type: string
|
|
||||||
example: +1(234)-567-8910
|
|
||||||
BuyMuseumTicketsRequest:
|
|
||||||
description: Request payload used for purchasing museum tickets.
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
ticketType:
|
|
||||||
$ref: '#/components/schemas/TicketType'
|
|
||||||
eventId:
|
|
||||||
description: Unique identifier for a special event. Required if purchasing tickets for the museum's special events.
|
|
||||||
$ref: '#/components/schemas/EventId'
|
|
||||||
ticketDate:
|
|
||||||
description: Date that the ticket is valid for.
|
|
||||||
$ref: '#/components/schemas/Date'
|
|
||||||
email:
|
|
||||||
$ref: '#/components/schemas/Email'
|
|
||||||
phone:
|
|
||||||
$ref: '#/components/schemas/Phone'
|
|
||||||
required:
|
|
||||||
- ticketType
|
|
||||||
- ticketDate
|
|
||||||
- email
|
|
||||||
TicketMessage:
|
|
||||||
description: Confirmation message after a ticket purchase.
|
|
||||||
type: string
|
|
||||||
example: Museum general entry ticket purchased
|
|
||||||
TicketId:
|
|
||||||
description: Unique identifier for museum ticket. Generated when purchased.
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
example: a54a57ca-36f8-421b-a6b4-2e8f26858a4c
|
|
||||||
TicketConfirmation:
|
|
||||||
description: Unique confirmation code used to verify ticket purchase.
|
|
||||||
type: string
|
|
||||||
example: ticket-event-a98c8f-7eb12
|
|
||||||
BuyMuseumTicketsResponse:
|
|
||||||
description: Details for a museum ticket after a successful purchase.
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
message:
|
|
||||||
$ref: '#/components/schemas/TicketMessage'
|
|
||||||
eventName:
|
|
||||||
$ref: '#/components/schemas/EventName'
|
|
||||||
ticketId:
|
|
||||||
$ref: '#/components/schemas/TicketId'
|
|
||||||
ticketType:
|
|
||||||
$ref: '#/components/schemas/TicketType'
|
|
||||||
ticketDate:
|
|
||||||
description: Date the ticket is valid for.
|
|
||||||
$ref: '#/components/schemas/Date'
|
|
||||||
confirmationCode:
|
|
||||||
$ref: '#/components/schemas/TicketConfirmation'
|
|
||||||
required:
|
|
||||||
- message
|
|
||||||
- ticketId
|
|
||||||
- ticketType
|
|
||||||
- ticketDate
|
|
||||||
- confirmationCode
|
|
||||||
GetTicketCodeResponse:
|
|
||||||
description: An image of a ticket with a QR code used for museum or event entry.
|
|
||||||
type: string
|
|
||||||
format: binary
|
|
||||||
GetMuseumHoursResponse:
|
|
||||||
description: List of museum operating hours for consecutive days.
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/components/schemas/MuseumDailyHours'
|
|
||||||
MuseumDailyHours:
|
|
||||||
description: Daily operating hours for the museum.
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
date:
|
|
||||||
description: Date the operating hours apply to.
|
|
||||||
$ref: '#/components/schemas/Date'
|
|
||||||
example: 2024-12-31
|
|
||||||
timeOpen:
|
|
||||||
type: string
|
|
||||||
pattern: '^([01]\d|2[0-3]):?([0-5]\d)$'
|
|
||||||
description: Time the museum opens on a specific date. Uses 24 hour time format (`HH:mm`).
|
|
||||||
example: 09:00
|
|
||||||
timeClose:
|
|
||||||
description: Time the museum closes on a specific date. Uses 24 hour time format (`HH:mm`).
|
|
||||||
type: string
|
|
||||||
pattern: '^([01]\d|2[0-3]):?([0-5]\d)$'
|
|
||||||
example: 18:00
|
|
||||||
required:
|
|
||||||
- date
|
|
||||||
- timeOpen
|
|
||||||
- timeClose
|
|
||||||
EventId:
|
|
||||||
description: Identifier for a special event.
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
example: 3be6453c-03eb-4357-ae5a-984a0e574a54
|
|
||||||
EventName:
|
|
||||||
type: string
|
|
||||||
description: Name of the special event
|
|
||||||
example: Pirate Coding Workshop
|
|
||||||
EventLocation:
|
|
||||||
type: string
|
|
||||||
description: Location where the special event is held
|
|
||||||
example: Computer Room
|
|
||||||
EventDescription:
|
|
||||||
type: string
|
|
||||||
description: Description of the special event
|
|
||||||
example: Captain Blackbeard shares his love of the C...language. And possibly Arrrrr (R lang).
|
|
||||||
EventDates:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/components/schemas/Date'
|
|
||||||
description: List of planned dates for the special event
|
|
||||||
EventPrice:
|
|
||||||
description: Price of a ticket for the special event
|
|
||||||
type: number
|
|
||||||
format: float
|
|
||||||
example: 25
|
|
||||||
CreateSpecialEventRequest:
|
|
||||||
description: Request payload for creating new special events at the museum.
|
|
||||||
properties:
|
|
||||||
name:
|
|
||||||
$ref: '#/components/schemas/EventName'
|
|
||||||
location:
|
|
||||||
$ref: '#/components/schemas/EventLocation'
|
|
||||||
eventDescription:
|
|
||||||
$ref: '#/components/schemas/EventDescription'
|
|
||||||
dates:
|
|
||||||
$ref: '#/components/schemas/EventDates'
|
|
||||||
price:
|
|
||||||
$ref: '#/components/schemas/EventPrice'
|
|
||||||
required:
|
|
||||||
- name
|
|
||||||
- location
|
|
||||||
- eventDescription
|
|
||||||
- dates
|
|
||||||
- price
|
|
||||||
UpdateSpecialEventRequest:
|
|
||||||
description: Request payload for updating an existing special event. Only included fields are updated in the event.
|
|
||||||
properties:
|
|
||||||
name:
|
|
||||||
$ref: '#/components/schemas/EventName'
|
|
||||||
location:
|
|
||||||
$ref: '#/components/schemas/EventLocation'
|
|
||||||
eventDescription:
|
|
||||||
$ref: '#/components/schemas/EventDescription'
|
|
||||||
dates:
|
|
||||||
$ref: '#/components/schemas/EventDates'
|
|
||||||
price:
|
|
||||||
$ref: '#/components/schemas/EventPrice'
|
|
||||||
ListSpecialEventsResponse:
|
|
||||||
description: A list of upcoming special events
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/components/schemas/SpecialEventResponse'
|
|
||||||
SpecialEventResponse:
|
|
||||||
description: Information about a special event.
|
|
||||||
properties:
|
|
||||||
eventId:
|
|
||||||
$ref: '#/components/schemas/EventId'
|
|
||||||
name:
|
|
||||||
$ref: '#/components/schemas/EventName'
|
|
||||||
location:
|
|
||||||
$ref: '#/components/schemas/EventLocation'
|
|
||||||
eventDescription:
|
|
||||||
$ref: '#/components/schemas/EventDescription'
|
|
||||||
dates:
|
|
||||||
$ref: '#/components/schemas/EventDates'
|
|
||||||
price:
|
|
||||||
$ref: '#/components/schemas/EventPrice'
|
|
||||||
required:
|
|
||||||
- eventId
|
|
||||||
- name
|
|
||||||
- location
|
|
||||||
- eventDescription
|
|
||||||
- dates
|
|
||||||
- price
|
|
||||||
securitySchemes:
|
|
||||||
MuseumPlaceholderAuth:
|
|
||||||
type: http
|
|
||||||
scheme: basic
|
|
||||||
examples:
|
|
||||||
BuyGeneralTicketsRequestExample:
|
|
||||||
summary: General entry ticket
|
|
||||||
value:
|
|
||||||
ticketType: general
|
|
||||||
ticketDate: 2023-09-07
|
|
||||||
email: todd@example.com
|
|
||||||
BuyEventTicketsRequestExample:
|
|
||||||
summary: Special event ticket
|
|
||||||
value:
|
|
||||||
ticketType: general
|
|
||||||
eventId: dad4bce8-f5cb-4078-a211-995864315e39
|
|
||||||
ticketDate: 2023-09-05
|
|
||||||
email: todd@example.com
|
|
||||||
BuyGeneralTicketsResponseExample:
|
|
||||||
summary: General entry ticket
|
|
||||||
value:
|
|
||||||
message: Museum general entry ticket purchased
|
|
||||||
ticketId: 382c0820-0530-4f4b-99af-13811ad0f17a
|
|
||||||
ticketType: general
|
|
||||||
ticketDate: 2023-09-07
|
|
||||||
confirmationCode: ticket-general-e5e5c6-dce78
|
|
||||||
BuyEventTicketsResponseExample:
|
|
||||||
summary: Special event ticket
|
|
||||||
value:
|
|
||||||
message: Museum special event ticket purchased
|
|
||||||
ticketId: b811f723-17b2-44f7-8952-24b03e43d8a9
|
|
||||||
eventName: Mermaid Treasure Identification and Analysis
|
|
||||||
ticketType: event
|
|
||||||
ticketDate: 2023-09-05
|
|
||||||
confirmationCode: ticket-event-9c55eg-8v82a
|
|
||||||
CreateSpecialEventRequestExample:
|
|
||||||
summary: Create special event
|
|
||||||
value:
|
|
||||||
name: Mermaid Treasure Identification and Analysis
|
|
||||||
location: Under the seaaa 🦀 🎶 🌊.
|
|
||||||
eventDescription: Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits, kindly donated by Ariel.
|
|
||||||
dates:
|
|
||||||
- 2023-09-05
|
|
||||||
- 2023-09-08
|
|
||||||
price: 0
|
|
||||||
CreateSpecialEventResponseExample:
|
|
||||||
summary: Special event created
|
|
||||||
value:
|
|
||||||
eventId: dad4bce8-f5cb-4078-a211-995864315e39
|
|
||||||
name: Mermaid Treasure Identification and Analysis
|
|
||||||
location: Under the seaaa 🦀 🎶 🌊.
|
|
||||||
eventDescription: Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits, kindly donated by Ariel.
|
|
||||||
dates:
|
|
||||||
- 2023-09-05
|
|
||||||
- 2023-09-08
|
|
||||||
price: 30
|
|
||||||
GetSpecialEventResponseExample:
|
|
||||||
summary: Get special event
|
|
||||||
value:
|
|
||||||
eventId: 6744a0da-4121-49cd-8479-f8cc20526495
|
|
||||||
name: Time Traveler Tea Party
|
|
||||||
location: Temporal Tearoom
|
|
||||||
eventDescription: Sip tea with important historical figures.
|
|
||||||
dates:
|
|
||||||
- 2023-11-18
|
|
||||||
- 2023-11-25
|
|
||||||
- 2023-12-02
|
|
||||||
price: 60
|
|
||||||
ListSpecialEventsResponseExample:
|
|
||||||
summary: List of special events
|
|
||||||
value:
|
|
||||||
- eventId: f3e0e76e-e4a8-466e-ab9c-ae36c15b8e97
|
|
||||||
name: Sasquatch Ballet
|
|
||||||
location: Seattle... probably
|
|
||||||
eventDescription: They're big, they're hairy, but they're also graceful. Come learn how the biggest feet can have the lightest touch.
|
|
||||||
dates:
|
|
||||||
- 2023-12-15
|
|
||||||
- 2023-12-22
|
|
||||||
price: 40
|
|
||||||
- eventId: 2f14374a-9c65-4ee5-94b7-fba66d893483
|
|
||||||
name: Solar Telescope Demonstration
|
|
||||||
location: Far from the sun.
|
|
||||||
eventDescription: Look at the sun without going blind!
|
|
||||||
dates:
|
|
||||||
- 2023-09-07
|
|
||||||
- 2023-09-14
|
|
||||||
price: 50
|
|
||||||
- eventId: 6aaa61ba-b2aa-4868-b803-603dbbf7bfdb
|
|
||||||
name: Cook like a Caveman
|
|
||||||
location: Fire Pit on East side
|
|
||||||
eventDescription: Learn to cook on an open flame.
|
|
||||||
dates:
|
|
||||||
- 2023-11-10
|
|
||||||
- 2023-11-17
|
|
||||||
- 2023-11-24
|
|
||||||
price: 5
|
|
||||||
- eventId: 602b75e1-5696-4ab8-8c7a-f9e13580f910
|
|
||||||
name: Underwater Basket Weaving
|
|
||||||
location: Rec Center Pool next door.
|
|
||||||
eventDescription: Learn to weave baskets underwater.
|
|
||||||
dates:
|
|
||||||
- 2023-09-12
|
|
||||||
- 2023-09-15
|
|
||||||
price: 15
|
|
||||||
- eventId: dad4bce8-f5cb-4078-a211-995864315e39
|
|
||||||
name: Mermaid Treasure Identification and Analysis
|
|
||||||
location: Room Sea-12
|
|
||||||
eventDescription: Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits — kindly donated by Ariel.
|
|
||||||
dates:
|
|
||||||
- 2023-09-05
|
|
||||||
- 2023-09-08
|
|
||||||
price: 30
|
|
||||||
- eventId: 6744a0da-4121-49cd-8479-f8cc20526495
|
|
||||||
name: Time Traveler Tea Party
|
|
||||||
location: Temporal Tearoom
|
|
||||||
eventDescription: Sip tea with important historical figures.
|
|
||||||
dates:
|
|
||||||
- 2023-11-18
|
|
||||||
- 2023-11-25
|
|
||||||
- 2023-12-02
|
|
||||||
price: 60
|
|
||||||
- eventId: 3be6453c-03eb-4357-ae5a-984a0e574a54
|
|
||||||
name: Pirate Coding Workshop
|
|
||||||
location: Computer Room
|
|
||||||
eventDescription: Captain Blackbeard shares his love of the C...language. And possibly Arrrrr (R lang).
|
|
||||||
dates:
|
|
||||||
- 2023-10-29
|
|
||||||
- 2023-10-30
|
|
||||||
- 2023-10-31
|
|
||||||
price: 45
|
|
||||||
- eventId: 9d90d29a-2af5-4206-97d9-9ea9ceadcb78
|
|
||||||
name: Llama Street Art Through the Ages
|
|
||||||
location: Auditorium
|
|
||||||
eventDescription: Llama street art?! Alpaca my bags -- let's go!
|
|
||||||
dates:
|
|
||||||
- 2023-10-29
|
|
||||||
- 2023-10-30
|
|
||||||
- 2023-10-31
|
|
||||||
price: 45
|
|
||||||
- eventId: a3c7b2c4-b5fb-4ef7-9322-00a919864957
|
|
||||||
name: The Great Parrot Debate
|
|
||||||
location: Outdoor Amphitheatre
|
|
||||||
eventDescription: See leading parrot minds discuss important geopolitical issues.
|
|
||||||
dates:
|
|
||||||
- 2023-11-03
|
|
||||||
- 2023-11-10
|
|
||||||
price: 35
|
|
||||||
- eventId: b92d46b7-4c5d-422b-87a5-287767e26f29
|
|
||||||
name: Eat a Bunch of Corn
|
|
||||||
location: Cafeteria
|
|
||||||
eventDescription: We accidentally bought too much corn. Please come eat it.
|
|
||||||
dates:
|
|
||||||
- 2023-11-10
|
|
||||||
- 2023-11-17
|
|
||||||
- 2023-11-24
|
|
||||||
price: 5
|
|
||||||
UpdateSpecialEventRequestExample:
|
|
||||||
summary: Update special event request
|
|
||||||
value:
|
|
||||||
location: On the beach.
|
|
||||||
price: 15
|
|
||||||
UpdateSpecialEventResponseExample:
|
|
||||||
summary: Update special event
|
|
||||||
value:
|
|
||||||
eventId: dad4bce8-f5cb-4078-a211-995864315e39
|
|
||||||
name: Mermaid Treasure Identification and Analysis
|
|
||||||
location: On the beach.
|
|
||||||
eventDescription: Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits, kindly donated by Ariel.
|
|
||||||
dates:
|
|
||||||
- 2023-09-05
|
|
||||||
- 2023-09-08
|
|
||||||
price: 15
|
|
||||||
GetMuseumHours:
|
|
||||||
summary: Museum opening hours
|
|
||||||
value:
|
|
||||||
- date: '2023-09-11'
|
|
||||||
timeOpen: '09:00'
|
|
||||||
timeClose: '18:00'
|
|
||||||
- date: '2023-09-12'
|
|
||||||
timeOpen: '09:00'
|
|
||||||
timeClose: '18:00'
|
|
||||||
- date: '2023-09-13'
|
|
||||||
timeOpen: '09:00'
|
|
||||||
timeClose: '18:00'
|
|
||||||
- date: '2023-09-14'
|
|
||||||
timeOpen: '09:00'
|
|
||||||
timeClose: '18:00'
|
|
||||||
- date: '2023-09-15'
|
|
||||||
timeOpen: '10:00'
|
|
||||||
timeClose: '16:00'
|
|
||||||
- date: '2023-09-18'
|
|
||||||
timeOpen: '09:00'
|
|
||||||
timeClose: '18:00'
|
|
||||||
- date: '2023-09-19'
|
|
||||||
timeOpen: '09:00'
|
|
||||||
timeClose: '18:00'
|
|
||||||
- date: '2023-09-20'
|
|
||||||
timeOpen: '09:00'
|
|
||||||
timeClose: '18:00'
|
|
||||||
- date: '2023-09-21'
|
|
||||||
timeOpen: '09:00'
|
|
||||||
timeClose: '18:00'
|
|
||||||
- date: '2023-09-22'
|
|
||||||
timeOpen: '10:00'
|
|
||||||
timeClose: '16:00'
|
|
||||||
ClosedMuseumHours:
|
|
||||||
summary: The museum is closed
|
|
||||||
value: []
|
|
||||||
parameters:
|
|
||||||
PaginationPage:
|
|
||||||
name: page
|
|
||||||
in: query
|
|
||||||
description: The page number to retrieve.
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
default: 1
|
|
||||||
example: 2
|
|
||||||
PaginationLimit:
|
|
||||||
name: limit
|
|
||||||
in: query
|
|
||||||
description: The number of days per page.
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
default: 10
|
|
||||||
maximum: 30
|
|
||||||
example: 15
|
|
||||||
EventId:
|
|
||||||
name: eventId
|
|
||||||
in: path
|
|
||||||
description: An identifier for a special event.
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
example: dad4bce8-f5cb-4078-a211-995864315e39
|
|
||||||
StartDate:
|
|
||||||
name: startDate
|
|
||||||
in: query
|
|
||||||
description: The starting date to retrieve future operating hours from. Defaults to today's date.
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
format: date
|
|
||||||
example: 2023-02-23
|
|
||||||
EndDate:
|
|
||||||
name: endDate
|
|
||||||
in: query
|
|
||||||
description: The end of a date range to retrieve special events for. Defaults to 7 days after `startDate`.
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
format: date
|
|
||||||
example: 2023-04-18
|
|
||||||
TicketId:
|
|
||||||
name: ticketId
|
|
||||||
in: path
|
|
||||||
description: An identifier for a ticket to a museum event. Used to generate ticket image.
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
example: a54a57ca-36f8-421b-a6b4-2e8f26858a4c
|
|
||||||
|
|
||||||
tags:
|
|
||||||
- name: Operations
|
|
||||||
x-displayName: About the museum
|
|
||||||
description: Operational information about the museum.
|
|
||||||
- name: Events
|
|
||||||
x-displayName: Upcoming events
|
|
||||||
description: Special events hosted by the Museum.
|
|
||||||
- name: Tickets
|
|
||||||
x-displayName: Buy tickets
|
|
||||||
description: Museum tickets for general entrance or special events.
|
|
||||||
|
|
||||||
x-tagGroups:
|
|
||||||
- name: Plan your visit
|
|
||||||
tags:
|
|
||||||
- Operations
|
|
||||||
- Events
|
|
||||||
- name: Purchases
|
|
||||||
tags:
|
|
||||||
- Tickets
|
|
||||||
- name: Entities
|
|
||||||
tags:
|
|
||||||
- Schemas
|
|
||||||
|
|
||||||
security:
|
|
||||||
- MuseumPlaceholderAuth: []
|
|
||||||
|
|
@ -9,7 +9,7 @@ const swagger = window.location.search.indexOf('swagger') > -1;
|
||||||
const userUrl = window.location.search.match(/url=(.*)$/);
|
const userUrl = window.location.search.match(/url=(.*)$/);
|
||||||
|
|
||||||
const specUrl =
|
const specUrl =
|
||||||
(userUrl && userUrl[1]) || (swagger ? 'museum.yaml' : big ? 'big-openapi.json' : 'museum.yaml');
|
(userUrl && userUrl[1]) || (swagger ? 'big-openapi.json' : big ? 'big-openapi.json' : 'big-openapi.json');
|
||||||
|
|
||||||
const options: RedocRawOptions = {
|
const options: RedocRawOptions = {
|
||||||
nativeScrollbars: false,
|
nativeScrollbars: false,
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ export default (env: { playground?: boolean; bench?: boolean } = {}) => ({
|
||||||
env.playground
|
env.playground
|
||||||
? 'playground/hmr-playground.tsx'
|
? 'playground/hmr-playground.tsx'
|
||||||
: env.bench
|
: env.bench
|
||||||
? '../benchmark/index.tsx'
|
? '../benchmark/index.tsx'
|
||||||
: 'index.tsx',
|
: 'index.tsx',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
target: 'web',
|
target: 'web',
|
||||||
|
|
@ -104,8 +104,8 @@ export default (env: { playground?: boolean; bench?: boolean } = {}) => ({
|
||||||
template: env.playground
|
template: env.playground
|
||||||
? 'demo/playground/index.html'
|
? 'demo/playground/index.html'
|
||||||
: env.bench
|
: env.bench
|
||||||
? 'benchmark/index.html'
|
? 'benchmark/index.html'
|
||||||
: 'demo/index.html',
|
: 'demo/index.html',
|
||||||
}),
|
}),
|
||||||
new webpack.ProvidePlugin({
|
new webpack.ProvidePlugin({
|
||||||
Buffer: ['buffer', 'Buffer'],
|
Buffer: ['buffer', 'Buffer'],
|
||||||
|
|
@ -115,7 +115,7 @@ export default (env: { playground?: boolean; bench?: boolean } = {}) => ({
|
||||||
webpackIgnore(/json-schema-ref-parser\/lib\/dereference\.js/),
|
webpackIgnore(/json-schema-ref-parser\/lib\/dereference\.js/),
|
||||||
webpackIgnore(/^\.\/SearchWorker\.worker$/),
|
webpackIgnore(/^\.\/SearchWorker\.worker$/),
|
||||||
new CopyWebpackPlugin({
|
new CopyWebpackPlugin({
|
||||||
patterns: ['demo/museum.yaml'],
|
patterns: ['demo/big-openapi.json'],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
|
||||||
10
package.json
10
package.json
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "redoc",
|
"name": "redoc",
|
||||||
"version": "2.5.2",
|
"version": "2.5.0",
|
||||||
"description": "ReDoc",
|
"description": "ReDoc",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
@ -62,7 +62,6 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@cfaester/enzyme-adapter-react-18": "^0.8.0",
|
"@cfaester/enzyme-adapter-react-18": "^0.8.0",
|
||||||
"@cypress/webpack-preprocessor": "^5.17.1",
|
|
||||||
"@size-limit/file": "^11.1.4",
|
"@size-limit/file": "^11.1.4",
|
||||||
"@types/chai": "^4.2.18",
|
"@types/chai": "^4.2.18",
|
||||||
"@types/dompurify": "^2.2.2",
|
"@types/dompurify": "^2.2.2",
|
||||||
|
|
@ -90,7 +89,6 @@
|
||||||
"copy-webpack-plugin": "^9.0.0",
|
"copy-webpack-plugin": "^9.0.0",
|
||||||
"core-js": "^3.13.1",
|
"core-js": "^3.13.1",
|
||||||
"css-loader": "^5.2.6",
|
"css-loader": "^5.2.6",
|
||||||
"cypress": "^13.8.1",
|
|
||||||
"enzyme": "^3.11.0",
|
"enzyme": "^3.11.0",
|
||||||
"enzyme-to-json": "^3.6.2",
|
"enzyme-to-json": "^3.6.2",
|
||||||
"esbuild-loader": "^4.3.0",
|
"esbuild-loader": "^4.3.0",
|
||||||
|
|
@ -126,7 +124,7 @@
|
||||||
"url": "^0.11.1",
|
"url": "^0.11.1",
|
||||||
"webpack": "^5.94.0",
|
"webpack": "^5.94.0",
|
||||||
"webpack-cli": "^5.1.4",
|
"webpack-cli": "^5.1.4",
|
||||||
"webpack-dev-server": "^5.2.1",
|
"webpack-dev-server": "^4.15.1",
|
||||||
"webpack-node-externals": "^3.0.0",
|
"webpack-node-externals": "^3.0.0",
|
||||||
"workerize-loader": "github:redocly/workerize-loader#webpack-5-dist"
|
"workerize-loader": "github:redocly/workerize-loader#webpack-5-dist"
|
||||||
},
|
},
|
||||||
|
|
@ -147,8 +145,8 @@
|
||||||
"lunr": "^2.3.9",
|
"lunr": "^2.3.9",
|
||||||
"mark.js": "^8.11.1",
|
"mark.js": "^8.11.1",
|
||||||
"marked": "^4.3.0",
|
"marked": "^4.3.0",
|
||||||
"mobx-react": "9.2.0",
|
"mobx-react": "^9.1.1",
|
||||||
"openapi-sampler": "^1.6.2",
|
"openapi-sampler": "^1.5.0",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
"perfect-scrollbar": "^1.5.5",
|
"perfect-scrollbar": "^1.5.5",
|
||||||
"polished": "^4.2.2",
|
"polished": "^4.2.2",
|
||||||
|
|
|
||||||
|
|
@ -73,8 +73,8 @@ export const PropertyNameCell = styled(PropertyCell)`
|
||||||
}
|
}
|
||||||
|
|
||||||
${({ kind }) =>
|
${({ kind }) =>
|
||||||
kind === 'patternProperties' &&
|
kind === 'patternProperties' &&
|
||||||
css`
|
css`
|
||||||
> span.property-name {
|
> span.property-name {
|
||||||
display: inline-table;
|
display: inline-table;
|
||||||
white-space: break-spaces;
|
white-space: break-spaces;
|
||||||
|
|
@ -89,9 +89,9 @@ export const PropertyNameCell = styled(PropertyCell)`
|
||||||
`}
|
`}
|
||||||
|
|
||||||
${({ kind = '' }) =>
|
${({ kind = '' }) =>
|
||||||
['field', 'additionalProperties', 'patternProperties'].includes(kind)
|
['field', 'additionalProperties', 'patternProperties'].includes(kind)
|
||||||
? ''
|
? ''
|
||||||
: 'font-style: italic'};
|
: 'font-style: italic'};
|
||||||
|
|
||||||
${extensionsHook('PropertyNameCell')};
|
${extensionsHook('PropertyNameCell')};
|
||||||
`;
|
`;
|
||||||
|
|
@ -151,7 +151,7 @@ export const PropertiesTable = styled.table`
|
||||||
border-collapse: separate;
|
border-collapse: separate;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
font-size: ${props => props.theme.typography.fontSize};
|
font-size: ${props => props.theme.typography.fontSize};
|
||||||
|
direction: ltr;
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ export const H2 = styled.h2`
|
||||||
${headerCommonMixin(2)};
|
${headerCommonMixin(2)};
|
||||||
color: ${({ theme }) => theme.colors.text.primary};
|
color: ${({ theme }) => theme.colors.text.primary};
|
||||||
margin: 0 0 20px;
|
margin: 0 0 20px;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
${extensionsHook('H2')};
|
${extensionsHook('H2')};
|
||||||
`;
|
`;
|
||||||
|
|
@ -31,6 +32,7 @@ export const H2 = styled.h2`
|
||||||
export const H3 = styled.h2`
|
export const H3 = styled.h2`
|
||||||
${headerCommonMixin(3)};
|
${headerCommonMixin(3)};
|
||||||
color: ${({ theme }) => theme.colors.text.primary};
|
color: ${({ theme }) => theme.colors.text.primary};
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
${extensionsHook('H3')};
|
${extensionsHook('H3')};
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ export class ApiInfo extends React.Component<ApiInfoProps> {
|
||||||
{info.title} {version}
|
{info.title} {version}
|
||||||
</ApiHeader>
|
</ApiHeader>
|
||||||
{!hideDownloadButtons && (
|
{!hideDownloadButtons && (
|
||||||
<p>
|
<p style={{ 'direction' : 'ltr', 'textAlign':'left' }}>
|
||||||
{l('downloadSpecification')}:
|
{l('downloadSpecification')}:
|
||||||
{downloadUrls?.map(({ title, url }) => {
|
{downloadUrls?.map(({ title, url }) => {
|
||||||
return (
|
return (
|
||||||
|
|
@ -96,12 +96,12 @@ export class ApiInfo extends React.Component<ApiInfoProps> {
|
||||||
)}
|
)}
|
||||||
<StyledMarkdownBlock>
|
<StyledMarkdownBlock>
|
||||||
{((info.license || info.contact || info.termsOfService) && (
|
{((info.license || info.contact || info.termsOfService) && (
|
||||||
<InfoSpanBoxWrap>
|
<InfoSpanBoxWrap>
|
||||||
<InfoSpanBox>
|
<InfoSpanBox>
|
||||||
{email} {website} {license} {terms}
|
{email} {website} {license} {terms}
|
||||||
</InfoSpanBox>
|
</InfoSpanBox>
|
||||||
</InfoSpanBoxWrap>
|
</InfoSpanBoxWrap>
|
||||||
)) ||
|
)) ||
|
||||||
null}
|
null}
|
||||||
</StyledMarkdownBlock>
|
</StyledMarkdownBlock>
|
||||||
<Markdown source={store.spec.info.summary} data-role="redoc-summary" />
|
<Markdown source={store.spec.info.summary} data-role="redoc-summary" />
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,211 @@
|
||||||
import { H1, MiddlePanel } from '../../common-elements';
|
import * as classnames from 'classnames';
|
||||||
import styled, { extensionsHook } from '../../styled-components';
|
import { darken } from 'polished';
|
||||||
|
|
||||||
const delimiterWidth = 15;
|
import { deprecatedCss, ShelfIcon } from '../../common-elements';
|
||||||
|
import styled, { css, media, ResolvedThemeInterface } from '../../styled-components';
|
||||||
|
|
||||||
export const ApiInfoWrap = MiddlePanel;
|
export const OperationBadge = styled.span.attrs((props: { type: string; color?: string }) => ({
|
||||||
|
className: `operation-type ${props.type}`,
|
||||||
export const ApiHeader = styled(H1)`
|
}))<{ type: string; color?: string }>`
|
||||||
margin-top: 0;
|
width: 9ex;
|
||||||
margin-bottom: 0.5em;
|
|
||||||
|
|
||||||
${extensionsHook('ApiHeader')};
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const DownloadButton = styled.a`
|
|
||||||
border: 1px solid ${props => props.theme.colors.primary.main};
|
|
||||||
color: ${props => props.theme.colors.primary.main};
|
|
||||||
font-weight: normal;
|
|
||||||
margin-left: 0.5em;
|
|
||||||
padding: 4px 8px 4px;
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-decoration: none;
|
height: ${props => props.theme.typography.code.fontSize};
|
||||||
cursor: pointer;
|
line-height: ${props => props.theme.typography.code.fontSize};
|
||||||
|
background-color: ${props => props.color || '#333'};
|
||||||
|
border-radius: 3px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 6px 4px;
|
||||||
|
font-size: 7px;
|
||||||
|
font-family: Verdana, sans-serif; // web-safe
|
||||||
|
color: white;
|
||||||
|
text-transform: uppercase;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 6px;
|
||||||
|
margin-top: 2px;
|
||||||
|
margin-left: 6px;
|
||||||
|
|
||||||
${extensionsHook('DownloadButton')};
|
&.get {
|
||||||
`;
|
background-color: ${({ theme }) => theme.colors.http.get};
|
||||||
|
|
||||||
export const InfoSpan = styled.span`
|
|
||||||
&::before {
|
|
||||||
content: '|';
|
|
||||||
display: inline-block;
|
|
||||||
opacity: 0.5;
|
|
||||||
width: ${delimiterWidth}px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:last-child::after {
|
&.post {
|
||||||
display: none;
|
background-color: ${({ theme }) => theme.colors.http.post};
|
||||||
|
}
|
||||||
|
|
||||||
|
&.put {
|
||||||
|
background-color: ${({ theme }) => theme.colors.http.put};
|
||||||
|
}
|
||||||
|
|
||||||
|
&.options {
|
||||||
|
background-color: ${({ theme }) => theme.colors.http.options};
|
||||||
|
}
|
||||||
|
|
||||||
|
&.patch {
|
||||||
|
background-color: ${({ theme }) => theme.colors.http.patch};
|
||||||
|
}
|
||||||
|
|
||||||
|
&.delete {
|
||||||
|
background-color: ${({ theme }) => theme.colors.http.delete};
|
||||||
|
}
|
||||||
|
|
||||||
|
&.basic {
|
||||||
|
background-color: ${({ theme }) => theme.colors.http.basic};
|
||||||
|
}
|
||||||
|
|
||||||
|
&.link {
|
||||||
|
background-color: ${({ theme }) => theme.colors.http.link};
|
||||||
|
}
|
||||||
|
|
||||||
|
&.head {
|
||||||
|
background-color: ${({ theme }) => theme.colors.http.head};
|
||||||
|
}
|
||||||
|
|
||||||
|
&.hook {
|
||||||
|
background-color: ${({ theme }) => theme.colors.primary.main};
|
||||||
|
}
|
||||||
|
|
||||||
|
&.schema {
|
||||||
|
background-color: ${({ theme }) => theme.colors.http.basic};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const InfoSpanBoxWrap = styled.div`
|
function menuItemActive(
|
||||||
|
depth,
|
||||||
|
{ theme }: { theme: ResolvedThemeInterface },
|
||||||
|
option: string,
|
||||||
|
): string {
|
||||||
|
if (depth > 1) {
|
||||||
|
return theme.sidebar.level1Items[option];
|
||||||
|
} else if (depth === 1) {
|
||||||
|
return theme.sidebar.groupItems[option];
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MenuItemUl = styled.ul<{ $expanded: boolean }>`
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
direction: rtl;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
padding-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& & {
|
||||||
|
font-size: 0.929em;
|
||||||
|
}
|
||||||
|
|
||||||
|
${props => (props.$expanded ? '' : 'display: none;')};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const MenuItemLi = styled.li<{ depth: number }>`
|
||||||
|
list-style: none inside none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
padding: 0;
|
||||||
|
${props => (props.depth === 0 ? 'margin-top: 15px' : '')};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const InfoSpanBox = styled.div`
|
export const menuItemDepth = {
|
||||||
|
0: css`
|
||||||
|
opacity: 0.7;
|
||||||
|
text-transform: ${({ theme }) => theme.sidebar.groupItems.textTransform};
|
||||||
|
font-size: 0.8em;
|
||||||
|
padding-bottom: 0;
|
||||||
|
cursor: default;
|
||||||
|
`,
|
||||||
|
1: css`
|
||||||
|
font-size: 0.929em;
|
||||||
|
text-transform: ${({ theme }) => theme.sidebar.level1Items.textTransform};
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface MenuItemLabelType {
|
||||||
|
$depth: number;
|
||||||
|
$active: boolean;
|
||||||
|
$deprecated?: boolean;
|
||||||
|
$type?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MenuItemLabel = styled.label.attrs((props: MenuItemLabelType) => ({
|
||||||
|
className: classnames('-depth' + props.$depth, {
|
||||||
|
active: props.$active,
|
||||||
|
}),
|
||||||
|
}))<MenuItemLabelType>`
|
||||||
|
cursor: pointer;
|
||||||
|
color: ${props =>
|
||||||
|
props.$active
|
||||||
|
? menuItemActive(props.$depth, props, 'activeTextColor')
|
||||||
|
: props.theme.sidebar.textColor};
|
||||||
|
margin: 0;
|
||||||
|
padding: 12.5px ${props => props.theme.spacing.unit * 4}px;
|
||||||
|
${({ $depth, $type, theme }) =>
|
||||||
|
($type === 'section' && $depth > 1 && 'padding-left: ' + theme.spacing.unit * 8 + 'px;') || ''}
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
justify-content: space-between;
|
||||||
// hide separator on new lines: idea from https://stackoverflow.com/a/31732902/1749888
|
font-family: ${props => props.theme.typography.headings.fontFamily};
|
||||||
margin-left: -${delimiterWidth}px;
|
${props => menuItemDepth[props.$depth]};
|
||||||
|
background-color: ${props =>
|
||||||
|
props.$active
|
||||||
|
? menuItemActive(props.$depth, props, 'activeBackgroundColor')
|
||||||
|
: props.theme.sidebar.backgroundColor};
|
||||||
|
|
||||||
|
${props => (props.$deprecated && deprecatedCss) || ''};
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: ${props => menuItemActive(props.$depth, props, 'activeTextColor')};
|
||||||
|
background-color: ${props => menuItemActive(props.$depth, props, 'activeBackgroundColor')};
|
||||||
|
}
|
||||||
|
|
||||||
|
${ShelfIcon} {
|
||||||
|
height: ${({ theme }) => theme.sidebar.arrow.size};
|
||||||
|
width: ${({ theme }) => theme.sidebar.arrow.size};
|
||||||
|
polygon {
|
||||||
|
fill: ${({ theme }) => theme.sidebar.arrow.color};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const MenuItemTitle = styled.span<{ width?: string }>`
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: ${props => (props.width ? props.width : 'auto')};
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const RedocAttribution = styled.div`
|
||||||
|
${({ theme }) => css`
|
||||||
|
font-size: 0.8em;
|
||||||
|
margin-top: ${theme.spacing.unit * 2}px;
|
||||||
|
text-align: center;
|
||||||
|
position: fixed;
|
||||||
|
width: ${theme.sidebar.width};
|
||||||
|
bottom: 0;
|
||||||
|
background: ${theme.sidebar.backgroundColor};
|
||||||
|
|
||||||
|
a,
|
||||||
|
a:visited,
|
||||||
|
a:hover {
|
||||||
|
color: ${theme.sidebar.textColor} !important;
|
||||||
|
padding: ${theme.spacing.unit}px 0;
|
||||||
|
border-top: 1px solid ${darken(0.1, theme.sidebar.backgroundColor)};
|
||||||
|
text-decoration: none;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
`};
|
||||||
|
img {
|
||||||
|
width: 15px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
${media.lessThan('small')`
|
||||||
|
width: 100%;
|
||||||
|
`};
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { ShelfIcon } from '../../common-elements';
|
import { ShelfIcon } from '../../common-elements';
|
||||||
import { OperationModel } from '../../services';
|
import { OperationModel } from '../../services';
|
||||||
import { Markdown } from '../Markdown/Markdown';
|
|
||||||
import { OptionsContext } from '../OptionsProvider';
|
import { OptionsContext } from '../OptionsProvider';
|
||||||
import { SelectOnClick } from '../SelectOnClick/SelectOnClick';
|
import { SelectOnClick } from '../SelectOnClick/SelectOnClick';
|
||||||
|
|
||||||
|
|
@ -59,7 +58,7 @@ export class Endpoint extends React.Component<EndpointProps, EndpointState> {
|
||||||
color={inverted ? 'black' : 'white'}
|
color={inverted ? 'black' : 'white'}
|
||||||
size={'20px'}
|
size={'20px'}
|
||||||
direction={expanded ? 'up' : 'down'}
|
direction={expanded ? 'up' : 'down'}
|
||||||
style={{ marginRight: '-25px' }}
|
style={{ marginRight: '-5px' }}
|
||||||
/>
|
/>
|
||||||
</EndpointInfo>
|
</EndpointInfo>
|
||||||
<ServersOverlay $expanded={expanded} aria-hidden={!expanded}>
|
<ServersOverlay $expanded={expanded} aria-hidden={!expanded}>
|
||||||
|
|
@ -70,7 +69,9 @@ export class Endpoint extends React.Component<EndpointProps, EndpointState> {
|
||||||
const basePath = getBasePath(normalizedUrl);
|
const basePath = getBasePath(normalizedUrl);
|
||||||
return (
|
return (
|
||||||
<ServerItem key={normalizedUrl}>
|
<ServerItem key={normalizedUrl}>
|
||||||
<Markdown source={server.description || ''} compact={true} />
|
<p style={{ textAlign: 'left', margin:'0 0 5px 0',padding:'0' }}>
|
||||||
|
{server.description || ''}
|
||||||
|
</p>
|
||||||
<SelectOnClick>
|
<SelectOnClick>
|
||||||
<ServerUrl>
|
<ServerUrl>
|
||||||
<span>
|
<span>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
import { css } from '../../styled-components';
|
import { css } from '../../styled-components';
|
||||||
|
|
||||||
export const jsonStyles = css`
|
export const jsonStyles = css`
|
||||||
|
.redoc-json{
|
||||||
|
direction: ltr;
|
||||||
|
}
|
||||||
|
|
||||||
.redoc-json code > .collapser {
|
.redoc-json code > .collapser {
|
||||||
display: none;
|
display: none;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
|
||||||
|
|
@ -16,16 +16,17 @@ const StyledMarkdownSpan = styled(StyledMarkdownBlock)`
|
||||||
const sanitize = (sanitize, html) => (sanitize ? dompurify.sanitize(html) : html);
|
const sanitize = (sanitize, html) => (sanitize ? dompurify.sanitize(html) : html);
|
||||||
|
|
||||||
export function SanitizedMarkdownHTML({
|
export function SanitizedMarkdownHTML({
|
||||||
inline,
|
inline,
|
||||||
compact,
|
compact,
|
||||||
...rest
|
...rest
|
||||||
}: StylingMarkdownProps & { html: string; className?: string; 'data-role'?: string }) {
|
}: StylingMarkdownProps & { html: string; className?: string; 'data-role'?: string }) {
|
||||||
const Wrap = inline ? StyledMarkdownSpan : StyledMarkdownBlock;
|
const Wrap = inline ? StyledMarkdownSpan : StyledMarkdownBlock;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OptionsConsumer>
|
<OptionsConsumer>
|
||||||
{options => (
|
{options => (
|
||||||
<Wrap
|
<Wrap
|
||||||
|
style={{'direction':'rtl'}}
|
||||||
className={'redoc-markdown ' + (rest.className || '')}
|
className={'redoc-markdown ' + (rest.className || '')}
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: sanitize(options.sanitize, rest.html),
|
__html: sanitize(options.sanitize, rest.html),
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ export const StyledMarkdownBlock = styled(
|
||||||
>,
|
>,
|
||||||
)`
|
)`
|
||||||
font-family: ${props => props.theme.typography.fontFamily};
|
font-family: ${props => props.theme.typography.fontFamily};
|
||||||
|
direction: ltr;
|
||||||
font-weight: ${props => props.theme.typography.fontWeightRegular};
|
font-weight: ${props => props.theme.typography.fontWeightRegular};
|
||||||
line-height: ${props => props.theme.typography.lineHeight};
|
line-height: ${props => props.theme.typography.lineHeight};
|
||||||
|
|
||||||
|
|
@ -38,8 +39,8 @@ export const StyledMarkdownBlock = styled(
|
||||||
}
|
}
|
||||||
|
|
||||||
${({ $compact }) =>
|
${({ $compact }) =>
|
||||||
$compact &&
|
$compact &&
|
||||||
`
|
`
|
||||||
p:first-child {
|
p:first-child {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
@ -49,8 +50,8 @@ export const StyledMarkdownBlock = styled(
|
||||||
`}
|
`}
|
||||||
|
|
||||||
${({ $inline }) =>
|
${({ $inline }) =>
|
||||||
$inline &&
|
$inline &&
|
||||||
` p {
|
` p {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}`}
|
}`}
|
||||||
|
|
||||||
|
|
@ -105,9 +106,10 @@ export const StyledMarkdownBlock = styled(
|
||||||
blockquote {
|
blockquote {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
padding: 0 15px;
|
margin-top: 1em;
|
||||||
|
padding: 0 0;
|
||||||
color: #777;
|
color: #777;
|
||||||
border-left: 4px solid #ddd;
|
border-right: 4px solid #ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
|
|
@ -117,7 +119,8 @@ export const StyledMarkdownBlock = styled(
|
||||||
|
|
||||||
ul,
|
ul,
|
||||||
ol {
|
ol {
|
||||||
padding-left: 2em;
|
text-align: right;
|
||||||
|
padding-right: 2em;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,23 +42,23 @@ export class Redoc extends React.Component<RedocProps> {
|
||||||
<StoreProvider value={store}>
|
<StoreProvider value={store}>
|
||||||
<OptionsProvider value={options}>
|
<OptionsProvider value={options}>
|
||||||
<RedocWrap className="redoc-wrap">
|
<RedocWrap className="redoc-wrap">
|
||||||
<StickyResponsiveSidebar menu={menu} className="menu-content">
|
|
||||||
<ApiLogo info={spec.info} />
|
|
||||||
{(!options.disableSearch && (
|
|
||||||
<SearchBox
|
|
||||||
search={search!}
|
|
||||||
marker={marker}
|
|
||||||
getItemById={menu.getItemById}
|
|
||||||
onActivate={menu.activateAndScroll}
|
|
||||||
/>
|
|
||||||
)) ||
|
|
||||||
null}
|
|
||||||
<SideMenu menu={menu} />
|
|
||||||
</StickyResponsiveSidebar>
|
|
||||||
<ApiContentWrap className="api-content">
|
<ApiContentWrap className="api-content">
|
||||||
<ApiInfo store={store} />
|
<ApiInfo store={store} />
|
||||||
<ContentItems items={menu.items as any} />
|
<ContentItems items={menu.items as any} />
|
||||||
</ApiContentWrap>
|
</ApiContentWrap>
|
||||||
|
<StickyResponsiveSidebar menu={menu} className="menu-content">
|
||||||
|
<ApiLogo info={spec.info} />
|
||||||
|
{(!options.disableSearch && (
|
||||||
|
<SearchBox
|
||||||
|
search={search!}
|
||||||
|
marker={marker}
|
||||||
|
getItemById={menu.getItemById}
|
||||||
|
onActivate={menu.activateAndScroll}
|
||||||
|
/>
|
||||||
|
)) ||
|
||||||
|
null}
|
||||||
|
<SideMenu menu={menu} />
|
||||||
|
</StickyResponsiveSidebar>
|
||||||
<BackgroundStub />
|
<BackgroundStub />
|
||||||
</RedocWrap>
|
</RedocWrap>
|
||||||
</OptionsProvider>
|
</OptionsProvider>
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ export const RedocWrap = styled.div`
|
||||||
|
|
||||||
export const ApiContentWrap = styled.div`
|
export const ApiContentWrap = styled.div`
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
direction: rtl;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: calc(100% - ${props => props.theme.sidebar.width});
|
width: calc(100% - ${props => props.theme.sidebar.width});
|
||||||
|
|
@ -35,6 +36,10 @@ export const ApiContentWrap = styled.div`
|
||||||
`};
|
`};
|
||||||
|
|
||||||
contain: layout;
|
contain: layout;
|
||||||
|
|
||||||
|
p {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const BackgroundStub = styled.div`
|
export const BackgroundStub = styled.div`
|
||||||
|
|
@ -42,15 +47,15 @@ export const BackgroundStub = styled.div`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
left: 0;
|
||||||
width: ${({ theme }) => {
|
width: ${({ theme }) => {
|
||||||
if (theme.rightPanel.width.endsWith('%')) {
|
if (theme.rightPanel.width.endsWith('%')) {
|
||||||
const percents = parseInt(theme.rightPanel.width, 10);
|
const percents = parseInt(theme.rightPanel.width, 10);
|
||||||
return `calc((100% - ${theme.sidebar.width}) * ${percents / 100})`;
|
return `calc((100% - ${theme.sidebar.width}) * ${percents / 100})`;
|
||||||
} else {
|
} else {
|
||||||
return theme.rightPanel.width;
|
return theme.rightPanel.width;
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
${media.lessThan('medium', true)`
|
${media.lessThan('medium', true)`
|
||||||
display: none;
|
display: none;
|
||||||
`};
|
`};
|
||||||
|
|
|
||||||
|
|
@ -148,8 +148,8 @@ export class SearchBox extends React.PureComponent<SearchBoxProps, SearchBoxStat
|
||||||
<SearchInput
|
<SearchInput
|
||||||
value={this.state.term}
|
value={this.state.term}
|
||||||
onKeyDown={this.handleKeyDown}
|
onKeyDown={this.handleKeyDown}
|
||||||
placeholder="Search..."
|
placeholder="جستجو ..."
|
||||||
aria-label="Search"
|
aria-label="جستجو"
|
||||||
type="text"
|
type="text"
|
||||||
onChange={this.search}
|
onChange={this.search}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,18 @@ export const SearchInput = styled.input.attrs(() => ({
|
||||||
}))`
|
}))`
|
||||||
width: calc(100% - ${props => props.theme.spacing.unit * 8}px);
|
width: calc(100% - ${props => props.theme.spacing.unit * 8}px);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
text-align: right;
|
||||||
|
direction: rtl;
|
||||||
margin: 0 ${props => props.theme.spacing.unit * 4}px;
|
margin: 0 ${props => props.theme.spacing.unit * 4}px;
|
||||||
padding: 5px ${props => props.theme.spacing.unit * 2}px 5px
|
padding: 5px ${props => props.theme.spacing.unit * 2}px 5px
|
||||||
${props => props.theme.spacing.unit * 4}px;
|
${props => props.theme.spacing.unit * 4}px;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-bottom: 1px solid
|
border-bottom: 1px solid
|
||||||
${({ theme }) =>
|
${({ theme }) =>
|
||||||
(getLuminance(theme.sidebar.backgroundColor) > 0.5 ? darken : lighten)(
|
(getLuminance(theme.sidebar.backgroundColor) > 0.5 ? darken : lighten)(
|
||||||
0.1,
|
0.1,
|
||||||
theme.sidebar.backgroundColor,
|
theme.sidebar.backgroundColor,
|
||||||
)};
|
)};
|
||||||
font-family: ${({ theme }) => theme.typography.fontFamily};
|
font-family: ${({ theme }) => theme.typography.fontFamily};
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|
@ -66,7 +68,7 @@ export const SearchResultsBox = styled.div`
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
background-color: inherit;
|
background-color: inherit;
|
||||||
}
|
}
|
||||||
|
|
@ -91,10 +93,10 @@ export const ClearIcon = styled.i`
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: ${props => props.theme.spacing.unit * 2}px;
|
width: ${props => props.theme.spacing.unit * 2}px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
right: ${props => props.theme.spacing.unit * 4}px;
|
left: ${props => props.theme.spacing.unit * 4}px;
|
||||||
line-height: 2em;
|
line-height: 2em;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-right: 2px;
|
margin-left: 15px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
color: '#666';
|
color: '#666';
|
||||||
|
|
|
||||||
|
|
@ -1,132 +1,212 @@
|
||||||
import { observer } from 'mobx-react';
|
{
|
||||||
import * as React from 'react';
|
"name": "redoc",
|
||||||
|
"version": "2.5.0",
|
||||||
import { ShelfIcon } from '../../common-elements/shelfs';
|
"description": "ReDoc",
|
||||||
import type { IMenuItem } from '../../services';
|
"repository": {
|
||||||
import { OperationModel } from '../../services';
|
"type": "git",
|
||||||
import { l } from '../../services/Labels';
|
"url": "git://github.com/Redocly/redoc"
|
||||||
import { scrollIntoViewIfNeeded } from '../../utils';
|
},
|
||||||
import { shortenHTTPVerb } from '../../utils/openapi';
|
"browserslist": [
|
||||||
import { OptionsContext } from '../OptionsProvider';
|
"defaults"
|
||||||
import { MenuItems } from './MenuItems';
|
],
|
||||||
import { MenuItemLabel, MenuItemLi, MenuItemTitle, OperationBadge } from './styled.elements';
|
"engines": {
|
||||||
|
"node": ">=6.9",
|
||||||
export interface MenuItemProps {
|
"npm": ">=3.0.0"
|
||||||
item: IMenuItem;
|
},
|
||||||
onActivate?: (item: IMenuItem) => void;
|
"author": "Roman Hotsiy <gotsijroman@gmail.com>",
|
||||||
withoutChildren?: boolean;
|
"license": "MIT",
|
||||||
children?: React.ReactChild;
|
"keywords": [
|
||||||
|
"OpenAPI",
|
||||||
|
"OpenAPI Specification",
|
||||||
|
"Swagger",
|
||||||
|
"JSON-Schema",
|
||||||
|
"API",
|
||||||
|
"REST",
|
||||||
|
"documentation",
|
||||||
|
"React.js"
|
||||||
|
],
|
||||||
|
"main": "bundles/redoc.lib.js",
|
||||||
|
"browser": "bundles/redoc.browser.lib.js",
|
||||||
|
"types": "typings/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"start": "webpack serve --mode=development --env playground --hot --config demo/webpack.config.ts",
|
||||||
|
"start:prod": "webpack serve --env playground --mode=production --config demo/webpack.config.ts",
|
||||||
|
"start:benchmark": "webpack serve --mode=production --env.bench --config demo/webpack.config.ts",
|
||||||
|
"test": "npm run unit && npm run license-check",
|
||||||
|
"unit": "jest --coverage",
|
||||||
|
"test:update-snapshot": "jest --updateSnapshot",
|
||||||
|
"e2e": "cypress run",
|
||||||
|
"e2e-ci": "cypress run --record",
|
||||||
|
"bundlesize": "size-limit",
|
||||||
|
"ts-check": "tsc --noEmit --skipLibCheck",
|
||||||
|
"cy:open": "cypress open",
|
||||||
|
"bundle:clean": "rimraf bundles",
|
||||||
|
"bundle:standalone": "webpack --env production --env standalone --mode=production",
|
||||||
|
"bundle:lib": "webpack --mode=production && npm run declarations",
|
||||||
|
"bundle:browser": "webpack --env production --env browser --mode=production",
|
||||||
|
"bundle": "npm run bundle:clean && npm run bundle:lib && npm run bundle:browser && npm run bundle:standalone",
|
||||||
|
"declarations": "tsc --emitDeclarationOnly -p tsconfig.lib.json && cp -R src/types typings/",
|
||||||
|
"stats": "webpack --env production --env standalone --json --profile --mode=production > stats.json",
|
||||||
|
"prettier": "prettier --write \"src/**/*.{ts,tsx}\"",
|
||||||
|
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 1",
|
||||||
|
"lint": "eslint --fix 'src/**/*.{js,ts,tsx}' --cache",
|
||||||
|
"benchmark": "node ./benchmark/benchmark.js",
|
||||||
|
"start:demo": "webpack serve --hot --config demo/webpack.config.ts --mode=development",
|
||||||
|
"build:demo": "webpack --mode=production --config demo/webpack.config.ts",
|
||||||
|
"publish-cdn": "scripts/publish-cdn.sh",
|
||||||
|
"deploy:demo": "aws s3 sync demo/dist s3://production-redoc-demo --acl=public-read",
|
||||||
|
"license-check": "license-checker --production --onlyAllow 'MIT;ISC;Apache-2.0;BSD;BSD-2-Clause;BSD-3-Clause;CC-BY-4.0;CC0-1.0;Python-2.0 ' --summary",
|
||||||
|
"docker:build": "docker build -f config/docker/Dockerfile -t redoc .",
|
||||||
|
"prepare": "husky install",
|
||||||
|
"pre-commit": "pretty-quick --staged && npm run lint"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@cfaester/enzyme-adapter-react-18": "^0.8.0",
|
||||||
|
"@size-limit/file": "^11.1.4",
|
||||||
|
"@types/chai": "^4.2.18",
|
||||||
|
"@types/dompurify": "^2.2.2",
|
||||||
|
"@types/enzyme": "^3.10.5",
|
||||||
|
"@types/enzyme-to-json": "^1.5.3",
|
||||||
|
"@types/jest": "^29.5.6",
|
||||||
|
"@types/json-pointer": "^1.0.30",
|
||||||
|
"@types/lunr": "^2.3.3",
|
||||||
|
"@types/mark.js": "^8.11.5",
|
||||||
|
"@types/marked": "^4.0.3",
|
||||||
|
"@types/node": "^15.6.1",
|
||||||
|
"@types/prismjs": "^1.16.5",
|
||||||
|
"@types/prop-types": "^15.7.3",
|
||||||
|
"@types/react": "^18.0.0",
|
||||||
|
"@types/react-dom": "^18.0.0",
|
||||||
|
"@types/styled-components": "^5.1.1",
|
||||||
|
"@types/tapable": "^2.2.2",
|
||||||
|
"@types/webpack": "^5.28.0",
|
||||||
|
"@types/webpack-env": "^1.18.0",
|
||||||
|
"@types/yargs": "^17.0.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.55.0",
|
||||||
|
"@typescript-eslint/parser": "^5.55.0",
|
||||||
|
"beautify-benchmark": "^0.2.4",
|
||||||
|
"conventional-changelog-cli": "^3.0.0",
|
||||||
|
"copy-webpack-plugin": "^9.0.0",
|
||||||
|
"core-js": "^3.13.1",
|
||||||
|
"css-loader": "^5.2.6",
|
||||||
|
"enzyme": "^3.11.0",
|
||||||
|
"enzyme-to-json": "^3.6.2",
|
||||||
|
"esbuild-loader": "^4.3.0",
|
||||||
|
"eslint": "^7.27.0",
|
||||||
|
"eslint-plugin-import": "^2.23.4",
|
||||||
|
"eslint-plugin-react": "^7.34.2",
|
||||||
|
"eslint-plugin-react-hooks": "^4.6.2",
|
||||||
|
"fork-ts-checker-webpack-plugin": "^6.2.10",
|
||||||
|
"html-webpack-plugin": "^5.3.1",
|
||||||
|
"husky": "^7.0.0",
|
||||||
|
"jest": "^29.7.0",
|
||||||
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
|
"js-yaml": "^4.1.0",
|
||||||
|
"license-checker": "^25.0.1",
|
||||||
|
"lodash.noop": "^3.0.1",
|
||||||
|
"mobx": "^6.10.2",
|
||||||
|
"outdent": "^0.8.0",
|
||||||
|
"prettier": "^2.3.2",
|
||||||
|
"pretty-quick": "^3.0.0",
|
||||||
|
"raf": "^3.4.1",
|
||||||
|
"react": "^18.0.0",
|
||||||
|
"react-dom": "^18.0.0",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"shelljs": "^0.8.4",
|
||||||
|
"size-limit": "^11.1.4",
|
||||||
|
"style-loader": "^3.3.1",
|
||||||
|
"styled-components": "^5.3.0",
|
||||||
|
"ts-jest": "^29.1.1",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
|
"tslib": "^2.4.0",
|
||||||
|
"typescript": "^4.9.0",
|
||||||
|
"unfetch": "^4.2.0",
|
||||||
|
"url": "^0.11.1",
|
||||||
|
"webpack": "^5.94.0",
|
||||||
|
"webpack-cli": "^5.1.4",
|
||||||
|
"webpack-dev-server": "^4.15.1",
|
||||||
|
"webpack-node-externals": "^3.0.0",
|
||||||
|
"workerize-loader": "github:redocly/workerize-loader#webpack-5-dist"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"core-js": "^3.1.4",
|
||||||
|
"mobx": "^6.0.4",
|
||||||
|
"react": "^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"react-dom": "^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"styled-components": "^4.1.1 || ^5.1.1 || ^6.0.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@redocly/openapi-core": "^1.4.0",
|
||||||
|
"classnames": "^2.3.2",
|
||||||
|
"decko": "^1.2.0",
|
||||||
|
"dompurify": "^3.2.4",
|
||||||
|
"eventemitter3": "^5.0.1",
|
||||||
|
"json-pointer": "^0.6.2",
|
||||||
|
"lunr": "^2.3.9",
|
||||||
|
"mark.js": "^8.11.1",
|
||||||
|
"marked": "^4.3.0",
|
||||||
|
"mobx-react": "^9.1.1",
|
||||||
|
"openapi-sampler": "^1.5.0",
|
||||||
|
"path-browserify": "^1.0.1",
|
||||||
|
"perfect-scrollbar": "^1.5.5",
|
||||||
|
"polished": "^4.2.2",
|
||||||
|
"prismjs": "^1.29.0",
|
||||||
|
"prop-types": "^15.8.1",
|
||||||
|
"react-tabs": "^6.0.2",
|
||||||
|
"slugify": "~1.4.7",
|
||||||
|
"stickyfill": "^1.1.1",
|
||||||
|
"swagger2openapi": "^7.0.8",
|
||||||
|
"url-template": "^2.0.8"
|
||||||
|
},
|
||||||
|
"size-limit": [
|
||||||
|
{
|
||||||
|
"path": "./bundles/redoc.standalone.js",
|
||||||
|
"limit": "350 kB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./bundles/redoc.lib.js",
|
||||||
|
"limit": "100 kB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./bundles/redoc.browser.lib.js",
|
||||||
|
"limit": "100 kB"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"jest": {
|
||||||
|
"testEnvironment": "jsdom",
|
||||||
|
"setupFilesAfterEnv": [
|
||||||
|
"<rootDir>/src/setupTests.ts"
|
||||||
|
],
|
||||||
|
"preset": "ts-jest",
|
||||||
|
"collectCoverageFrom": [
|
||||||
|
"src/**/*.{ts,tsx}"
|
||||||
|
],
|
||||||
|
"coverageReporters": [
|
||||||
|
"json",
|
||||||
|
"lcov",
|
||||||
|
"text-summary"
|
||||||
|
],
|
||||||
|
"coveragePathIgnorePatterns": [
|
||||||
|
"\\.d\\.ts$",
|
||||||
|
"/benchmark/",
|
||||||
|
"/node_modules/",
|
||||||
|
"src/services/__tests__/models/helpers.ts"
|
||||||
|
],
|
||||||
|
"modulePathIgnorePatterns": [
|
||||||
|
"/benchmark/",
|
||||||
|
"src/services/__tests__/models/helpers.ts"
|
||||||
|
],
|
||||||
|
"snapshotSerializers": [
|
||||||
|
"enzyme-to-json/serializer"
|
||||||
|
],
|
||||||
|
"moduleNameMapper": {
|
||||||
|
"\\.(css|less)$": "<rootDir>/src/empty.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"prettier": {
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"printWidth": 100,
|
||||||
|
"arrowParens": "avoid"
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
|
||||||
export class MenuItem extends React.Component<MenuItemProps> {
|
|
||||||
ref = React.createRef<HTMLLabelElement>();
|
|
||||||
|
|
||||||
activate = (evt: React.MouseEvent<HTMLElement>) => {
|
|
||||||
this.props.onActivate!(this.props.item);
|
|
||||||
evt.stopPropagation();
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.scrollIntoViewIfActive();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
this.scrollIntoViewIfActive();
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollIntoViewIfActive() {
|
|
||||||
if (this.props.item.active && this.ref.current) {
|
|
||||||
scrollIntoViewIfNeeded(this.ref.current);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { item, withoutChildren } = this.props;
|
|
||||||
return (
|
|
||||||
<MenuItemLi
|
|
||||||
tabIndex={0}
|
|
||||||
onClick={this.activate}
|
|
||||||
onKeyDown={evt => {
|
|
||||||
// Space or Enter key will activate the menu item
|
|
||||||
if (evt.key === 'Enter' || evt.key === ' ') {
|
|
||||||
this.props.onActivate!(this.props.item);
|
|
||||||
evt.stopPropagation();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
depth={item.depth}
|
|
||||||
data-item-id={item.id}
|
|
||||||
role="menuitem"
|
|
||||||
aria-label={item.sidebarLabel}
|
|
||||||
aria-expanded={item.expanded}
|
|
||||||
>
|
|
||||||
{item.type === 'operation' ? (
|
|
||||||
<OperationMenuItemContent {...this.props} item={item as OperationModel} />
|
|
||||||
) : (
|
|
||||||
<MenuItemLabel $depth={item.depth} $active={item.active} $type={item.type} ref={this.ref}>
|
|
||||||
{item.type === 'schema' && <OperationBadge type="schema">schema</OperationBadge>}
|
|
||||||
<MenuItemTitle width="calc(100% - 38px)" title={item.sidebarLabel}>
|
|
||||||
{item.sidebarLabel}
|
|
||||||
{this.props.children}
|
|
||||||
</MenuItemTitle>
|
|
||||||
{(item.depth > 0 && item.items.length > 0 && (
|
|
||||||
<ShelfIcon float={'right'} direction={item.expanded ? 'down' : 'right'} />
|
|
||||||
)) ||
|
|
||||||
null}
|
|
||||||
</MenuItemLabel>
|
|
||||||
)}
|
|
||||||
{!withoutChildren && item.items && item.items.length > 0 && (
|
|
||||||
<MenuItems
|
|
||||||
expanded={item.expanded}
|
|
||||||
items={item.items}
|
|
||||||
onActivate={this.props.onActivate}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</MenuItemLi>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OperationMenuItemContentProps {
|
|
||||||
item: OperationModel;
|
|
||||||
children?: React.ReactChild;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const OperationMenuItemContent = observer((props: OperationMenuItemContentProps) => {
|
|
||||||
const { item } = props;
|
|
||||||
const ref = React.createRef<HTMLLabelElement>();
|
|
||||||
const { showWebhookVerb } = React.useContext(OptionsContext);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (props.item.active && ref.current) {
|
|
||||||
scrollIntoViewIfNeeded(ref.current);
|
|
||||||
}
|
|
||||||
}, [props.item.active, ref]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MenuItemLabel
|
|
||||||
$depth={item.depth}
|
|
||||||
$active={item.active}
|
|
||||||
$deprecated={item.deprecated}
|
|
||||||
ref={ref}
|
|
||||||
>
|
|
||||||
{item.badges &&
|
|
||||||
item.badges?.map(({ name, color }) => (
|
|
||||||
<OperationBadge type="badge" color={color} key={name}>
|
|
||||||
{name}
|
|
||||||
</OperationBadge>
|
|
||||||
))}
|
|
||||||
{item.isWebhook ? (
|
|
||||||
<OperationBadge type="hook">
|
|
||||||
{showWebhookVerb ? item.httpVerb : l('webhook')}
|
|
||||||
</OperationBadge>
|
|
||||||
) : (
|
|
||||||
<OperationBadge type={item.httpVerb}>{shortenHTTPVerb(item.httpVerb)}</OperationBadge>
|
|
||||||
)}
|
|
||||||
<MenuItemTitle tabIndex={0} width="calc(100% - 38px)">
|
|
||||||
{item.sidebarLabel}
|
|
||||||
{props.children}
|
|
||||||
</MenuItemTitle>
|
|
||||||
</MenuItemLabel>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@ import { OptionsContext } from '../OptionsProvider';
|
||||||
import { MenuItems } from './MenuItems';
|
import { MenuItems } from './MenuItems';
|
||||||
|
|
||||||
import { PerfectScrollbarWrap } from '../../common-elements/perfect-scrollbar';
|
import { PerfectScrollbarWrap } from '../../common-elements/perfect-scrollbar';
|
||||||
import { RedocAttribution } from './styled.elements';
|
|
||||||
import RedoclyLogo from './Logo';
|
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class SideMenu extends React.Component<{ menu: MenuStore; className?: string }> {
|
export class SideMenu extends React.Component<{ menu: MenuStore; className?: string }> {
|
||||||
|
|
@ -27,12 +25,6 @@ export class SideMenu extends React.Component<{ menu: MenuStore; className?: str
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MenuItems items={store.items} onActivate={this.activate} root={true} />
|
<MenuItems items={store.items} onActivate={this.activate} root={true} />
|
||||||
<RedocAttribution>
|
|
||||||
<a target="_blank" rel="noopener noreferrer" href="https://redocly.com/redoc/">
|
|
||||||
<RedoclyLogo />
|
|
||||||
API docs by Redocly
|
|
||||||
</a>
|
|
||||||
</RedocAttribution>
|
|
||||||
</PerfectScrollbarWrap>
|
</PerfectScrollbarWrap>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ export const OperationBadge = styled.span.attrs((props: { type: string; color?:
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
|
margin-left: 6px;
|
||||||
|
|
||||||
&.get {
|
&.get {
|
||||||
background-color: ${({ theme }) => theme.colors.http.get};
|
background-color: ${({ theme }) => theme.colors.http.get};
|
||||||
|
|
@ -87,6 +88,8 @@ function menuItemActive(
|
||||||
export const MenuItemUl = styled.ul<{ $expanded: boolean }>`
|
export const MenuItemUl = styled.ul<{ $expanded: boolean }>`
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
direction: rtl;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
&:first-child {
|
&:first-child {
|
||||||
padding-bottom: 32px;
|
padding-bottom: 32px;
|
||||||
|
|
@ -135,21 +138,21 @@ export const MenuItemLabel = styled.label.attrs((props: MenuItemLabelType) => ({
|
||||||
}))<MenuItemLabelType>`
|
}))<MenuItemLabelType>`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: ${props =>
|
color: ${props =>
|
||||||
props.$active
|
props.$active
|
||||||
? menuItemActive(props.$depth, props, 'activeTextColor')
|
? menuItemActive(props.$depth, props, 'activeTextColor')
|
||||||
: props.theme.sidebar.textColor};
|
: props.theme.sidebar.textColor};
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 12.5px ${props => props.theme.spacing.unit * 4}px;
|
padding: 12.5px ${props => props.theme.spacing.unit * 4}px;
|
||||||
${({ $depth, $type, theme }) =>
|
${({ $depth, $type, theme }) =>
|
||||||
($type === 'section' && $depth > 1 && 'padding-left: ' + theme.spacing.unit * 8 + 'px;') || ''}
|
($type === 'section' && $depth > 1 && 'padding-left: ' + theme.spacing.unit * 8 + 'px;') || ''}
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
font-family: ${props => props.theme.typography.headings.fontFamily};
|
font-family: ${props => props.theme.typography.headings.fontFamily};
|
||||||
${props => menuItemDepth[props.$depth]};
|
${props => menuItemDepth[props.$depth]};
|
||||||
background-color: ${props =>
|
background-color: ${props =>
|
||||||
props.$active
|
props.$active
|
||||||
? menuItemActive(props.$depth, props, 'activeBackgroundColor')
|
? menuItemActive(props.$depth, props, 'activeBackgroundColor')
|
||||||
: props.theme.sidebar.backgroundColor};
|
: props.theme.sidebar.backgroundColor};
|
||||||
|
|
||||||
${props => (props.$deprecated && deprecatedCss) || ''};
|
${props => (props.$deprecated && deprecatedCss) || ''};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ const defaultTheme: ThemeInterface = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
sidebar: {
|
sidebar: {
|
||||||
width: '260px',
|
width: '300px',
|
||||||
backgroundColor: '#fafafa',
|
backgroundColor: '#fafafa',
|
||||||
textColor: '#333333',
|
textColor: '#333333',
|
||||||
activeTextColor: theme =>
|
activeTextColor: theme =>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user