Merge remote-tracking branch 'origin/master'
@@ -16,7 +16,7 @@ node_js:
|
|||||||
- "12"
|
- "12"
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- DEPLOY_ENV=GH_PAGES
|
- DEPLOY_ENV=POSTWOMAN_IO
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
|
|||||||
47
README.md
@@ -23,8 +23,8 @@ When I wrote this, only God and I understood what I was doing. Now, only God kno
|
|||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<br>
|
<br>
|
||||||
<img src="static/screely.png" alt="postwoman" width="100%">
|
<img src="static/screenshot.gif" alt="postwoman" width="100%">
|
||||||
<img src="static/screely2.png" alt="postwoman" width="100%">
|
<img src="static/screenshot2.png" alt="postwoman" width="100%">
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -63,6 +63,15 @@ _Customized themes are also synced with local session storage_
|
|||||||
- Offline support
|
- Offline support
|
||||||
- Low RAM/memory and CPU usage
|
- Low RAM/memory and CPU usage
|
||||||
|
|
||||||
|
:rocket: **Request**: Retrieve data from a URL without having to do a full page refresh
|
||||||
|
|
||||||
|
- Choose `method`
|
||||||
|
- Enter `URL`
|
||||||
|
- Enter `Path`
|
||||||
|
- Copy public "Share URL"
|
||||||
|
- Generate request code for JavaScript XHR, Fetch, cURL
|
||||||
|
- Copy generated request code to clipboard
|
||||||
|
|
||||||
:electric_plug: **Web Socket**: Establish full-duplex communication channels over a single TCP connection
|
:electric_plug: **Web Socket**: Establish full-duplex communication channels over a single TCP connection
|
||||||
|
|
||||||
- Send and receive data
|
- Send and receive data
|
||||||
@@ -86,6 +95,9 @@ _Customized themes are also synced with local session storage_
|
|||||||
|
|
||||||
:wave: **Responses**: Contains the status line, headers and the message/response body
|
:wave: **Responses**: Contains the status line, headers and the message/response body
|
||||||
|
|
||||||
|
- Copy response to clipboard
|
||||||
|
- View preview for HTML responses
|
||||||
|
|
||||||
_HTML responses have "Preview HTML" feature_
|
_HTML responses have "Preview HTML" feature_
|
||||||
|
|
||||||
:alarm_clock: **History**: Request entries are synced with local session storage to reuse with a single click
|
:alarm_clock: **History**: Request entries are synced with local session storage to reuse with a single click
|
||||||
@@ -103,7 +115,9 @@ _History entries can be deleted one-by-one or all together_
|
|||||||
|
|
||||||
## Demo
|
## Demo
|
||||||
|
|
||||||
[https://liyasthomas.github.io/postwoman](https://liyasthomas.github.io/postwoman)
|
[https://postwoman.io](https://postwoman.io)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
1. Specify your request method
|
1. Specify your request method
|
||||||
2. Type in your API URL
|
2. Type in your API URL
|
||||||
@@ -177,20 +191,27 @@ See the [CHANGELOG](CHANGELOG.md) file for details.
|
|||||||
* ([contributors](https://github.com/liyasthomas/postwoman/graphs/contributors))
|
* ([contributors](https://github.com/liyasthomas/postwoman/graphs/contributors))
|
||||||
|
|
||||||
### Contributors
|
### Contributors
|
||||||
* [John Harker](https://github.com/NBTX)
|
|
||||||
* [Andrew Bastin](https://github.com/AndrewBastin)
|
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||||
* [Nick Palenchar](https://github.com/nickpalenchar)
|
<!-- prettier-ignore -->
|
||||||
* [Abraham Williams](https://github.com/abraham)
|
<table>
|
||||||
* [Nicholas La Roux](https://github.com/larouxn)
|
<tr>
|
||||||
* [RifqiAlAbqary](https://github.com/reefqi037)
|
<td align="center"><a href="https://github.com/NBTX"><img src="https://github.com/NBTX.png?size=100" width="100px;" alt="John Harker"/><br /><sub><b>John Harker</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=NBTX" title="Code">💻</a></td>
|
||||||
* [izerozlu](https://github.com/izerozlu)
|
<td align="center"><a href="https://github.com/izerozlu"><img src="https://github.com/izerozlu.png?size=100" width="100px;" alt="izerozlu"/><br /><sub><b>izerozlu</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=izerozlu" title="Code">💻</a></td>
|
||||||
* [Thomas Yuba](https://github.com/yubathom)
|
<td align="center"><a href="https://github.com/AndrewBastin"><img src="https://github.com/AndrewBastin.png?size=100" width="100px;" alt="Andrew Bastin"/><br /><sub><b>Andrew Bastin</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=AndrewBastin" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/nickpalenchar"><img src="https://github.com/nickpalenchar.png?size=100" width="100px;" alt="Nick Palenchar"/><br /><sub><b>Nick Palenchar</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=nickpalenchar" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/yubathom"><img src="https://github.com/yubathom.png?size=100" width="100px;" alt="Thomas Yuba"/><br /><sub><b>Thomas Yuba</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=yubathom" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/larouxn"><img src="https://github.com/larouxn.png?size=100" width="100px;" alt="Nicholas La Roux"/><br /><sub><b>Nicholas La Roux</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=larouxn" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||||
|
|
||||||
|
See the list of [contributors](https://github.com/liyasthomas/postwoman/graphs/contributors) who participated in this project.
|
||||||
|
|
||||||
### Thanks
|
### Thanks
|
||||||
* [Dribbble](https://dribbble.com)
|
* [Dribbble](https://dribbble.com)
|
||||||
|
|
||||||
See the list of [contributors](https://github.com/liyasthomas/postwoman/graphs/contributors) who participated in this project.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|||||||
@@ -10,7 +10,11 @@ $responsiveWidth: 720px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
::-webkit-scrollbar-thumb {
|
||||||
background-color: #4a4a4a;
|
background-color: rgba(0, 0, 0, .3);
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background-color: rgba(0, 0, 0, .5);
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
@@ -78,6 +82,9 @@ body.sticky-footer footer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
margin: 4px;
|
margin: 4px;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -88,9 +95,19 @@ button {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
|
|
||||||
|
&.icon {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
color: var(--ac-color);
|
||||||
|
fill: var(--ac-color);
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:not([disabled]):hover,
|
&:not([disabled]):hover,
|
||||||
&:not(.disabled):focus {
|
&:not(.disabled):focus {
|
||||||
background-color: transparent;
|
background-color: var(--bg-color);
|
||||||
box-shadow: inset 0 0 0 2px var(--ac-color);
|
box-shadow: inset 0 0 0 2px var(--ac-color);
|
||||||
color: var(--ac-color);
|
color: var(--ac-color);
|
||||||
}
|
}
|
||||||
@@ -122,51 +139,59 @@ fieldset.blue legend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fieldset.gray {
|
fieldset.gray {
|
||||||
border-color: #9B9B9B;
|
border-color: #BCC2CD;
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset.gray legend {
|
fieldset.gray legend {
|
||||||
color: #9B9B9B;
|
color: #BCC2CD;
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset.green {
|
fieldset.green {
|
||||||
border-color: #B8E986;
|
border-color: #50fa7b;
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset.green legend {
|
fieldset.green legend {
|
||||||
color: #B8E986;
|
color: #50fa7b;
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset.cyan {
|
fieldset.cyan {
|
||||||
border-color: #50E3C2;
|
border-color: #8be9fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset.cyan legend {
|
fieldset.cyan legend {
|
||||||
color: #50E3C2;
|
color: #8be9fd;
|
||||||
}
|
|
||||||
|
|
||||||
fieldset.blue-dark {
|
|
||||||
border-color: #4A90E2;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset.blue-dark legend {
|
|
||||||
color: #4A90E2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset.purple {
|
fieldset.purple {
|
||||||
border-color: #C198FB;
|
border-color: #bd93f9;
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset.purple legend {
|
fieldset.purple legend {
|
||||||
color: #C198FB;
|
color: #bd93f9;
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset.orange {
|
fieldset.orange {
|
||||||
border-color: #F5A623;
|
border-color: #ffb86c;
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset.orange legend {
|
fieldset.orange legend {
|
||||||
color: #F5A623;
|
color: #ffb86c;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset.pink {
|
||||||
|
border-color: #ff79c6;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset.pink legend {
|
||||||
|
color: #ff79c6;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset.red {
|
||||||
|
border-color: #ff5555;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset.red legend {
|
||||||
|
color: #ff5555;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
@@ -187,12 +212,19 @@ pre {
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
select,
|
select,
|
||||||
input,
|
input,
|
||||||
option {
|
option {
|
||||||
height: 41px;
|
height: 41px;
|
||||||
|
|
||||||
|
&:not([readonly]):hover,
|
||||||
|
&:not([readonly]):focus {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
box-shadow: inset 0 0 0 2px var(--ac-color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="checkbox"] {
|
input[type="checkbox"] {
|
||||||
@@ -231,6 +263,11 @@ input[type="checkbox"] {
|
|||||||
background-color: var(--err-color);
|
background-color: var(--err-color);
|
||||||
color: #b2b2b2;
|
color: #b2b2b2;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
|
||||||
|
&.icon {
|
||||||
|
color: #b2b2b2;
|
||||||
|
fill: #b2b2b2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
@@ -258,6 +295,10 @@ ol li {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.show-on-small-screen {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: $responsiveWidth) {
|
@media (max-width: $responsiveWidth) {
|
||||||
header div {
|
header div {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -283,6 +324,10 @@ ol li {
|
|||||||
.hide-on-small-screen {
|
.hide-on-small-screen {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.show-on-small-screen {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#installPWA {
|
#installPWA {
|
||||||
@@ -349,11 +394,8 @@ fieldset#history {
|
|||||||
margin: 4px;
|
margin: 4px;
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#response-details {
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.covers-response {
|
.covers-response {
|
||||||
|
|||||||
@@ -7,37 +7,37 @@
|
|||||||
|
|
||||||
// Dark is the default theme variant.
|
// Dark is the default theme variant.
|
||||||
:root {
|
:root {
|
||||||
--bg-dark-color: #000000;
|
--bg-dark-color: #44475a;
|
||||||
// Background color
|
// Background color
|
||||||
--bg-color: #121212;
|
--bg-color: #282a36;
|
||||||
// Auto-complete color
|
// Auto-complete color
|
||||||
--atc-color: #212121;
|
--atc-color: #3C4556;
|
||||||
// Text color
|
// Text color
|
||||||
--fg-color: #FFF;
|
--fg-color: #f8f8f2;
|
||||||
|
|
||||||
// Error color
|
// Error color
|
||||||
--err-color: #393939;
|
--err-color: #3C4556;
|
||||||
|
|
||||||
// Active color
|
// Active color
|
||||||
--ac-color: #51FF0D;
|
--ac-color: #50fa7b;
|
||||||
// Active text color
|
// Active text color
|
||||||
--act-color: #121212;
|
--act-color: #282a36;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root.light {
|
:root.light {
|
||||||
--bg-dark-color: #ffffff;
|
--bg-dark-color: #e1e4eb;
|
||||||
// Background color
|
// Background color
|
||||||
--bg-color: #F6F8FA;
|
--bg-color: #ebeef5;
|
||||||
// Auto-complete color
|
// Auto-complete color
|
||||||
--atc-color: #F1F1F1;
|
--atc-color: #e1e4eb;
|
||||||
// Text color
|
// Text color
|
||||||
--fg-color: #121212;
|
--fg-color: #5d5d5f;
|
||||||
|
|
||||||
// Error color
|
// Error color
|
||||||
--err-color: invert(#393939, 1);
|
--err-color: invert(#3C4556, 1);
|
||||||
|
|
||||||
// Active color
|
// Active color
|
||||||
--ac-color: #51FF0D;
|
--ac-color: #57b5f9;
|
||||||
// Active text color
|
// Active text color
|
||||||
--act-color: #121212;
|
--act-color: #ebeef5;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,190 +1,186 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="autocomplete-wrapper">
|
<div class="autocomplete-wrapper">
|
||||||
<label>
|
<label>
|
||||||
<slot />
|
<slot />
|
||||||
<input type="text"
|
<input type="text" :placeholder="placeholder" v-model="value" @input="updateSuggestions" @keyup="updateSuggestions" @click="updateSuggestions" @keydown="handleKeystroke" ref="acInput" :spellcheck="spellcheck" :autocapitalize="spellcheck" :autocorrect="spellcheck">
|
||||||
:placeholder="placeholder"
|
|
||||||
v-model="value"
|
|
||||||
@input="updateSuggestions"
|
|
||||||
@keyup="updateSuggestions"
|
|
||||||
@click="updateSuggestions"
|
|
||||||
@keydown="handleKeystroke"
|
|
||||||
ref="acInput"
|
|
||||||
:spellcheck="spellcheck"
|
|
||||||
:autocapitalize="spellcheck"
|
|
||||||
:autocorrect="spellcheck">
|
|
||||||
|
|
||||||
<ul class="suggestions" v-if="suggestions.length > 0 && suggestionsVisible" :style="{ transform: `translate(${suggestionsOffsetLeft}px, 0)` }">
|
<ul class="suggestions" v-if="suggestions.length > 0 && suggestionsVisible" :style="{ transform: `translate(${suggestionsOffsetLeft}px, 0)` }">
|
||||||
<li v-for="(suggestion, index) in suggestions" @click.prevent="forceSuggestion(suggestion)" :class="{ active: currentSuggestionIndex === index }">{{ suggestion }}</li>
|
<li v-for="(suggestion, index) in suggestions" @click.prevent="forceSuggestion(suggestion)" :class="{ active: currentSuggestionIndex === index }">{{ suggestion }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.autocomplete-wrapper {
|
.autocomplete-wrapper {
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
input:focus + ul.suggestions, ul.suggestions:hover {
|
input:focus+ul.suggestions,
|
||||||
display: block;
|
ul.suggestions:hover {
|
||||||
}
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
ul.suggestions {
|
ul.suggestions {
|
||||||
display: none;
|
display: none;
|
||||||
background-color: var(--atc-color);
|
background-color: var(--atc-color);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 90%;
|
top: 90%;
|
||||||
margin: 0 4px;
|
margin: 0 4px;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border-radius: 0 0 4px 4px;
|
border-radius: 0 0 4px 4px;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
transition: transform 200ms ease-out;
|
transition: transform 200ms ease-out;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
margin: 5px 0;
|
padding: 8px 16px;
|
||||||
padding: 10px 10px;
|
font-weight: 700;
|
||||||
font-weight: 700;
|
font-size: 18px;
|
||||||
font-size: 18px;
|
font-family: monospace;
|
||||||
font-family: monospace;
|
white-space: pre-wrap;
|
||||||
white-space: pre-wrap;
|
|
||||||
|
|
||||||
&:hover, &.active {
|
&:last-child {
|
||||||
background-color: var(--ac-color);
|
border-radius: 0 0 4px 4px;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
&:hover,
|
||||||
|
&.active {
|
||||||
|
background-color: var(--ac-color);
|
||||||
|
color: var(--act-color);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const KEY_TAB = 9;
|
const KEY_TAB = 9;
|
||||||
const KEY_ESC = 27;
|
const KEY_ESC = 27;
|
||||||
|
|
||||||
const KEY_ARROW_UP = 38;
|
const KEY_ARROW_UP = 38;
|
||||||
const KEY_ARROW_DOWN = 40;
|
const KEY_ARROW_DOWN = 40;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
spellcheck: {
|
spellcheck: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
required: false
|
required: false
|
||||||
},
|
},
|
||||||
|
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'Start typing...',
|
default: 'Start typing...',
|
||||||
required: false
|
required: false
|
||||||
},
|
},
|
||||||
|
|
||||||
source: {
|
source: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: true
|
required: true
|
||||||
},
|
|
||||||
|
|
||||||
value: {}
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
value () {
|
|
||||||
this.$emit('input', this.value);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
value: "",
|
|
||||||
|
|
||||||
selectionStart: 0,
|
|
||||||
suggestionsOffsetLeft: 0,
|
|
||||||
currentSuggestionIndex: -1,
|
|
||||||
suggestionsVisible: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
updateSuggestions (event) {
|
|
||||||
// Hide suggestions if ESC pressed.
|
|
||||||
if(event.which && event.which === KEY_ESC){
|
|
||||||
event.preventDefault();
|
|
||||||
this.suggestionsVisible = false;
|
|
||||||
this.currentSuggestionIndex = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// As suggestions is a reactive property, this implicitly
|
|
||||||
// causes suggestions to update.
|
|
||||||
this.selectionStart = this.$refs.acInput.selectionStart;
|
|
||||||
this.suggestionsOffsetLeft = (12 * this.selectionStart);
|
|
||||||
this.suggestionsVisible = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
forceSuggestion (text) {
|
|
||||||
let input = this.value.substring(0, this.selectionStart);
|
|
||||||
this.value = input + text;
|
|
||||||
|
|
||||||
this.selectionStart = this.value.length;
|
|
||||||
this.suggestionsVisible = true;
|
|
||||||
this.currentSuggestionIndex = -1;
|
|
||||||
},
|
|
||||||
|
|
||||||
handleKeystroke (event) {
|
|
||||||
if(event.which === KEY_ARROW_UP){
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
this.currentSuggestionIndex = this.currentSuggestionIndex - 1 >= 0
|
|
||||||
? this.currentSuggestionIndex - 1
|
|
||||||
: 0;
|
|
||||||
}else if(event.which === KEY_ARROW_DOWN){
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
this.currentSuggestionIndex = this.currentSuggestionIndex < this.suggestions.length - 1
|
|
||||||
? this.currentSuggestionIndex + 1
|
|
||||||
: this.suggestions.length - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(event.which === KEY_TAB){
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
let activeSuggestion = this.suggestions[this.currentSuggestionIndex >= 0 ? this.currentSuggestionIndex : 0];
|
|
||||||
if(activeSuggestion){
|
|
||||||
let input = this.value.substring(0, this.selectionStart);
|
|
||||||
this.value = input + activeSuggestion;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
/**
|
|
||||||
* Gets the suggestions list to be displayed under the input box.
|
|
||||||
*
|
|
||||||
* @returns {default.props.source|{type, required}}
|
|
||||||
*/
|
|
||||||
suggestions () {
|
|
||||||
let input = this.value.substring(0, this.selectionStart);
|
|
||||||
|
|
||||||
return this.source.filter((entry) => {
|
|
||||||
return entry.toLowerCase().startsWith(input.toLowerCase())
|
|
||||||
&& input.toLowerCase() !== entry.toLowerCase();
|
|
||||||
})
|
|
||||||
// Cut off the part that's already been typed.
|
|
||||||
.map((entry) => entry.substring(this.selectionStart))
|
|
||||||
// We only want the top 3 suggestions.
|
|
||||||
.slice(0, 3);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted () {
|
|
||||||
this.updateSuggestions({
|
|
||||||
target: this.$refs.acInput
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
value() {
|
||||||
|
this.$emit('input', this.value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
value: "application/json",
|
||||||
|
selectionStart: 0,
|
||||||
|
suggestionsOffsetLeft: 0,
|
||||||
|
currentSuggestionIndex: -1,
|
||||||
|
suggestionsVisible: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
updateSuggestions(event) {
|
||||||
|
// Hide suggestions if ESC pressed.
|
||||||
|
if (event.which && event.which === KEY_ESC) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.suggestionsVisible = false;
|
||||||
|
this.currentSuggestionIndex = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// As suggestions is a reactive property, this implicitly
|
||||||
|
// causes suggestions to update.
|
||||||
|
this.selectionStart = this.$refs.acInput.selectionStart;
|
||||||
|
this.suggestionsOffsetLeft = (12 * this.selectionStart);
|
||||||
|
this.suggestionsVisible = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
forceSuggestion(text) {
|
||||||
|
let input = this.value.substring(0, this.selectionStart);
|
||||||
|
this.value = input + text;
|
||||||
|
|
||||||
|
this.selectionStart = this.value.length;
|
||||||
|
this.suggestionsVisible = true;
|
||||||
|
this.currentSuggestionIndex = -1;
|
||||||
|
},
|
||||||
|
|
||||||
|
handleKeystroke(event) {
|
||||||
|
if (event.which === KEY_ARROW_UP) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
this.currentSuggestionIndex = this.currentSuggestionIndex - 1 >= 0 ?
|
||||||
|
this.currentSuggestionIndex - 1 :
|
||||||
|
0;
|
||||||
|
} else if (event.which === KEY_ARROW_DOWN) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
this.currentSuggestionIndex = this.currentSuggestionIndex < this.suggestions.length - 1 ?
|
||||||
|
this.currentSuggestionIndex + 1 :
|
||||||
|
this.suggestions.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.which === KEY_TAB) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
let activeSuggestion = this.suggestions[this.currentSuggestionIndex >= 0 ? this.currentSuggestionIndex : 0];
|
||||||
|
if (activeSuggestion) {
|
||||||
|
let input = this.value.substring(0, this.selectionStart);
|
||||||
|
this.value = input + activeSuggestion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
/**
|
||||||
|
* Gets the suggestions list to be displayed under the input box.
|
||||||
|
*
|
||||||
|
* @returns {default.props.source|{type, required}}
|
||||||
|
*/
|
||||||
|
suggestions() {
|
||||||
|
let input = this.value.substring(0, this.selectionStart);
|
||||||
|
|
||||||
|
return this.source.filter((entry) => {
|
||||||
|
return entry.toLowerCase().startsWith(input.toLowerCase()) &&
|
||||||
|
input.toLowerCase() !== entry.toLowerCase();
|
||||||
|
})
|
||||||
|
// Cut off the part that's already been typed.
|
||||||
|
.map((entry) => entry.substring(this.selectionStart))
|
||||||
|
// We only want the top 3 suggestions.
|
||||||
|
.slice(0, 3);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.updateSuggestions({
|
||||||
|
target: this.$refs.acInput
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li id="filter-history">
|
<li id="filter-history">
|
||||||
<label for="filter-history-input">Search History</label>
|
<label for="filter-history-input">Search History</label>
|
||||||
<input id="filter-history-input" type="text" :disabled="history.length === 0 || isClearingHistory" v-model="filterText">
|
<input id="filter-history-input" type="text" :readonly="history.length === 0 || isClearingHistory" v-model="filterText">
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<virtual-list class="virtual-list" :class="{filled: filteredHistory.length}" :size="89" :remain="Math.min(5, filteredHistory.length)">
|
<virtual-list class="virtual-list" :class="{filled: filteredHistory.length}" :size="89" :remain="Math.min(5, filteredHistory.length)">
|
||||||
@@ -25,18 +25,24 @@
|
|||||||
<label :for="'path#'+index">Path</label>
|
<label :for="'path#'+index">Path</label>
|
||||||
<input :id="'path#'+index" type="text" readonly :value="entry.path">
|
<input :id="'path#'+index" type="text" readonly :value="entry.path">
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<div class="show-on-small-screen">
|
||||||
<label :for="'delete-button#'+index" class="hide-on-small-screen"> </label>
|
<li>
|
||||||
<button :id="'delete-button#'+index" :disabled="isClearingHistory" @click="deleteHistory(entry)">
|
<label :for="'delete-button#'+index" class="hide-on-small-screen"> </label>
|
||||||
Delete
|
<button class="icon" :id="'delete-button#'+index" :disabled="isClearingHistory" @click="deleteHistory(entry)">
|
||||||
</button>
|
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd">
|
||||||
</li>
|
<path d="M5.662 23l-5.369-5.365c-.195-.195-.293-.45-.293-.707 0-.256.098-.512.293-.707l14.929-14.928c.195-.194.451-.293.707-.293.255 0 .512.099.707.293l7.071 7.073c.196.195.293.451.293.708 0 .256-.097.511-.293.707l-11.216 11.219h5.514v2h-12.343zm3.657-2l-5.486-5.486-1.419 1.414 4.076 4.072h2.829zm6.605-17.581l-10.677 10.68 5.658 5.659 10.676-10.682-5.657-5.657z" />
|
||||||
<li>
|
</svg>
|
||||||
<label :for="'use-button#'+index" class="hide-on-small-screen"> </label>
|
</button>
|
||||||
<button :id="'use-button#'+index" :disabled="isClearingHistory" @click="useHistory(entry)">
|
</li>
|
||||||
Use
|
<li>
|
||||||
</button>
|
<label :for="'use-button#'+index" class="hide-on-small-screen"> </label>
|
||||||
</li>
|
<button class="icon" :id="'use-button#'+index" :disabled="isClearingHistory" @click="useHistory(entry)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||||
|
<path d="M14.078 7.061l2.861 2.862-10.799 10.798-3.584.723.724-3.585 10.798-10.798zm0-2.829l-12.64 12.64-1.438 7.128 7.127-1.438 12.642-12.64-5.691-5.69zm7.105 4.277l2.817-2.82-5.691-5.689-2.816 2.817 5.69 5.692z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
</ul>
|
</ul>
|
||||||
</virtual-list>
|
</virtual-list>
|
||||||
<ul :class="{hidden: filteredHistory.length != 0 || history.length === 0 }">
|
<ul :class="{hidden: filteredHistory.length != 0 || history.length === 0 }">
|
||||||
@@ -47,7 +53,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li v-if="!isClearingHistory">
|
<li v-if="!isClearingHistory">
|
||||||
<button id="clear-history-button" :disabled="history.length === 0" @click="enableHistoryClearing">
|
<button id="clear-history-button" :disabled="history.length === 0" @click="enableHistoryClearing">
|
||||||
Clear History
|
Clear all
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li v-else>
|
<li v-else>
|
||||||
@@ -147,7 +153,7 @@
|
|||||||
|
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
.virtual-list.filled {
|
.virtual-list.filled {
|
||||||
min-height: 430px;
|
min-height: 380px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,11 +25,13 @@
|
|||||||
|
|
||||||
div {
|
div {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
label.caption {
|
label.caption {
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
label.toggle {
|
label.toggle {
|
||||||
@@ -46,6 +48,7 @@
|
|||||||
box-sizing: initial;
|
box-sizing: initial;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 10px 5px;
|
margin: 10px 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
.handle {
|
.handle {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -62,8 +65,6 @@
|
|||||||
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transition: $transition;
|
transition: $transition;
|
||||||
|
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.on {
|
&.on {
|
||||||
|
|||||||
@@ -32,11 +32,13 @@
|
|||||||
Install PWA
|
Install PWA
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Bottom section of footer: version/author information -->
|
<!-- Bottom section of footer: version/author information -->
|
||||||
<p class="align-center">
|
<p class="align-center">
|
||||||
<span v-if="version.name">{{ version.name }}
|
<span v-if="version.name">
|
||||||
<span v-if="version.hash">- {{ version.hash }}</span>
|
<a v-bind:href="'https://github.com/liyasthomas/postwoman/releases/tag/' + version.name" target="_blank">{{version.name }}</a>
|
||||||
|
<span v-if="version.hash">
|
||||||
|
- <a v-bind:href="'https://github.com/liyasthomas/postwoman/commit/' + version.hash" target="_blank">{{ version.hash }}</a>
|
||||||
|
</span>
|
||||||
<span v-if="version.variant"> ({{ version.variant }})</span>
|
<span v-if="version.variant"> ({{ version.variant }})</span>
|
||||||
• </span>by <a href="https://liyasthomas.web.app" target="_blank">Liyas Thomas 🦄</a>
|
• </span>by <a href="https://liyasthomas.web.app" target="_blank">Liyas Thomas 🦄</a>
|
||||||
</p>
|
</p>
|
||||||
@@ -158,7 +160,7 @@
|
|||||||
// Apply theme from settings.
|
// Apply theme from settings.
|
||||||
document.documentElement.className = this.$store.state.postwoman.settings.THEME_CLASS || '';
|
document.documentElement.className = this.$store.state.postwoman.settings.THEME_CLASS || '';
|
||||||
// Load theme color data from settings, or use default color.
|
// Load theme color data from settings, or use default color.
|
||||||
let color = this.$store.state.postwoman.settings.THEME_COLOR || '#51FF0D';
|
let color = this.$store.state.postwoman.settings.THEME_COLOR || '#50fa7b';
|
||||||
let vibrant = this.$store.state.postwoman.settings.THEME_COLOR_VIBRANT;
|
let vibrant = this.$store.state.postwoman.settings.THEME_COLOR_VIBRANT;
|
||||||
if (vibrant == null) vibrant = true;
|
if (vibrant == null) vibrant = true;
|
||||||
document.documentElement.style.setProperty('--ac-color', color);
|
document.documentElement.style.setProperty('--ac-color', color);
|
||||||
|
|||||||
250
nuxt.config.js
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
// Some helpful application constants.
|
// Some helpful application constants.
|
||||||
// TODO: Use these when rendering the pages (rather than just for head/meta tags...)
|
// TODO: Use these when rendering the pages (rather than just for head/meta tags...)
|
||||||
export const meta = {
|
export const meta = {
|
||||||
@@ -6,10 +5,8 @@ export const meta = {
|
|||||||
shortDescription: "API request builder",
|
shortDescription: "API request builder",
|
||||||
description: "The Postwoman API request builder helps you create your requests faster, saving you precious time on your development."
|
description: "The Postwoman API request builder helps you create your requests faster, saving you precious time on your development."
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sets the base path for the router.
|
// Sets the base path for the router.
|
||||||
// Important for deploying to GitHub pages.
|
// Important for deploying to GitHub pages.
|
||||||
|
|
||||||
// -- Travis includes the author in the repo slug,
|
// -- Travis includes the author in the repo slug,
|
||||||
// so if there's a /, we need to get everything after it.
|
// so if there's a /, we need to get everything after it.
|
||||||
let repoName = (process.env.TRAVIS_REPO_SLUG || '').split('/').pop();
|
let repoName = (process.env.TRAVIS_REPO_SLUG || '').split('/').pop();
|
||||||
@@ -22,94 +19,195 @@ export const routerBase = process.env.DEPLOY_ENV === 'GH_PAGES' ? {
|
|||||||
base: '/'
|
base: '/'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mode: 'spa',
|
mode: 'spa',
|
||||||
/*
|
/*
|
||||||
** Headers of the page
|
** Headers of the page
|
||||||
*/
|
*/
|
||||||
head: {
|
head: {
|
||||||
title: `${meta.name} \u2022 ${meta.shortDescription}`,
|
title: `${meta.name} \u2022 ${meta.shortDescription}`,
|
||||||
meta: [
|
meta: [
|
||||||
{ charset: 'utf-8' },
|
{
|
||||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1, minimum-scale=1, shrink-to-fit=no, minimal-ui' },
|
charset: 'utf-8'
|
||||||
{ hid: 'description', name: 'description', content: meta.description || '' },
|
},
|
||||||
{ name: 'keywords', content: 'postwoman, api, request, testing, tool, rest, websocket'},
|
{
|
||||||
|
name: 'viewport',
|
||||||
{ name: 'X-UA-Compatible', content: "IE=edge, chrome=1" },
|
content: 'width=device-width, initial-scale=1, minimum-scale=1, shrink-to-fit=no, minimal-ui'
|
||||||
{ itemprop: "name", content: `${meta.name} \u2022 ${meta.shortDescription}` },
|
},
|
||||||
{ itemprop: "description", content: meta.description },
|
{
|
||||||
{ itemprop: "image", content: `${routerBase.router.base}icons/icon-192x192.png` },
|
hid: 'description',
|
||||||
|
name: 'description',
|
||||||
|
content: meta.description || ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'keywords',
|
||||||
|
content: 'postwoman, postwoman chrome, postwoman online, postwoman for mac, postwoman app, postwoman for windows, postwoman google chrome, postwoman chrome app, get postwoman, postwoman web, postwoman android, postwoman app for chrome, postwoman mobile app, postwoman web app, api, request, testing, tool, rest, websocket'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'X-UA-Compatible',
|
||||||
|
content: "IE=edge, chrome=1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itemprop: "name",
|
||||||
|
content: `${meta.name} \u2022 ${meta.shortDescription}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itemprop: "description",
|
||||||
|
content: meta.description
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itemprop: "image",
|
||||||
|
content: `${routerBase.router.base}icons/icon-192x192.png`
|
||||||
|
},
|
||||||
// Add to homescreen for Chrome on Android. Fallback for PWA (handled by nuxt)
|
// Add to homescreen for Chrome on Android. Fallback for PWA (handled by nuxt)
|
||||||
{ name: 'application-name', content: meta.name },
|
{
|
||||||
|
name: 'application-name',
|
||||||
|
content: meta.name
|
||||||
|
},
|
||||||
// Add to homescreen for Safari on iOS
|
// Add to homescreen for Safari on iOS
|
||||||
{ name: 'apple-mobile-web-app-capable', content: 'yes' },
|
{
|
||||||
{ name: 'apple-mobile-web-app-status-bar-style', content: 'black-translucent' },
|
name: 'apple-mobile-web-app-capable',
|
||||||
{ name: 'apple-mobile-web-app-title', content: meta.name },
|
content: 'yes'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'apple-mobile-web-app-status-bar-style',
|
||||||
|
content: 'black-translucent'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'apple-mobile-web-app-title',
|
||||||
|
content: meta.name
|
||||||
|
},
|
||||||
// Windows phone tile icon
|
// Windows phone tile icon
|
||||||
{ name: 'msapplication-TileImage', content: `${routerBase.router.base}icons/icon-144x144.png` },
|
{
|
||||||
{ name: 'msapplication-TileColor', content: '#121212' },
|
name: 'msapplication-TileImage',
|
||||||
{ name: 'msapplication-tap-highlight', content: 'no' },
|
content: `${routerBase.router.base}icons/icon-144x144.png`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'msapplication-TileColor',
|
||||||
|
content: '#282a36'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'msapplication-tap-highlight',
|
||||||
|
content: 'no'
|
||||||
|
},
|
||||||
// OpenGraph
|
// OpenGraph
|
||||||
{ property: 'og:site_name', content: meta.name },
|
{
|
||||||
{ property: 'og:url', content: 'https://liyasthomas.github.io/postwoman' },
|
property: 'og:site_name',
|
||||||
{ property: 'og:type', content: 'website' },
|
content: meta.name
|
||||||
{ property: 'og:title', content: `${meta.name} \u2022 ${meta.shortDescription}` },
|
},
|
||||||
{ property: 'og:description', content: meta.description },
|
{
|
||||||
{ property: 'og:image', content: `${routerBase.router.base}icons/icon-144x144.png` },
|
property: 'og:url',
|
||||||
|
content: 'https://postwoman.io'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: 'og:type',
|
||||||
|
content: 'website'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: 'og:title',
|
||||||
|
content: `${meta.name} \u2022 ${meta.shortDescription}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: 'og:description',
|
||||||
|
content: meta.description
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: 'og:image',
|
||||||
|
content: `${routerBase.router.base}icons/icon-144x144.png`
|
||||||
|
},
|
||||||
// Twitter
|
// Twitter
|
||||||
{ name: 'twitter:card', content: "summary" },
|
{
|
||||||
{ name: 'twitter:site', content: "@liyasthomas" },
|
name: 'twitter:card',
|
||||||
{ name: 'twitter:creator', content: "@liyasthomas" },
|
content: "summary"
|
||||||
{ name: 'twitter:url', content: "https://liyasthomas.github.io/postwoman" },
|
},
|
||||||
{ name: 'twitter:title', content: meta.name },
|
{
|
||||||
{ name: 'twitter:description', content: meta.shortDescription },
|
name: 'twitter:site',
|
||||||
{ name: 'twitter:image', content: `${routerBase.router.base}icons/icon-144x144.png` },
|
content: "@liyasthomas"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'twitter:creator',
|
||||||
|
content: "@liyasthomas"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'twitter:url',
|
||||||
|
content: "https://postwoman.io"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'twitter:title',
|
||||||
|
content: meta.name
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'twitter:description',
|
||||||
|
content: meta.shortDescription
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'twitter:image',
|
||||||
|
content: `${routerBase.router.base}icons/icon-144x144.png`
|
||||||
|
},
|
||||||
],
|
],
|
||||||
link: [
|
link: [
|
||||||
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
|
{
|
||||||
|
rel: 'icon',
|
||||||
|
type: 'image/x-icon',
|
||||||
|
href: `${routerBase.router.base}favicon.ico`
|
||||||
|
},
|
||||||
// Home-screen icons (iOS)
|
// Home-screen icons (iOS)
|
||||||
{ rel: 'apple-touch-icon', href: `${routerBase.router.base}icons/icon-48x48.png` },
|
{
|
||||||
{ rel: 'apple-touch-icon', sizes: '72x72', href: `${routerBase.router.base}icons/icon-72x72.png` },
|
rel: 'apple-touch-icon',
|
||||||
{ rel: 'apple-touch-icon', sizes: '96x96', href: `${routerBase.router.base}icons/icon-96x96.png` },
|
href: `${routerBase.router.base}icons/icon-48x48.png`
|
||||||
{ rel: 'apple-touch-icon', sizes: '144x144', href: `${routerBase.router.base}icons/icon-144x144.png` },
|
},
|
||||||
{ rel: 'apple-touch-icon', sizes: '192x192', href: `${routerBase.router.base}icons/icon-192x192.png` },
|
{
|
||||||
|
rel: 'apple-touch-icon',
|
||||||
|
sizes: '72x72',
|
||||||
|
href: `${routerBase.router.base}icons/icon-72x72.png`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rel: 'apple-touch-icon',
|
||||||
|
sizes: '96x96',
|
||||||
|
href: `${routerBase.router.base}icons/icon-96x96.png`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rel: 'apple-touch-icon',
|
||||||
|
sizes: '144x144',
|
||||||
|
href: `${routerBase.router.base}icons/icon-144x144.png`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rel: 'apple-touch-icon',
|
||||||
|
sizes: '192x192',
|
||||||
|
href: `${routerBase.router.base}icons/icon-192x192.png`
|
||||||
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
/*
|
/*
|
||||||
** Customize the progress-bar color
|
** Customize the progress-bar color
|
||||||
*/
|
*/
|
||||||
loading: { color: 'var(--ac-color)' },
|
loading: {
|
||||||
|
color: 'var(--ac-color)'
|
||||||
|
},
|
||||||
/*
|
/*
|
||||||
** Global CSS
|
** Global CSS
|
||||||
*/
|
*/
|
||||||
css: [
|
css: [
|
||||||
'@/assets/css/themes.scss',
|
'@/assets/css/themes.scss',
|
||||||
'@/assets/css/fonts.scss',
|
'@/assets/css/fonts.scss',
|
||||||
'@/assets/css/styles.scss'
|
'@/assets/css/styles.scss'
|
||||||
],
|
],
|
||||||
/*
|
/*
|
||||||
** Plugins to load before mounting the App
|
** Plugins to load before mounting the App
|
||||||
*/
|
*/
|
||||||
plugins: [
|
plugins: [
|
||||||
{ src: '~/plugins/vuex-persist' }
|
{
|
||||||
|
src: '~/plugins/vuex-persist'
|
||||||
|
}
|
||||||
],
|
],
|
||||||
/*
|
/*
|
||||||
** Nuxt.js dev-modules
|
** Nuxt.js dev-modules
|
||||||
*/
|
*/
|
||||||
buildModules: [
|
buildModules: [
|
||||||
],
|
],
|
||||||
/*
|
/*
|
||||||
** Nuxt.js modules
|
** Nuxt.js modules
|
||||||
*/
|
*/
|
||||||
modules: [
|
modules: [
|
||||||
// See https://goo.gl/OOhYW5
|
// See https://goo.gl/OOhYW5
|
||||||
['@nuxtjs/pwa', {
|
['@nuxtjs/pwa', {
|
||||||
@@ -117,48 +215,40 @@ export default {
|
|||||||
name: meta.name,
|
name: meta.name,
|
||||||
short_name: meta.name,
|
short_name: meta.name,
|
||||||
description: meta.shortDescription,
|
description: meta.shortDescription,
|
||||||
|
|
||||||
display: "standalone",
|
display: "standalone",
|
||||||
theme_color: "#121212",
|
theme_color: "#282a36",
|
||||||
background_color: "#121212",
|
background_color: "#282a36",
|
||||||
|
start_url: `${routerBase.router.base}`,
|
||||||
icons: ((sizes) => {
|
icons: ((sizes) => {
|
||||||
let icons = [];
|
let icons = [];
|
||||||
|
for (let size of sizes) {
|
||||||
for(let size of sizes){
|
|
||||||
icons.push({
|
icons.push({
|
||||||
"src": `${routerBase.router.base}icons/icon-${size}x${size}.png`,
|
"src": `${routerBase.router.base}icons/icon-${size}x${size}.png`,
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"sizes": `${size}x${size}`
|
"sizes": `${size}x${size}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return icons;
|
return icons;
|
||||||
})([48, 72, 96, 144, 192, 512])
|
})([48, 72, 96, 144, 192, 512])
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
|
|
||||||
['@nuxtjs/axios']
|
['@nuxtjs/axios']
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Build configuration
|
** Build configuration
|
||||||
*/
|
*/
|
||||||
build: {
|
build: {
|
||||||
/*
|
/*
|
||||||
** You can extend webpack config here
|
** You can extend webpack config here
|
||||||
*/
|
*/
|
||||||
extend (config, ctx) {
|
extend(config, ctx) {}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Generate configuration
|
** Generate configuration
|
||||||
*/
|
*/
|
||||||
generate: {
|
generate: {
|
||||||
fallback: true
|
fallback: true
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Router configuration
|
** Router configuration
|
||||||
*/
|
*/
|
||||||
|
|||||||
224
pages/index.vue
@@ -37,6 +37,27 @@
|
|||||||
<label for="path">Path</label>
|
<label for="path">Path</label>
|
||||||
<input @keyup.enter="isValidURL ? sendRequest() : null" id="path" v-model="path">
|
<input @keyup.enter="isValidURL ? sendRequest() : null" id="path" v-model="path">
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<label class="hide-on-small-screen" for="copyRequest"> </label>
|
||||||
|
<button class="icon" @click="copyRequest" id="copyRequest" ref="copyRequest" :disabled="!isValidURL">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
|
||||||
|
<path d="M22 6v16h-16v-16h16zm2-2h-20v20h20v-20zm-24 17v-21h21v2h-19v19h-2z" />
|
||||||
|
</svg>
|
||||||
|
<span>Share URL</span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<label class="hide-on-small-screen" for="code"> </label>
|
||||||
|
<button class="icon" id="code" name="code" v-on:click="isHidden = !isHidden" :disabled="!isValidURL">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" v-if="isHidden">
|
||||||
|
<path d="M12.015 7c4.751 0 8.063 3.012 9.504 4.636-1.401 1.837-4.713 5.364-9.504 5.364-4.42 0-7.93-3.536-9.478-5.407 1.493-1.647 4.817-4.593 9.478-4.593zm0-2c-7.569 0-12.015 6.551-12.015 6.551s4.835 7.449 12.015 7.449c7.733 0 11.985-7.449 11.985-7.449s-4.291-6.551-11.985-6.551zm-.015 5c1.103 0 2 .897 2 2s-.897 2-2 2-2-.897-2-2 .897-2 2-2zm0-2c-2.209 0-4 1.792-4 4 0 2.209 1.791 4 4 4s4-1.791 4-4c0-2.208-1.791-4-4-4z" />
|
||||||
|
</svg>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" v-if="!isHidden">
|
||||||
|
<path d="M19.604 2.562l-3.346 3.137c-1.27-.428-2.686-.699-4.243-.699-7.569 0-12.015 6.551-12.015 6.551s1.928 2.951 5.146 5.138l-2.911 2.909 1.414 1.414 17.37-17.035-1.415-1.415zm-6.016 5.779c-3.288-1.453-6.681 1.908-5.265 5.206l-1.726 1.707c-1.814-1.16-3.225-2.65-4.06-3.66 1.493-1.648 4.817-4.594 9.478-4.594.927 0 1.796.119 2.61.315l-1.037 1.026zm-2.883 7.431l5.09-4.993c1.017 3.111-2.003 6.067-5.09 4.993zm13.295-4.221s-4.252 7.449-11.985 7.449c-1.379 0-2.662-.291-3.851-.737l1.614-1.583c.715.193 1.458.32 2.237.32 4.791 0 8.104-3.527 9.504-5.364-.729-.822-1.956-1.99-3.587-2.952l1.489-1.46c2.982 1.9 4.579 4.327 4.579 4.327z" />
|
||||||
|
</svg>
|
||||||
|
<span>{{ isHidden ? 'Show Code' : 'Hide Code' }}</span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label class="hide-on-small-screen" for="action"> </label>
|
<label class="hide-on-small-screen" for="action"> </label>
|
||||||
<button :disabled="!isValidURL" @click="sendRequest" class="show" id="action" name="action" ref="sendButton">
|
<button :disabled="!isValidURL" @click="sendRequest" class="show" id="action" name="action" ref="sendButton">
|
||||||
@@ -45,7 +66,35 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</pw-section>
|
</pw-section>
|
||||||
<pw-section class="blue-dark" label="Request Body" v-if="method === 'POST' || method === 'PUT' || method === 'PATCH'">
|
<pw-section class="blue" label="Request Code" ref="requestCode" v-if="!isHidden">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<label for="requestType">Request Type</label>
|
||||||
|
<select name="requestType" v-model="requestType">
|
||||||
|
<option>JavaScript XHR</option>
|
||||||
|
<option>Fetch</option>
|
||||||
|
<option>cURL</option>
|
||||||
|
</select>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<div class="flex-wrap">
|
||||||
|
<label for="generatedCode">Generated Code</label>
|
||||||
|
<div>
|
||||||
|
<button class="icon" @click="copyRequestCode" name="copyRequestCode" ref="copyRequestCode">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
|
||||||
|
<path d="M22 6v16h-16v-16h16zm2-2h-20v20h20v-20zm-24 17v-21h21v2h-19v19h-2z" />
|
||||||
|
</svg>
|
||||||
|
<span>Copy</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<textarea ref="generatedCode" name="generatedCode" style="font-family: monospace;" rows="16">{{requestCode}}</textarea>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</pw-section>
|
||||||
|
<pw-section class="blue" label="Request Body" v-if="method === 'POST' || method === 'PUT' || method === 'PATCH'">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<autocomplete :source="validContentTypes" :spellcheck="false" v-model="contentType">Content Type
|
<autocomplete :source="validContentTypes" :spellcheck="false" v-model="contentType">Content Type
|
||||||
@@ -61,11 +110,11 @@
|
|||||||
<ol v-for="(param, index) in bodyParams">
|
<ol v-for="(param, index) in bodyParams">
|
||||||
<li>
|
<li>
|
||||||
<label :for="'bparam'+index">Key {{index + 1}}</label>
|
<label :for="'bparam'+index">Key {{index + 1}}</label>
|
||||||
<input :name="'bparam'+index" v-model="param.key">
|
<input :name="'bparam'+index" v-model="param.key" @keyup.prevent="setRouteQueryState">
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label :for="'bvalue'+index">Value {{index + 1}}</label>
|
<label :for="'bvalue'+index">Value {{index + 1}}</label>
|
||||||
<input :name="'bvalue'+index" v-model="param.value">
|
<input :name="'bvalue'+index" v-model="param.value" @keyup.prevent="setRouteQueryState">
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label class="hide-on-small-screen" for="request"> </label>
|
<label class="hide-on-small-screen" for="request"> </label>
|
||||||
@@ -107,16 +156,28 @@
|
|||||||
<div class="flex-wrap">
|
<div class="flex-wrap">
|
||||||
<label for="body">response</label>
|
<label for="body">response</label>
|
||||||
<div>
|
<div>
|
||||||
<button class="block" @click="copyRequest" name="copyRequest" v-if="isValidURL">Copy Request URL</button>
|
<button class="icon" @click="copyResponse" name="copyResponse" ref="copyResponse" v-if="response.body">
|
||||||
<button @click="copyResponse" name="copyResponse" v-if="response.body">Copy Response</button>
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
|
||||||
|
<path d="M22 6v16h-16v-16h16zm2-2h-20v20h20v-20zm-24 17v-21h21v2h-19v19h-2z" />
|
||||||
|
</svg>
|
||||||
|
<span>Copy</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="response-details-wrapper">
|
<div id="response-details-wrapper">
|
||||||
<textarea id="response-details" name="body" readonly rows="16">{{response.body || '(waiting to send request)'}}</textarea>
|
<textarea ref="responseBody" name="body" readonly rows="16">{{response.body || '(waiting to send request)'}}</textarea>
|
||||||
<iframe :class="{hidden: !previewEnabled}" class="covers-response" ref="previewFrame" src="about:blank"></iframe>
|
<iframe :class="{hidden: !previewEnabled}" class="covers-response" ref="previewFrame" src="about:blank"></iframe>
|
||||||
</div>
|
</div>
|
||||||
<div class="align-right" v-if="response.body && responseType === 'text/html'">
|
<div class="align-right" v-if="response.body && responseType === 'text/html'">
|
||||||
<button @click.prevent="togglePreview">{{ previewEnabled ? 'Hide Preview' : 'Preview HTML' }}</button>
|
<button class="icon" @click.prevent="togglePreview">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" v-if="!previewEnabled">
|
||||||
|
<path d="M12.015 7c4.751 0 8.063 3.012 9.504 4.636-1.401 1.837-4.713 5.364-9.504 5.364-4.42 0-7.93-3.536-9.478-5.407 1.493-1.647 4.817-4.593 9.478-4.593zm0-2c-7.569 0-12.015 6.551-12.015 6.551s4.835 7.449 12.015 7.449c7.733 0 11.985-7.449 11.985-7.449s-4.291-6.551-11.985-6.551zm-.015 5c1.103 0 2 .897 2 2s-.897 2-2 2-2-.897-2-2 .897-2 2-2zm0-2c-2.209 0-4 1.792-4 4 0 2.209 1.791 4 4 4s4-1.791 4-4c0-2.208-1.791-4-4-4z" />
|
||||||
|
</svg>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" v-if="previewEnabled">
|
||||||
|
<path d="M19.604 2.562l-3.346 3.137c-1.27-.428-2.686-.699-4.243-.699-7.569 0-12.015 6.551-12.015 6.551s1.928 2.951 5.146 5.138l-2.911 2.909 1.414 1.414 17.37-17.035-1.415-1.415zm-6.016 5.779c-3.288-1.453-6.681 1.908-5.265 5.206l-1.726 1.707c-1.814-1.16-3.225-2.65-4.06-3.66 1.493-1.648 4.817-4.594 9.478-4.594.927 0 1.796.119 2.61.315l-1.037 1.026zm-2.883 7.431l5.09-4.993c1.017 3.111-2.003 6.067-5.09 4.993zm13.295-4.221s-4.252 7.449-11.985 7.449c-1.379 0-2.662-.291-3.851-.737l1.614-1.583c.715.193 1.458.32 2.237.32 4.791 0 8.104-3.527 9.504-5.364-.729-.822-1.956-1.99-3.587-2.952l1.489-1.46c2.982 1.9 4.579 4.327 4.579 4.327z" />
|
||||||
|
</svg>
|
||||||
|
<span>{{ previewEnabled ? 'Hide Preview' : 'Preview HTML' }}</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -153,11 +214,11 @@
|
|||||||
<ol v-for="(header, index) in headers">
|
<ol v-for="(header, index) in headers">
|
||||||
<li>
|
<li>
|
||||||
<label :for="'header'+index">Key {{index + 1}}</label>
|
<label :for="'header'+index">Key {{index + 1}}</label>
|
||||||
<input :name="'header'+index" v-model="header.key">
|
<input :name="'header'+index" v-model="header.key" @keyup.prevent="setRouteQueryState">
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label :for="'value'+index">Value {{index + 1}}</label>
|
<label :for="'value'+index">Value {{index + 1}}</label>
|
||||||
<input :name="'value'+index" v-model="header.value">
|
<input :name="'value'+index" v-model="header.value" @keyup.prevent="setRouteQueryState">
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label class="hide-on-small-screen" for="header"> </label>
|
<label class="hide-on-small-screen" for="header"> </label>
|
||||||
@@ -177,7 +238,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</pw-section>
|
</pw-section>
|
||||||
<pw-section class="cyan" collapsed label="Parameters">
|
<pw-section class="pink" collapsed label="Parameters">
|
||||||
<ol v-for="(param, index) in params">
|
<ol v-for="(param, index) in params">
|
||||||
<li>
|
<li>
|
||||||
<label :for="'param'+index">Key {{index + 1}}</label>
|
<label :for="'param'+index">Key {{index + 1}}</label>
|
||||||
@@ -278,6 +339,8 @@
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showModal: false,
|
showModal: false,
|
||||||
|
copyButton: '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M22 6v16h-16v-16h16zm2-2h-20v20h20v-20zm-24 17v-21h21v2h-19v19h-2z" /></svg>',
|
||||||
|
copiedButton: '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M22 2v20h-20v-20h20zm2-2h-24v24h24v-24zm-5.541 8.409l-1.422-1.409-7.021 7.183-3.08-2.937-1.395 1.435 4.5 4.319 8.418-8.591z"/></svg>',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: 'https://reqres.in',
|
url: 'https://reqres.in',
|
||||||
auth: 'None',
|
auth: 'None',
|
||||||
@@ -291,6 +354,8 @@
|
|||||||
rawParams: '',
|
rawParams: '',
|
||||||
rawInput: false,
|
rawInput: false,
|
||||||
contentType: 'application/json',
|
contentType: 'application/json',
|
||||||
|
requestType: 'JavaScript XHR',
|
||||||
|
isHidden: true,
|
||||||
response: {
|
response: {
|
||||||
status: '',
|
status: '',
|
||||||
headers: '',
|
headers: '',
|
||||||
@@ -323,6 +388,10 @@
|
|||||||
watch: {
|
watch: {
|
||||||
contentType(val) {
|
contentType(val) {
|
||||||
this.rawInput = !this.knownContentTypes.includes(val);
|
this.rawInput = !this.knownContentTypes.includes(val);
|
||||||
|
},
|
||||||
|
rawInput (status) {
|
||||||
|
if (status && this.rawParams === '') this.rawParams = '{}'
|
||||||
|
else this.setRouteQueryState()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -386,6 +455,89 @@
|
|||||||
},
|
},
|
||||||
responseType() {
|
responseType() {
|
||||||
return (this.response.headers['content-type'] || '').split(';')[0].toLowerCase();
|
return (this.response.headers['content-type'] || '').split(';')[0].toLowerCase();
|
||||||
|
},
|
||||||
|
requestCode() {
|
||||||
|
if (this.requestType == 'JavaScript XHR') {
|
||||||
|
var requestString = []
|
||||||
|
requestString.push('const xhr = new XMLHttpRequest()');
|
||||||
|
const user = this.auth === 'Basic' ? this.httpUser : null
|
||||||
|
const pswd = this.auth === 'Basic' ? this.httpPassword : null
|
||||||
|
requestString.push('xhr.open(' + this.method + ', ' + this.url + this.path + this.queryString + ', true, ' + user + ', ' + pswd + ')');
|
||||||
|
if (this.auth === 'Bearer Token') {
|
||||||
|
requestString.push("xhr.setRequestHeader('Authorization', 'Bearer ' + " + this.bearerToken + ")");
|
||||||
|
}
|
||||||
|
if (this.headers) {
|
||||||
|
this.headers.forEach(function(element) {
|
||||||
|
requestString.push('xhr.setRequestHeader(' + element.key + ', ' + element.value + ')');
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (this.method === 'POST' || this.method === 'PUT') {
|
||||||
|
const requestBody = this.rawInput ? this.rawParams : this.rawRequestBody;
|
||||||
|
requestString.push("xhr.setRequestHeader('Content-Length', " + requestBody.length + ")")
|
||||||
|
requestString.push("xhr.setRequestHeader('Content-Type', `" + this.contentType + "; charset=utf-8`)")
|
||||||
|
requestString.push("xhr.send(" + requestBody + ")")
|
||||||
|
} else {
|
||||||
|
requestString.push('xhr.send()')
|
||||||
|
}
|
||||||
|
return requestString.join('\n');
|
||||||
|
} else if (this.requestType == 'Fetch') {
|
||||||
|
var requestString = [];
|
||||||
|
var headers = [];
|
||||||
|
requestString.push('fetch(' + this.url + this.path + this.queryString + ', {\n')
|
||||||
|
requestString.push(' method: "' + this.method + '",\n')
|
||||||
|
if (this.auth === 'Basic') {
|
||||||
|
var basic = this.httpUser + ':' + this.httpPassword;
|
||||||
|
headers.push(' "Authorization": "Basic ' + window.btoa(unescape(encodeURIComponent(basic))) + ',\n')
|
||||||
|
} else if (this.auth === 'Bearer Token') {
|
||||||
|
headers.push(' "Authorization": "Bearer Token ' + this.bearerToken + ',\n')
|
||||||
|
}
|
||||||
|
if (this.method === 'POST' || this.method === 'PUT') {
|
||||||
|
const requestBody = this.rawInput ? this.rawParams : this.rawRequestBody;
|
||||||
|
requestString.push(' body: ' + requestBody + ',\n')
|
||||||
|
headers.push(' "Content-Length": ' + requestBody.length + ',\n')
|
||||||
|
headers.push(' "Content-Type": "' + this.contentType + '; charset=utf-8",\n')
|
||||||
|
}
|
||||||
|
if (this.headers) {
|
||||||
|
this.headers.forEach(function(element) {
|
||||||
|
headers.push(' "' + element.key + '": "' + element.value + '",\n');
|
||||||
|
})
|
||||||
|
}
|
||||||
|
headers = headers.join('').slice(0, -3);
|
||||||
|
requestString.push(' headers: {\n' + headers + '\n },\n')
|
||||||
|
requestString.push(' credentials: "same-origin"\n')
|
||||||
|
requestString.push(')}).then(function(response) {\n')
|
||||||
|
requestString.push(' response.status\n')
|
||||||
|
requestString.push(' response.statusText\n')
|
||||||
|
requestString.push(' response.headers\n')
|
||||||
|
requestString.push(' response.url\n\n')
|
||||||
|
requestString.push(' return response.text()\n')
|
||||||
|
requestString.push(')}, function(error) {\n')
|
||||||
|
requestString.push(' error.message\n')
|
||||||
|
requestString.push(')}')
|
||||||
|
return requestString.join('');
|
||||||
|
} else if (this.requestType == 'cURL') {
|
||||||
|
var requestString = [];
|
||||||
|
requestString.push('curl -X ' + this.method + ' \\\n')
|
||||||
|
requestString.push(" '" + this.url + this.path + this.queryString + "' \\\n")
|
||||||
|
if (this.auth === 'Basic') {
|
||||||
|
var basic = this.httpUser + ':' + this.httpPassword;
|
||||||
|
requestString.push(" -H 'Authorization: Basic " + window.btoa(unescape(encodeURIComponent(basic))) + "' \\\n")
|
||||||
|
} else if (this.auth === 'Bearer Token') {
|
||||||
|
requestString.push(" -H 'Authorization: Bearer Token " + this.bearerToken + "' \\\n")
|
||||||
|
}
|
||||||
|
if (this.headers) {
|
||||||
|
this.headers.forEach(function(element) {
|
||||||
|
requestString.push(" -H '" + element.key + ": " + element.value + "' \\\n");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (this.method === 'POST' || this.method === 'PUT') {
|
||||||
|
const requestBody = this.rawInput ? this.rawParams : this.rawRequestBody;
|
||||||
|
requestString.push(" -H 'Content-Length: " + requestBody.length + "' \\\n")
|
||||||
|
requestString.push(" -H 'Content-Type: " + this.contentType + "; charset=utf-8' \\\n")
|
||||||
|
requestString.push(" -d '" + requestBody + "' \\\n")
|
||||||
|
}
|
||||||
|
return requestString.join('').slice(0, -4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -561,17 +713,38 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
copyRequest() {
|
copyRequest() {
|
||||||
var dummy = document.createElement('input');
|
if (navigator.share) {
|
||||||
document.body.appendChild(dummy);
|
let time = new Date().toLocaleTimeString();
|
||||||
dummy.value = window.location.href;
|
let date = new Date().toLocaleDateString();
|
||||||
dummy.select();
|
navigator.share({
|
||||||
document.execCommand('copy');
|
text: `Postwoman • API request builder at ${time} on ${date}`,
|
||||||
document.body.removeChild(dummy);
|
url: window.location.href
|
||||||
|
}).then(() => {
|
||||||
|
// console.log('Thanks for sharing!');
|
||||||
|
})
|
||||||
|
.catch(console.error);
|
||||||
|
} else {
|
||||||
|
this.$refs.copyRequest.innerHTML = this.copiedButton + '<span>Copied</span>';
|
||||||
|
var dummy = document.createElement('input');
|
||||||
|
document.body.appendChild(dummy);
|
||||||
|
dummy.value = window.location.href;
|
||||||
|
dummy.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
document.body.removeChild(dummy);
|
||||||
|
setTimeout(() => this.$refs.copyRequest.innerHTML = this.copyButton + '<span>Share URL</span>', 1500)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
copyRequestCode() {
|
||||||
|
this.$refs.copyRequestCode.innerHTML = this.copiedButton + '<span>Copied</span>';
|
||||||
|
this.$refs.generatedCode.select();
|
||||||
|
document.execCommand("copy");
|
||||||
|
setTimeout(() => this.$refs.copyRequestCode.innerHTML = this.copyButton + '<span>Copy</span>', 1500)
|
||||||
},
|
},
|
||||||
copyResponse() {
|
copyResponse() {
|
||||||
var copyText = document.getElementById("response-details");
|
this.$refs.copyResponse.innerHTML = this.copiedButton + '<span>Copied</span>';
|
||||||
copyText.select();
|
this.$refs.responseBody.select();
|
||||||
document.execCommand("copy");
|
document.execCommand("copy");
|
||||||
|
setTimeout(() => this.$refs.copyResponse.innerHTML = this.copyButton + '<span>Copy</span>', 1500)
|
||||||
},
|
},
|
||||||
togglePreview() {
|
togglePreview() {
|
||||||
this.previewEnabled = !this.previewEnabled;
|
this.previewEnabled = !this.previewEnabled;
|
||||||
@@ -601,14 +774,19 @@
|
|||||||
} else return ''
|
} else return ''
|
||||||
}
|
}
|
||||||
let flats = ['method', 'url', 'path', 'auth', 'httpUser', 'httpPassword', 'bearerToken', 'contentType'].map(item => flat(item))
|
let flats = ['method', 'url', 'path', 'auth', 'httpUser', 'httpPassword', 'bearerToken', 'contentType'].map(item => flat(item))
|
||||||
let deeps = ['headers', 'params', 'bodyParams'].map(item => deep(item))
|
let deeps = ['headers', 'params'].map(item => deep(item))
|
||||||
this.$router.replace('/?' + flats.concat(deeps).join('').slice(0, -1))
|
let bodyParams = this.rawInput ? [flat('rawParams')] : [deep('bodyParams')];
|
||||||
|
|
||||||
|
this.$router.replace('/?' + flats.concat(deeps, bodyParams).join('').slice(0, -1))
|
||||||
},
|
},
|
||||||
setRouteQueries(queries) {
|
setRouteQueries(queries) {
|
||||||
if (typeof(queries) !== 'object') throw new Error('Route query parameters must be a Object')
|
if (typeof(queries) !== 'object') throw new Error('Route query parameters must be a Object')
|
||||||
for (const key in queries) {
|
for (const key in queries) {
|
||||||
if (key === 'headers' || key === 'params' || key === 'bodyParams') this[key] = JSON.parse(queries[key])
|
if (key === 'headers' || key === 'params' || key === 'bodyParams') this[key] = JSON.parse(queries[key])
|
||||||
else if (typeof(this[key]) === 'string') this[key] = queries[key];
|
if (key === 'rawParams') {
|
||||||
|
this.rawInput = true
|
||||||
|
this.rawParams = queries['rawParams']
|
||||||
|
} else if (typeof(this[key]) === 'string') this[key] = queries[key]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
observeRequestButton() {
|
observeRequestButton() {
|
||||||
@@ -665,11 +843,11 @@
|
|||||||
vm.headers,
|
vm.headers,
|
||||||
vm.params,
|
vm.params,
|
||||||
vm.bodyParams,
|
vm.bodyParams,
|
||||||
vm.contentType
|
vm.contentType,
|
||||||
|
vm.rawParams
|
||||||
], val => {
|
], val => {
|
||||||
this.setRouteQueryState()
|
this.setRouteQueryState()
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +1,39 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<pw-section class="blue" label="Theme">
|
<pw-section class="cyan" label="Theme">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<h3 class="title">Background</h3>
|
<h3 class="title">Background</h3>
|
||||||
<div class="backgrounds">
|
<div class="backgrounds">
|
||||||
<span :key="theme.class" @click="applyTheme(theme.class)" v-for="theme in themes">
|
<span :key="theme.class" @click="applyTheme(theme.class)" v-for="theme in themes">
|
||||||
<swatch :active="settings.THEME_CLASS === theme.class" :class="{ vibrant: theme.vibrant }" :color="theme.color" :name="theme.name"></swatch>
|
<swatch :active="settings.THEME_CLASS === theme.class" :class="{ vibrant: theme.vibrant }" :color="theme.color" :name="theme.name"></swatch>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<h3 class="title">Color</h3>
|
<h3 class="title">Color</h3>
|
||||||
<div class="colors">
|
<div class="colors">
|
||||||
<span :key="entry.color" @click.prevent="setActiveColor(entry.color, entry.vibrant)" v-for="entry in colors">
|
<span :key="entry.color" @click.prevent="setActiveColor(entry.color, entry.vibrant)" v-for="entry in colors">
|
||||||
<swatch :active="settings.THEME_COLOR === entry.color.toUpperCase()" :class="{ vibrant: entry.vibrant }" :color="entry.color" :name="entry.name" />
|
<swatch :active="settings.THEME_COLOR === entry.color.toUpperCase()" :class="{ vibrant: entry.vibrant }" :color="entry.color" :name="entry.name" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<h3 class="title">Frames</h3>
|
<h3 class="title">Frames</h3>
|
||||||
<pw-toggle :on="!settings.DISABLE_FRAME_COLORS" @change="toggleSetting('DISABLE_FRAME_COLORS')">
|
<span>
|
||||||
Multi-color {{ settings.DISABLE_FRAME_COLORS ? "disabled" : "enabled" }}
|
<pw-toggle :on="!settings.DISABLE_FRAME_COLORS" @change="toggleSetting('DISABLE_FRAME_COLORS')">
|
||||||
</pw-toggle>
|
Multi-color {{ settings.DISABLE_FRAME_COLORS ? "disabled" : "enabled" }}
|
||||||
</li>
|
</pw-toggle>
|
||||||
</ul>
|
</span>
|
||||||
</pw-section>
|
</li>
|
||||||
|
</ul>
|
||||||
|
</pw-section>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
PROXY SETTINGS
|
PROXY SETTINGS
|
||||||
--------------
|
--------------
|
||||||
This feature is currently not finished.
|
This feature is currently not finished.
|
||||||
@@ -57,141 +59,151 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</pw-section>
|
</pw-section>
|
||||||
-->
|
-->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import section from "../components/section";
|
import section from "../components/section";
|
||||||
import swatch from "../components/settings/swatch";
|
import swatch from "../components/settings/swatch";
|
||||||
import toggle from "../components/toggle";
|
import toggle from "../components/toggle";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
'pw-section': section,
|
'pw-section': section,
|
||||||
'pw-toggle': toggle,
|
'pw-toggle': toggle,
|
||||||
'swatch': swatch
|
'swatch': swatch
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// NOTE:: You need to first set the CSS for your theme in /assets/css/themes.scss
|
// NOTE:: You need to first set the CSS for your theme in /assets/css/themes.scss
|
||||||
// You should copy the existing light theme as a template and then just
|
// You should copy the existing light theme as a template and then just
|
||||||
// set the relevant values.
|
// set the relevant values.
|
||||||
themes: [{
|
themes: [{
|
||||||
"color": "#121212",
|
"color": "#282a36",
|
||||||
"name": "Dark (Default)",
|
"name": "Dark (Default)",
|
||||||
"class": ""
|
"class": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"color": "#DFDFDF",
|
"color": "#ebeef5",
|
||||||
"name": "Light",
|
"name": "Light",
|
||||||
"vibrant": true,
|
"vibrant": true,
|
||||||
"class": "light"
|
"class": "light"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
// You can define a new color here! It will simply store the color value.
|
// You can define a new color here! It will simply store the color value.
|
||||||
colors: [
|
colors: [
|
||||||
// If the color is vibrant, black is used as the active foreground color.
|
// If the color is vibrant, black is used as the active foreground color.
|
||||||
{
|
{
|
||||||
"color": "#51ff0d",
|
"color": "#50fa7b",
|
||||||
"name": "Lime (Default)",
|
"name": "Green (Default)",
|
||||||
"vibrant": true
|
"vibrant": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"color": "#FFC107",
|
"color": "#f1fa8c",
|
||||||
"name": "Yellow",
|
"name": "Yellow",
|
||||||
"vibrant": true
|
"vibrant": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"color": "#E91E63",
|
"color": "#ff79c6",
|
||||||
"name": "Pink",
|
"name": "Pink",
|
||||||
"vibrant": false
|
"vibrant": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"color": "#e74c3c",
|
"color": "#ff5555",
|
||||||
"name": "Red",
|
"name": "Red",
|
||||||
"vibrant": false
|
"vibrant": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"color": "#9b59b6",
|
"color": "#bd93f9",
|
||||||
"name": "Purple",
|
"name": "Purple",
|
||||||
"vibrant": false
|
"vibrant": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"color": "#2980b9",
|
"color": "#ffb86c",
|
||||||
"name": "Blue",
|
"name": "Orange",
|
||||||
"vibrant": false
|
"vibrant": true
|
||||||
},
|
},
|
||||||
],
|
{
|
||||||
|
"color": "#8be9fd",
|
||||||
|
"name": "Cyan",
|
||||||
|
"vibrant": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "#57b5f9",
|
||||||
|
"name": "Blue",
|
||||||
|
"vibrant": false
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
settings: {
|
settings: {
|
||||||
THEME_CLASS: this.$store.state.postwoman.settings.THEME_CLASS || '',
|
THEME_CLASS: this.$store.state.postwoman.settings.THEME_CLASS || '',
|
||||||
THEME_COLOR: '',
|
THEME_COLOR: '',
|
||||||
THEME_COLOR_VIBRANT: true,
|
THEME_COLOR_VIBRANT: true,
|
||||||
|
|
||||||
DISABLE_FRAME_COLORS: this.$store.state.postwoman.settings.DISABLE_FRAME_COLORS || false,
|
DISABLE_FRAME_COLORS: this.$store.state.postwoman.settings.DISABLE_FRAME_COLORS || false,
|
||||||
PROXY_ENABLED: this.$store.state.postwoman.settings.PROXY_ENABLED || false,
|
PROXY_ENABLED: this.$store.state.postwoman.settings.PROXY_ENABLED || false,
|
||||||
PROXY_URL: this.$store.state.postwoman.settings.PROXY_URL || '',
|
PROXY_URL: this.$store.state.postwoman.settings.PROXY_URL || '',
|
||||||
PROXY_KEY: this.$store.state.postwoman.settings.PROXY_KEY || ''
|
PROXY_KEY: this.$store.state.postwoman.settings.PROXY_KEY || ''
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
proxySettings: {
|
|
||||||
deep: true,
|
|
||||||
handler (value) {
|
|
||||||
this.applySetting('PROXY_URL', value.url);
|
|
||||||
this.applySetting('PROXY_KEY', value.key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
applyTheme(name) {
|
|
||||||
this.applySetting('THEME_CLASS', name);
|
|
||||||
document.documentElement.className = name;
|
|
||||||
let imgGitHub = document.getElementById("imgGitHub");
|
|
||||||
imgGitHub.style['filter'] = "";
|
|
||||||
imgGitHub.style['webkit-filter'] = "invert(100%)";
|
|
||||||
if (name.includes("light")){
|
|
||||||
imgGitHub.style['filter'] = "invert(100%)";
|
|
||||||
imgGitHub.style['webkit-filter'] = "invert(100%)";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setActiveColor(color, vibrant) {
|
|
||||||
// By default, the color is vibrant.
|
|
||||||
if (vibrant == null) vibrant = true;
|
|
||||||
document.documentElement.style.setProperty('--ac-color', color);
|
|
||||||
document.documentElement.style.setProperty('--act-color', vibrant ? '#121212' : '#fff');
|
|
||||||
this.applySetting('THEME_COLOR', color.toUpperCase());
|
|
||||||
this.applySetting('THEME_COLOR_VIBRANT', vibrant);
|
|
||||||
},
|
|
||||||
getActiveColor() {
|
|
||||||
// This strips extra spaces and # signs from the strings.
|
|
||||||
const strip = (str) => str.replace(/#/g, '').replace(/ /g, '');
|
|
||||||
return `#${strip(window.getComputedStyle(document.documentElement).getPropertyValue('--ac-color')).toUpperCase()}`;
|
|
||||||
},
|
|
||||||
applySetting(key, value) {
|
|
||||||
this.settings[key] = value;
|
|
||||||
this.$store.commit('postwoman/applySetting', [key, value]);
|
|
||||||
},
|
|
||||||
toggleSetting(key) {
|
|
||||||
this.settings[key] = !this.settings[key];
|
|
||||||
this.$store.commit('postwoman/applySetting', [key, this.settings[key]]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeMount() {
|
|
||||||
this.settings.THEME_COLOR = this.getActiveColor();
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
proxySettings () {
|
|
||||||
return {
|
|
||||||
url: this.settings.PROXY_URL,
|
|
||||||
key: this.settings.PROXY_KEY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
proxySettings: {
|
||||||
|
deep: true,
|
||||||
|
handler(value) {
|
||||||
|
this.applySetting('PROXY_URL', value.url);
|
||||||
|
this.applySetting('PROXY_KEY', value.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
applyTheme(name) {
|
||||||
|
this.applySetting('THEME_CLASS', name);
|
||||||
|
document.documentElement.className = name;
|
||||||
|
let imgGitHub = document.getElementById("imgGitHub");
|
||||||
|
imgGitHub.style['filter'] = "";
|
||||||
|
imgGitHub.style['webkit-filter'] = "invert(100%)";
|
||||||
|
if (name.includes("light")) {
|
||||||
|
imgGitHub.style['filter'] = "invert(100%)";
|
||||||
|
imgGitHub.style['webkit-filter'] = "invert(100%)";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setActiveColor(color, vibrant) {
|
||||||
|
// By default, the color is vibrant.
|
||||||
|
if (vibrant == null) vibrant = true;
|
||||||
|
document.documentElement.style.setProperty('--ac-color', color);
|
||||||
|
document.documentElement.style.setProperty('--act-color', vibrant ? '#282a36' : '#f8f8f2');
|
||||||
|
this.applySetting('THEME_COLOR', color.toUpperCase());
|
||||||
|
this.applySetting('THEME_COLOR_VIBRANT', vibrant);
|
||||||
|
},
|
||||||
|
getActiveColor() {
|
||||||
|
// This strips extra spaces and # signs from the strings.
|
||||||
|
const strip = (str) => str.replace(/#/g, '').replace(/ /g, '');
|
||||||
|
return `#${strip(window.getComputedStyle(document.documentElement).getPropertyValue('--ac-color')).toUpperCase()}`;
|
||||||
|
},
|
||||||
|
applySetting(key, value) {
|
||||||
|
this.settings[key] = value;
|
||||||
|
this.$store.commit('postwoman/applySetting', [key, value]);
|
||||||
|
},
|
||||||
|
toggleSetting(key) {
|
||||||
|
this.settings[key] = !this.settings[key];
|
||||||
|
this.$store.commit('postwoman/applySetting', [key, this.settings[key]]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeMount() {
|
||||||
|
this.settings.THEME_COLOR = this.getActiveColor();
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
proxySettings() {
|
||||||
|
return {
|
||||||
|
url: this.settings.PROXY_URL,
|
||||||
|
key: this.settings.PROXY_KEY
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<pw-section class="blue" label="Request" ref="request">
|
<pw-section class="cyan" label="Request" ref="request">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<label for="url">URL</label>
|
<label for="url">URL</label>
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<label for="message">Message</label>
|
<label for="message">Message</label>
|
||||||
<input id="message" name="message" type="text" v-model="communication.input" :disabled="!connectionState" @keyup.enter="connectionState ? sendMessage() : null">
|
<input id="message" name="message" type="text" v-model="communication.input" :readonly="!connectionState" @keyup.enter="connectionState ? sendMessage() : null">
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for="send" class="hide-on-small-screen"> </label>
|
<label for="send" class="hide-on-small-screen"> </label>
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
this.communication.log = [{
|
this.communication.log = [{
|
||||||
payload: `Connecting to ${this.url}...`,
|
payload: `Connecting to ${this.url}...`,
|
||||||
source: 'info',
|
source: 'info',
|
||||||
color: 'lime'
|
color: 'var(--ac-color)'
|
||||||
}];
|
}];
|
||||||
try {
|
try {
|
||||||
this.socket = new WebSocket(this.url);
|
this.socket = new WebSocket(this.url);
|
||||||
@@ -113,7 +113,7 @@
|
|||||||
this.communication.log = [{
|
this.communication.log = [{
|
||||||
payload: `Connected to ${this.url}.`,
|
payload: `Connected to ${this.url}.`,
|
||||||
source: 'info',
|
source: 'info',
|
||||||
color: 'lime',
|
color: 'var(--ac-color)',
|
||||||
ts: (new Date()).toLocaleTimeString()
|
ts: (new Date()).toLocaleTimeString()
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
this.communication.log.push({
|
this.communication.log.push({
|
||||||
payload: `Disconnected from ${this.url}.`,
|
payload: `Disconnected from ${this.url}.`,
|
||||||
source: 'info',
|
source: 'info',
|
||||||
color: 'red',
|
color: '#ff5555',
|
||||||
ts: (new Date()).toLocaleTimeString()
|
ts: (new Date()).toLocaleTimeString()
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
1
static/CNAME
Normal file
@@ -0,0 +1 @@
|
|||||||
|
postwoman.io
|
||||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
BIN
static/icon.png
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.9 KiB |
@@ -59,4 +59,4 @@
|
|||||||
data-original="#121212"
|
data-original="#121212"
|
||||||
d="M 64.601,236.822 C 64.601,394.256 192.786,612 306.001,612 412.582,612 547.4,394.256 547.4,236.822 547.4,79.388 439.322,0 306,0 172.678,0 64.601,79.388 64.601,236.822 Z m 304.12,116.415 c 29.475,-29.475 70.598,-40.195 108.552,-32.173 8.021,37.954 -2.698,79.077 -32.173,108.552 -29.475,29.475 -70.598,40.195 -108.552,32.173 -8.022,-37.955 2.698,-79.078 32.173,-108.552 z M 134.727,321.063 c 37.954,-8.021 79.077,2.698 108.552,32.173 29.475,29.475 40.195,70.598 32.173,108.552 -37.954,8.021 -79.077,-2.698 -108.552,-32.173 -29.475,-29.476 -40.194,-70.598 -32.173,-108.552 z"
|
d="M 64.601,236.822 C 64.601,394.256 192.786,612 306.001,612 412.582,612 547.4,394.256 547.4,236.822 547.4,79.388 439.322,0 306,0 172.678,0 64.601,79.388 64.601,236.822 Z m 304.12,116.415 c 29.475,-29.475 70.598,-40.195 108.552,-32.173 8.021,37.954 -2.698,79.077 -32.173,108.552 -29.475,29.475 -70.598,40.195 -108.552,32.173 -8.022,-37.955 2.698,-79.078 32.173,-108.552 z M 134.727,321.063 c 37.954,-8.021 79.077,2.698 108.552,32.173 29.475,29.475 40.195,70.598 32.173,108.552 -37.954,8.021 -79.077,-2.698 -108.552,-32.173 -29.475,-29.476 -40.194,-70.598 -32.173,-108.552 z"
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#51ff0d" /></g></g></g></svg>
|
style="fill:#50fa7b" /></g></g></g></svg>
|
||||||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
BIN
static/screenshot.gif
Normal file
|
After Width: | Height: | Size: 323 KiB |
BIN
static/screenshot2.png
Normal file
|
After Width: | Height: | Size: 173 KiB |