feat: landing page + smart components
This commit is contained in:
18
assets/js/getLinkTag.js
Normal file
18
assets/js/getLinkTag.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
const DEFAULT_TAG = "button"
|
||||||
|
const ANCHOR_TAG = "a"
|
||||||
|
const FRAMEWORK_LINK = "NuxtLink" // or "router-link", "g-link"...
|
||||||
|
|
||||||
|
const getLinkTag = ({ to, blank }) => {
|
||||||
|
if (!to) {
|
||||||
|
return DEFAULT_TAG
|
||||||
|
} else if (blank) {
|
||||||
|
return ANCHOR_TAG
|
||||||
|
} else if (/^\/(?!\/).*$/.test(to)) {
|
||||||
|
// regex101.com/r/LU1iFL/1
|
||||||
|
return FRAMEWORK_LINK
|
||||||
|
} else {
|
||||||
|
return ANCHOR_TAG
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getLinkTag as default, ANCHOR_TAG, FRAMEWORK_LINK }
|
||||||
@@ -149,6 +149,46 @@ hr {
|
|||||||
@apply my-4;
|
@apply my-4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tippy-popper {
|
||||||
|
.tooltip-theme {
|
||||||
|
@apply bg-secondary;
|
||||||
|
@apply text-primaryLight;
|
||||||
|
@apply text-xs;
|
||||||
|
@apply font-semibold;
|
||||||
|
@apply px-2;
|
||||||
|
@apply px-4;
|
||||||
|
@apply shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover-theme {
|
||||||
|
@apply bg-primaryLight;
|
||||||
|
@apply text-secondary;
|
||||||
|
@apply p-2;
|
||||||
|
@apply shadow-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[x-placement^="top"] .tippy-tooltip .tippy-arrow {
|
||||||
|
border-top-color: var(--color-primary-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[x-placement^="bottom"] .tippy-tooltip .tippy-arrow {
|
||||||
|
border-bottom-color: var(--color-primary-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[x-placement^="left"] .tippy-tooltip .tippy-arrow {
|
||||||
|
border-left-color: var(--color-primary-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[x-placement^="right"] .tippy-tooltip .tippy-arrow {
|
||||||
|
border-right-color: var(--color-primary-light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[arrow] > div {
|
||||||
|
@apply flex;
|
||||||
|
@apply w-full;
|
||||||
|
}
|
||||||
|
|
||||||
.tooltip {
|
.tooltip {
|
||||||
@apply z-50;
|
@apply z-50;
|
||||||
@apply outline-none;
|
@apply outline-none;
|
||||||
|
|||||||
@@ -29,11 +29,11 @@
|
|||||||
|
|
||||||
@mixin lightTheme {
|
@mixin lightTheme {
|
||||||
// Background color
|
// Background color
|
||||||
--primary-color: rgba(255, 255, 255, 1);
|
--primary-color: theme("colors.white");
|
||||||
// Light Background color
|
// Light Background color
|
||||||
--primary-light-color: theme("colors.gray.200");
|
--primary-light-color: theme("colors.gray.50");
|
||||||
// Dark Background color
|
// Dark Background color
|
||||||
--primary-dark-color: rgba(0, 0, 0, 0.02);
|
--primary-dark-color: theme("colors.gray.100");
|
||||||
// Text color
|
// Text color
|
||||||
--secondary-color: theme("colors.gray.600");
|
--secondary-color: theme("colors.gray.600");
|
||||||
// Light Text color
|
// Light Text color
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<header class="flex container items-center justify-between p-2 flex-1">
|
<header class="flex container items-center justify-between p-2 flex-1">
|
||||||
<div class="flex items-center relative ml-4">
|
<div class="flex items-center relative ml-2">
|
||||||
<nuxt-link :to="localePath('index')">
|
<nuxt-link :to="localePath('index')">
|
||||||
<h1 class="heading logo">Hoppscotch</h1>
|
<h1 class="heading logo">Hoppscotch</h1>
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
|
<AppGitHubStarButton class="ml-8" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<button
|
<button
|
||||||
|
|||||||
125
components/button/Primary.vue
Normal file
125
components/button/Primary.vue
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
<template>
|
||||||
|
<SmartLink
|
||||||
|
:to="`${/^\/(?!\/).*$/.test(to) ? localePath(to) : to}`"
|
||||||
|
:exact="exact"
|
||||||
|
:blank="blank"
|
||||||
|
class="
|
||||||
|
inline-flex
|
||||||
|
items-center
|
||||||
|
justify-center
|
||||||
|
py-2
|
||||||
|
font-semibold
|
||||||
|
transition
|
||||||
|
focus:outline-none
|
||||||
|
"
|
||||||
|
:class="[
|
||||||
|
color
|
||||||
|
? `text-${color}-800 bg-${color}-200 hover:text-${color}-900 hover:bg-${color}-300 focus:text-${color}-900 focus:bg-${color}-300`
|
||||||
|
: `text-white bg-accent hover:bg-accentDark focus:bg-accentDark`,
|
||||||
|
label ? 'px-4' : 'px-2',
|
||||||
|
rounded ? 'rounded-full' : 'rounded-lg',
|
||||||
|
{ 'opacity-50 cursor-not-allowed': disabled },
|
||||||
|
{ 'pointer-events-none': loading },
|
||||||
|
{ 'px-4 py-4 text-lg': large },
|
||||||
|
{ 'shadow-lg hover:shadow-xl': shadow },
|
||||||
|
{
|
||||||
|
'text-white bg-gradient-to-tr from-gradientFrom via-gradientVia to-gradientTo':
|
||||||
|
gradient,
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
:disabled="disabled"
|
||||||
|
:tabindex="loading ? '-1' : '0'"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-if="!loading"
|
||||||
|
class="inline-flex items-center justify-center whitespace-nowrap"
|
||||||
|
:class="{ 'flex-row-reverse': reverse }"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
v-if="icon"
|
||||||
|
:class="label ? (reverse ? 'ml-2' : 'mr-2') : ''"
|
||||||
|
class="material-icons"
|
||||||
|
>
|
||||||
|
{{ icon }}
|
||||||
|
</i>
|
||||||
|
<SmartIcon
|
||||||
|
v-if="svg"
|
||||||
|
:name="svg"
|
||||||
|
:class="label ? (reverse ? 'ml-4' : 'mr-4') : ''"
|
||||||
|
class="svg-icons"
|
||||||
|
/>
|
||||||
|
{{ label }}
|
||||||
|
<span v-if="shortkey" class="px-1 ml-2 rounded bg-accentLight">{{
|
||||||
|
shortkey
|
||||||
|
}}</span>
|
||||||
|
</span>
|
||||||
|
<SmartSpinner v-else />
|
||||||
|
</SmartLink>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
to: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
exact: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
blank: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
svg: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
large: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
shadow: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
reverse: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
rounded: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
gradient: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
shortkey: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
96
components/button/Secondary.vue
Normal file
96
components/button/Secondary.vue
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
<template>
|
||||||
|
<SmartLink
|
||||||
|
:to="`${/^\/(?!\/).*$/.test(to) ? localePath(to) : to}`"
|
||||||
|
:exact="exact"
|
||||||
|
:blank="blank"
|
||||||
|
class="
|
||||||
|
inline-flex
|
||||||
|
items-center
|
||||||
|
justify-center
|
||||||
|
py-2
|
||||||
|
font-semibold
|
||||||
|
transition
|
||||||
|
focus:outline-none
|
||||||
|
"
|
||||||
|
:class="[
|
||||||
|
color
|
||||||
|
? `text-${color}-500 hover:text-${color}-600 focus:text-${color}-600`
|
||||||
|
: 'hover:text-secondaryDark focus:text-secondaryDark',
|
||||||
|
label ? 'px-3 rounded-lg' : 'px-2 rounded-full',
|
||||||
|
rounded ? 'rounded-full' : 'rounded-lg',
|
||||||
|
{ 'opacity-50 cursor-not-allowed': disabled },
|
||||||
|
{ 'flex-row-reverse': reverse },
|
||||||
|
{
|
||||||
|
'border border-divider hover:border-dividerDark focus:border-dividerDark':
|
||||||
|
outline,
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
:disabled="disabled"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
v-if="icon"
|
||||||
|
:class="label ? (reverse ? 'ml-2' : 'mr-2') : ''"
|
||||||
|
class="material-icons"
|
||||||
|
>
|
||||||
|
{{ icon }}
|
||||||
|
</i>
|
||||||
|
<SmartIcon
|
||||||
|
v-if="svg"
|
||||||
|
:name="svg"
|
||||||
|
:class="label ? (reverse ? 'ml-2' : 'mr-2') : ''"
|
||||||
|
class="svg-icons"
|
||||||
|
/>
|
||||||
|
{{ label }}
|
||||||
|
</SmartLink>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
to: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
exact: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
blank: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
svg: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
reverse: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
rounded: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
outline: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
118
components/landing/Features.vue
Normal file
118
components/landing/Features.vue
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex flex-col p-4">
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<p class="my-4 font-semibold tracking-widest text-center text-accent">
|
||||||
|
FEATURES
|
||||||
|
</p>
|
||||||
|
<h3
|
||||||
|
class="
|
||||||
|
max-w-xl
|
||||||
|
mt-4
|
||||||
|
mb-8
|
||||||
|
text-4xl
|
||||||
|
font-bold
|
||||||
|
leading-tight
|
||||||
|
tracking-tight
|
||||||
|
text-center
|
||||||
|
transition
|
||||||
|
text-secondaryDark
|
||||||
|
"
|
||||||
|
>
|
||||||
|
A technology-first approach to payments and finance
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||||
|
<div
|
||||||
|
v-for="(feature, index) in features"
|
||||||
|
:key="`feature-${index}`"
|
||||||
|
class="
|
||||||
|
inline-flex
|
||||||
|
flex-col
|
||||||
|
p-8
|
||||||
|
transition
|
||||||
|
border
|
||||||
|
rounded-lg
|
||||||
|
border-divider
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<i class="text-3xl material-icons text-accent">{{ feature.icon }}</i>
|
||||||
|
<div class="flex-grow">
|
||||||
|
<h2
|
||||||
|
class="
|
||||||
|
mt-4
|
||||||
|
mb-2
|
||||||
|
text-lg
|
||||||
|
font-semibold
|
||||||
|
transition
|
||||||
|
text-secondaryDark
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ feature.title }}
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
{{ feature.description }}
|
||||||
|
</p>
|
||||||
|
<p class="mt-2">
|
||||||
|
<NuxtLink :to="feature.link.target" class="link">
|
||||||
|
{{ feature.link.title }}
|
||||||
|
<i class="material-icons">chevron_right</i>
|
||||||
|
</NuxtLink>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
features: [
|
||||||
|
{
|
||||||
|
icon: "offline_bolt",
|
||||||
|
title: "SaaS Executives",
|
||||||
|
description:
|
||||||
|
"Unblock your barriers to new markets to sell software globally, to companies of all sizes, at all different price points, and increase your revenue growth with Kooli’s SaaS Commerce Platform.",
|
||||||
|
link: { title: "Learn more", target: "/settings" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "stars",
|
||||||
|
title: "Product Managers",
|
||||||
|
description:
|
||||||
|
"Don’t let your billing stack hold you back. Everything you need to grow your SaaS business. Subscription billing, payments, taxes and more, in one unified platform.",
|
||||||
|
link: { title: "Learn more", target: "/settings" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "supervised_user_circle",
|
||||||
|
title: "Creators",
|
||||||
|
description:
|
||||||
|
"Kooli is for artists and creators: writers, designers, software developers, musicians, educators, filmmakers, and anyone in-between. If you make stuff, you can sell that stuff.",
|
||||||
|
link: { title: "Learn more", target: "/settings" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "build_circle",
|
||||||
|
title: "Developers",
|
||||||
|
description:
|
||||||
|
"Focus on building, not billing. Save the blood, sweat and tears for your software development, not your billing stack, with Paddle’s subscription and commerce platform.",
|
||||||
|
link: { title: "Learn more", target: "/settings" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "monetization_on",
|
||||||
|
title: "Finance",
|
||||||
|
description:
|
||||||
|
"All your payments, subscriptions, taxes, invoices, SaaS metrics, and more in one place. Integrate your product, CRM, and accounting with only one tool, not dozens.",
|
||||||
|
link: { title: "Learn more", target: "/settings" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "group_work",
|
||||||
|
title: "Enterprise",
|
||||||
|
description:
|
||||||
|
"Accept payments in 135+ currencies to better serve your international customers with a single integration. No international business entity required. Fees exclude GST.",
|
||||||
|
link: { title: "Learn more", target: "/settings" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
168
components/landing/Footer.vue
Normal file
168
components/landing/Footer.vue
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
<template>
|
||||||
|
<footer class="flex flex-col px-8 py-16">
|
||||||
|
<nav class="grid grid-cols-2 gap-4 md:grid-cols-4">
|
||||||
|
<div class="flex flex-col space-y-2">
|
||||||
|
<SmartLink
|
||||||
|
:to="
|
||||||
|
!$store.state.authUser
|
||||||
|
? localePath('/')
|
||||||
|
: localePath(`/${$store.state.login}`)
|
||||||
|
"
|
||||||
|
class="my-2"
|
||||||
|
>
|
||||||
|
<AppLogo class="h-8" />
|
||||||
|
</SmartLink>
|
||||||
|
<span> Kooli </span>
|
||||||
|
<SmartChangeLanguage />
|
||||||
|
<ul class="space-y-2">
|
||||||
|
<li>
|
||||||
|
<SmartAnchor label="Terms" to="/about/terms" class="footer-nav" />
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<SmartAnchor
|
||||||
|
label="Privacy"
|
||||||
|
to="/about/privacy"
|
||||||
|
class="footer-nav"
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<SmartColorModePicker />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col space-y-2">
|
||||||
|
<h4 class="my-2 font-semibold">Solutions</h4>
|
||||||
|
<ul class="space-y-2">
|
||||||
|
<li
|
||||||
|
v-for="(item, index) in navigation.solutions"
|
||||||
|
:key="`item-${index}`"
|
||||||
|
>
|
||||||
|
<SmartAnchor
|
||||||
|
:label="item.name"
|
||||||
|
:to="item.link"
|
||||||
|
class="footer-nav"
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col space-y-2">
|
||||||
|
<h4 class="my-2 font-semibold">Platform</h4>
|
||||||
|
<ul class="space-y-2">
|
||||||
|
<li
|
||||||
|
v-for="(item, index) in navigation.platform"
|
||||||
|
:key="`item-${index}`"
|
||||||
|
>
|
||||||
|
<SmartAnchor
|
||||||
|
:label="item.name"
|
||||||
|
:to="item.link"
|
||||||
|
class="footer-nav"
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col space-y-2">
|
||||||
|
<h4 class="my-2 font-semibold">Company</h4>
|
||||||
|
<ul class="space-y-2">
|
||||||
|
<li
|
||||||
|
v-for="(item, index) in navigation.company"
|
||||||
|
:key="`item-${index}`"
|
||||||
|
>
|
||||||
|
<SmartAnchor
|
||||||
|
:label="item.name"
|
||||||
|
:to="item.link"
|
||||||
|
class="footer-nav"
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</footer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
navigation: {
|
||||||
|
solutions: [
|
||||||
|
{
|
||||||
|
name: "SaaS",
|
||||||
|
link: "/settings",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Products",
|
||||||
|
link: "/settings",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Creators",
|
||||||
|
link: "/settings",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Developers",
|
||||||
|
link: "/settings",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Finance",
|
||||||
|
link: "/settings",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Enterprise",
|
||||||
|
link: "/settings",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
platform: [
|
||||||
|
{
|
||||||
|
name: "Payments",
|
||||||
|
link: "/settings",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Subscriptions",
|
||||||
|
link: "/settings",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "API",
|
||||||
|
link: "https://docs.kooli.tech/api",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Guides",
|
||||||
|
link: "https://docs.kooli.tech/guides",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
company: [
|
||||||
|
{
|
||||||
|
name: "About",
|
||||||
|
link: "/about",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Jobs",
|
||||||
|
link: "/about/jobs",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Integrations",
|
||||||
|
link: "/about/integrations",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Support",
|
||||||
|
link: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Contact",
|
||||||
|
link: "/about/contact",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Blog",
|
||||||
|
link: "https://blog.kooli.tech",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.footer-nav {
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
@apply text-secondaryDark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="globe" class="w-full"></div>
|
<div ref="globe"></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -32,12 +32,23 @@ export default {
|
|||||||
mounted() {
|
mounted() {
|
||||||
this.init()
|
this.init()
|
||||||
this.animate()
|
this.animate()
|
||||||
|
window.addEventListener(
|
||||||
|
"resize",
|
||||||
|
() => {
|
||||||
|
this.camera.aspect =
|
||||||
|
this.$refs.globe.clientWidth / this.$refs.globe.clientHeight
|
||||||
|
this.camera.updateProjectionMatrix()
|
||||||
|
this.renderer.setSize(
|
||||||
|
this.$refs.globe.clientWidth,
|
||||||
|
this.$refs.globe.clientHeight
|
||||||
|
)
|
||||||
|
},
|
||||||
|
false
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
init() {
|
init() {
|
||||||
const container = document.getElementById("globe")
|
|
||||||
|
|
||||||
this.globe = new ThreeGlobe()
|
this.globe = new ThreeGlobe()
|
||||||
.globeImageUrl(texture)
|
.globeImageUrl(texture)
|
||||||
.atmosphereColor("#aaaaaa")
|
.atmosphereColor("#aaaaaa")
|
||||||
@@ -56,9 +67,12 @@ export default {
|
|||||||
this.renderer = new THREE.WebGLRenderer({
|
this.renderer = new THREE.WebGLRenderer({
|
||||||
alpha: true,
|
alpha: true,
|
||||||
})
|
})
|
||||||
this.renderer.setSize(container.clientWidth, container.clientHeight)
|
this.renderer.setSize(
|
||||||
|
this.$refs.globe.clientWidth,
|
||||||
|
this.$refs.globe.clientHeight
|
||||||
|
)
|
||||||
|
|
||||||
container.appendChild(this.renderer.domElement)
|
this.$refs.globe.appendChild(this.renderer.domElement)
|
||||||
|
|
||||||
this.scene = new THREE.Scene()
|
this.scene = new THREE.Scene()
|
||||||
this.scene.background = null
|
this.scene.background = null
|
||||||
@@ -67,7 +81,8 @@ export default {
|
|||||||
this.scene.add(new THREE.DirectionalLight(0xffffff, 0.8))
|
this.scene.add(new THREE.DirectionalLight(0xffffff, 0.8))
|
||||||
|
|
||||||
this.camera = new THREE.PerspectiveCamera()
|
this.camera = new THREE.PerspectiveCamera()
|
||||||
this.camera.aspect = container.clientWidth / container.clientHeight
|
this.camera.aspect =
|
||||||
|
this.$refs.globe.clientWidth / this.$refs.globe.clientHeight
|
||||||
this.camera.updateProjectionMatrix()
|
this.camera.updateProjectionMatrix()
|
||||||
this.camera.position.z = 300
|
this.camera.position.z = 300
|
||||||
},
|
},
|
||||||
42
components/landing/Hero.vue
Normal file
42
components/landing/Hero.vue
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex p-4 relative overflow-hidden">
|
||||||
|
<div class="relative my-16 z-10 max-w-3xl">
|
||||||
|
<h2
|
||||||
|
class="
|
||||||
|
leading-none
|
||||||
|
tracking-tighter
|
||||||
|
font-semibold
|
||||||
|
text-accent text-5xl
|
||||||
|
md:text-6xl
|
||||||
|
lg:text-8xl
|
||||||
|
"
|
||||||
|
>
|
||||||
|
Open Source
|
||||||
|
</h2>
|
||||||
|
<h3
|
||||||
|
class="
|
||||||
|
text-3xl
|
||||||
|
my-8
|
||||||
|
font-mono
|
||||||
|
text-secondaryDark
|
||||||
|
md:text-4xl
|
||||||
|
lg:text-4xl
|
||||||
|
font-semibold
|
||||||
|
"
|
||||||
|
>
|
||||||
|
API Development Ecosystem
|
||||||
|
</h3>
|
||||||
|
<p class="text-lg my-4 text-secondaryLight max-w-4/5">
|
||||||
|
Millions of developers and companies build, ship, and maintain their
|
||||||
|
APIs on Hoppscotch — the largest and most advanced development platform
|
||||||
|
in the world.
|
||||||
|
</p>
|
||||||
|
<div class="my-8 flex items-center">
|
||||||
|
<button class="button rounded text-xl">Get Started</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg:absolute lg:inset-y-0 lg:right-0 lg:w-1/2">
|
||||||
|
<LandingGlobe class="h-64 w-full sm:h-72 md:h-96 lg:w-full lg:h-full" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
142
components/landing/Package.vue
Normal file
142
components/landing/Package.vue
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex flex-col p-4">
|
||||||
|
<div class="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
||||||
|
<div
|
||||||
|
class="inline-flex flex-col transition border rounded-lg border-divider"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col p-8">
|
||||||
|
<p class="font-semibold tracking-widest text-accent">API</p>
|
||||||
|
<h3
|
||||||
|
class="
|
||||||
|
max-w-xl
|
||||||
|
my-4
|
||||||
|
text-4xl
|
||||||
|
font-semibold
|
||||||
|
leading-tight
|
||||||
|
tracking-tight
|
||||||
|
transition
|
||||||
|
text-secondaryDark
|
||||||
|
"
|
||||||
|
>
|
||||||
|
Powerful and easy-to-use APIs
|
||||||
|
</h3>
|
||||||
|
<p class="my-4 text-lg md:w-4/5">
|
||||||
|
We agonize over the right abstractions so your teams don’t need to
|
||||||
|
stitch together disparate systems or spend months integrating
|
||||||
|
payments functionality.
|
||||||
|
</p>
|
||||||
|
<div class="flex mt-4">
|
||||||
|
<ButtonPrimary
|
||||||
|
to="https://docs.kooli.tech/guides"
|
||||||
|
label="Read the docs"
|
||||||
|
icon="chevron_right"
|
||||||
|
reverse
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
||||||
|
<div
|
||||||
|
v-for="(api, index) in apis"
|
||||||
|
:key="`api-${index}`"
|
||||||
|
class="inline-flex flex-col p-8"
|
||||||
|
>
|
||||||
|
<i class="text-3xl material-icons text-accent">{{ api.icon }}</i>
|
||||||
|
<div class="flex-grow">
|
||||||
|
<h2
|
||||||
|
class="
|
||||||
|
mt-4
|
||||||
|
mb-2
|
||||||
|
text-lg
|
||||||
|
font-semibold
|
||||||
|
transition
|
||||||
|
text-secondaryDark
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ api.title }}
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
{{ api.description }}
|
||||||
|
</p>
|
||||||
|
<p class="mt-2">
|
||||||
|
<SmartLink :to="api.link.target" class="link">
|
||||||
|
{{ api.link.title }}
|
||||||
|
<i class="material-icons">chevron_right</i>
|
||||||
|
</SmartLink>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="
|
||||||
|
inline-flex
|
||||||
|
flex-col
|
||||||
|
p-4
|
||||||
|
transition
|
||||||
|
border
|
||||||
|
rounded-lg
|
||||||
|
border-divider
|
||||||
|
bg-primaryLight
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div class="flex">
|
||||||
|
<div class="w-3 h-3 mr-2 bg-red-500 rounded-full"></div>
|
||||||
|
<div class="w-3 h-3 mr-2 bg-yellow-500 rounded-full"></div>
|
||||||
|
<div class="w-3 h-3 bg-green-500 rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-1 p-4 overflow-auto whitespace-pre">
|
||||||
|
<pre>
|
||||||
|
/*
|
||||||
|
** TailwindCSS Configuration File
|
||||||
|
**
|
||||||
|
** Docs: https://tailwindcss.com/docs/configuration
|
||||||
|
** Default: https://github.com/tailwindcss/tailwindcss/blob/master/stubs/defaultConfig.stub.js
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
future: {
|
||||||
|
removeDeprecatedGapUtilities: true,
|
||||||
|
purgeLayersByDefault: true,
|
||||||
|
},
|
||||||
|
experimental: "all",
|
||||||
|
dark: "class",
|
||||||
|
corePlugins: {
|
||||||
|
float: false,
|
||||||
|
clear: false,
|
||||||
|
transitionDelay: false,
|
||||||
|
skew: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
apis: [
|
||||||
|
{
|
||||||
|
icon: "layers",
|
||||||
|
title: "Tools for every stack",
|
||||||
|
description:
|
||||||
|
"We offer client and server libraries in everything from React, PHP to .NET and iOS.",
|
||||||
|
link: {
|
||||||
|
title: "See libraries",
|
||||||
|
target: "https://docs.kooli.tech/api",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "extension",
|
||||||
|
title: "Prebuilt integrations",
|
||||||
|
description:
|
||||||
|
"Use integrations for systems like Shopify, PayPal, and more.",
|
||||||
|
link: { title: "Explore partners", target: "/about/integrations" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
27
components/landing/Stats.vue
Normal file
27
components/landing/Stats.vue
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex p-4 font-mono space-x-16">
|
||||||
|
<div v-for="(stat, index) in stats" :key="`stat-${index}`">
|
||||||
|
<span class="text-xl font-bold">
|
||||||
|
{{ stat.count }}<span class="text-secondaryLight">+</span>
|
||||||
|
</span>
|
||||||
|
<br />
|
||||||
|
<span class="text-sm">
|
||||||
|
{{ stat.audience }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
stats: [
|
||||||
|
{ count: "350k", audience: "Developers" },
|
||||||
|
{ count: "10k", audience: "Organizations" },
|
||||||
|
{ count: "1m", audience: "Requests" },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
27
components/landing/Users.vue
Normal file
27
components/landing/Users.vue
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex flex-col p-4">
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<p
|
||||||
|
class="mt-4 mb-8 font-semibold tracking-widest text-center text-accent"
|
||||||
|
>
|
||||||
|
EMPOWERING CREATORS
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-3 gap-4 md:grid-cols-4 lg:grid-cols-6">
|
||||||
|
<div
|
||||||
|
v-for="(user, index) in 12"
|
||||||
|
:key="`user-${index}`"
|
||||||
|
class="inline-flex flex-col items-center justify-center p-4"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="`https://i.pravatar.cc/${Math.floor(
|
||||||
|
Math.random() * (600 - 400 + 1) + 400
|
||||||
|
)}`"
|
||||||
|
alt="Profile picture"
|
||||||
|
loading="lazy"
|
||||||
|
class="inline-flex flex-col object-contain object-center h-24 w-24"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
74
components/smart/Anchor.vue
Normal file
74
components/smart/Anchor.vue
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<template>
|
||||||
|
<SmartLink
|
||||||
|
:to="`${/^\/(?!\/).*$/.test(to) ? localePath(to) : to}`"
|
||||||
|
:exact="exact"
|
||||||
|
:blank="blank"
|
||||||
|
class="inline-flex items-center justify-center focus:outline-none"
|
||||||
|
:class="[
|
||||||
|
color
|
||||||
|
? `text-${color}-500 transition hover:text-${color}-600 focus:text-${color}-600`
|
||||||
|
: 'transition hover:text-secondaryDark focus:text-secondaryDark',
|
||||||
|
{ 'opacity-50 cursor-not-allowed': disabled },
|
||||||
|
{ 'flex-row-reverse': reverse },
|
||||||
|
]"
|
||||||
|
:disabled="disabled"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
v-if="icon"
|
||||||
|
:class="label ? (reverse ? 'ml-2' : 'mr-2') : ''"
|
||||||
|
class="material-icons"
|
||||||
|
>
|
||||||
|
{{ icon }}
|
||||||
|
</i>
|
||||||
|
<SmartIcon
|
||||||
|
v-if="svg"
|
||||||
|
:name="svg"
|
||||||
|
:class="label ? (reverse ? 'ml-2' : 'mr-2') : ''"
|
||||||
|
class="svg-icons"
|
||||||
|
/>
|
||||||
|
{{ label }}
|
||||||
|
</SmartLink>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
to: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
exact: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
blank: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
svg: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
reverse: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
51
components/smart/ChangeLanguage.vue
Normal file
51
components/smart/ChangeLanguage.vue
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<span>
|
||||||
|
<tippy
|
||||||
|
ref="language"
|
||||||
|
trigger="click"
|
||||||
|
theme="popover"
|
||||||
|
arrow
|
||||||
|
interactive
|
||||||
|
:animate-fill="false"
|
||||||
|
>
|
||||||
|
<template #trigger>
|
||||||
|
<button
|
||||||
|
v-tippy="{ animateFill: false, theme: 'tooltip' }"
|
||||||
|
:title="$t('choose_language')"
|
||||||
|
>
|
||||||
|
<span class="mr-2 text-lg">
|
||||||
|
{{
|
||||||
|
$i18n.locales.find(({ code }) => code == $i18n.locale).country
|
||||||
|
| formatCountry
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
{{ $i18n.locales.find(({ code }) => code == $i18n.locale).name }}
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
<NuxtLink
|
||||||
|
v-for="locale in $i18n.locales.filter(
|
||||||
|
({ code }) => code !== $i18n.locale
|
||||||
|
)"
|
||||||
|
:key="locale.code"
|
||||||
|
class="
|
||||||
|
inline-flex
|
||||||
|
items-center
|
||||||
|
px-4
|
||||||
|
py-2
|
||||||
|
transition
|
||||||
|
rounded-lg
|
||||||
|
hover:bg-accentLight hover:text-secondaryDark
|
||||||
|
focus:bg-accentLight focus:text-secondaryDark focus:outline-none
|
||||||
|
"
|
||||||
|
:to="switchLocalePath(locale.code)"
|
||||||
|
>
|
||||||
|
<span class="mr-2 text-lg">
|
||||||
|
{{ locale.country | formatCountry }}
|
||||||
|
</span>
|
||||||
|
<span class="font-semibold">
|
||||||
|
{{ locale.name }}
|
||||||
|
</span>
|
||||||
|
</NuxtLink>
|
||||||
|
</tippy>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
67
components/smart/Link.js
Normal file
67
components/smart/Link.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/* Vue 2 Functional Component: https://vuejs.org/v2/guide/render-function.html#Functional-Components */
|
||||||
|
import { mergeData } from "vue-functional-data-merge"
|
||||||
|
import getLinkTag, { ANCHOR_TAG, FRAMEWORK_LINK } from "~/assets/js/getLinkTag"
|
||||||
|
|
||||||
|
const SmartLink = {
|
||||||
|
functional: true,
|
||||||
|
props: {
|
||||||
|
to: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
exact: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
blank: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// It's a convention to rename `createElement` to `h`
|
||||||
|
render(h, context) {
|
||||||
|
const tag = getLinkTag(context.props)
|
||||||
|
|
||||||
|
// Map our attributes correctly
|
||||||
|
const attrs = {}
|
||||||
|
let on = {}
|
||||||
|
switch (tag) {
|
||||||
|
case ANCHOR_TAG:
|
||||||
|
// Map `to` prop to the correct attribute
|
||||||
|
attrs.href = context.props.to
|
||||||
|
|
||||||
|
// Handle `blank` prop
|
||||||
|
if (context.props.blank) {
|
||||||
|
attrs.target = "_blank"
|
||||||
|
attrs.rel = "noopener"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform native events to regular events for HTML anchor tag
|
||||||
|
on = { ...context.data.nativeOn }
|
||||||
|
delete context.data.nativeOn
|
||||||
|
break
|
||||||
|
|
||||||
|
case FRAMEWORK_LINK:
|
||||||
|
// Map `to` prop to the correct attribute
|
||||||
|
attrs.to = context.props.to
|
||||||
|
|
||||||
|
// Handle `exact` prop
|
||||||
|
if (context.props.exact) {
|
||||||
|
attrs.exact = true
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge our new data with existing ones
|
||||||
|
const data = mergeData(context.data, { attrs, on })
|
||||||
|
|
||||||
|
// Return a new virtual node
|
||||||
|
return h(tag, data, context.children)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SmartLink
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
<Pane
|
<Pane
|
||||||
v-if="!hideNavigationPane"
|
v-if="!hideNavigationPane"
|
||||||
style="width: auto"
|
style="width: auto"
|
||||||
class="overflow-y-auto bg-primaryDark flex items-stretch"
|
class="overflow-y-auto bg-primaryLight flex items-stretch"
|
||||||
>
|
>
|
||||||
<AppSidenav />
|
<AppSidenav />
|
||||||
</Pane>
|
</Pane>
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
</Pane>
|
</Pane>
|
||||||
</Splitpanes>
|
</Splitpanes>
|
||||||
</Pane>
|
</Pane>
|
||||||
<Pane style="height: auto" class="bg-primaryDark">
|
<Pane style="height: auto" class="bg-primaryLight">
|
||||||
<button
|
<button
|
||||||
class="button icon"
|
class="button icon"
|
||||||
@click="hideNavigationPane = !hideNavigationPane"
|
@click="hideNavigationPane = !hideNavigationPane"
|
||||||
@@ -120,12 +120,8 @@ export default {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.splitpanes--vertical > .splitpanes__splitter {
|
.splitpanes--vertical > .splitpanes__splitter {
|
||||||
display: none;
|
display: none;
|
||||||
width: 0;
|
|
||||||
background: linear-gradient(90deg, #ccc, #111);
|
|
||||||
}
|
}
|
||||||
.splitpanes--horizontal > .splitpanes__splitter {
|
.splitpanes--horizontal > .splitpanes__splitter {
|
||||||
display: none;
|
display: none;
|
||||||
height: 0;
|
|
||||||
background: linear-gradient(0deg, #ccc, #111);
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -93,11 +93,13 @@ export default {
|
|||||||
|
|
||||||
// Plugins to run before rendering page (https://go.nuxtjs.dev/config-plugins)
|
// Plugins to run before rendering page (https://go.nuxtjs.dev/config-plugins)
|
||||||
plugins: [
|
plugins: [
|
||||||
|
"~/plugins/v-tippy",
|
||||||
"~/plugins/vuex-persist",
|
"~/plugins/vuex-persist",
|
||||||
"~/plugins/v-tooltip",
|
"~/plugins/v-tooltip",
|
||||||
"~/plugins/vue-rx",
|
"~/plugins/vue-rx",
|
||||||
"~/plugins/vue-apollo",
|
"~/plugins/vue-apollo",
|
||||||
{ src: "~/plugins/web-worker", ssr: false },
|
{ src: "~/plugins/web-worker", ssr: false },
|
||||||
|
"~/plugins/formatCountry.js",
|
||||||
],
|
],
|
||||||
|
|
||||||
// Auto import components (https://go.nuxtjs.dev/config-components)
|
// Auto import components (https://go.nuxtjs.dev/config-components)
|
||||||
@@ -225,114 +227,133 @@ export default {
|
|||||||
name: "English",
|
name: "English",
|
||||||
iso: "en-US",
|
iso: "en-US",
|
||||||
file: "en-US.json",
|
file: "en-US.json",
|
||||||
|
country: "US",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "es",
|
code: "es",
|
||||||
name: "Español",
|
name: "Español",
|
||||||
iso: "es-ES",
|
iso: "es-ES",
|
||||||
file: "es-ES.json",
|
file: "es-ES.json",
|
||||||
|
country: "ES",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "fr",
|
code: "fr",
|
||||||
name: "Français",
|
name: "Français",
|
||||||
iso: "fr-FR",
|
iso: "fr-FR",
|
||||||
file: "fr-FR.json",
|
file: "fr-FR.json",
|
||||||
|
country: "FR",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "fa",
|
code: "fa",
|
||||||
name: "Farsi",
|
name: "Farsi",
|
||||||
iso: "fa-IR",
|
iso: "fa-IR",
|
||||||
file: "fa-IR.json",
|
file: "fa-IR.json",
|
||||||
|
country: "IR",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "pt",
|
code: "pt",
|
||||||
name: "Português",
|
name: "Português",
|
||||||
iso: "pt-PT",
|
iso: "pt-PT",
|
||||||
file: "pt-PT.json",
|
file: "pt-PT.json",
|
||||||
|
country: "PT",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "pt-br",
|
code: "pt-br",
|
||||||
name: "Português Brasileiro",
|
name: "Português Brasileiro",
|
||||||
iso: "pt-BR",
|
iso: "pt-BR",
|
||||||
file: "pt-BR.json",
|
file: "pt-BR.json",
|
||||||
|
country: "BR",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "cn",
|
code: "cn",
|
||||||
name: "简体中文",
|
name: "简体中文",
|
||||||
iso: "zh-CN",
|
iso: "zh-CN",
|
||||||
file: "zh-CN.json",
|
file: "zh-CN.json",
|
||||||
|
country: "CN",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "tw",
|
code: "tw",
|
||||||
name: "繁體中文",
|
name: "繁體中文",
|
||||||
iso: "zh-TW",
|
iso: "zh-TW",
|
||||||
file: "zh-TW.json",
|
file: "zh-TW.json",
|
||||||
|
country: "TW",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "id",
|
code: "id",
|
||||||
name: "Bahasa Indonesia",
|
name: "Bahasa Indonesia",
|
||||||
iso: "id-ID",
|
iso: "id-ID",
|
||||||
file: "id-ID.json",
|
file: "id-ID.json",
|
||||||
|
country: "ID",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "tr",
|
code: "tr",
|
||||||
name: "Türkçe",
|
name: "Türkçe",
|
||||||
iso: "tr-TR",
|
iso: "tr-TR",
|
||||||
file: "tr-TR.json",
|
file: "tr-TR.json",
|
||||||
|
country: "TR",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "de",
|
code: "de",
|
||||||
name: "Deutsch",
|
name: "Deutsch",
|
||||||
iso: "de-DE",
|
iso: "de-DE",
|
||||||
file: "de-DE.json",
|
file: "de-DE.json",
|
||||||
|
country: "DE",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "ja",
|
code: "ja",
|
||||||
name: "日本語",
|
name: "日本語",
|
||||||
iso: "ja-JP",
|
iso: "ja-JP",
|
||||||
file: "ja-JP.json",
|
file: "ja-JP.json",
|
||||||
|
country: "JP",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "ko",
|
code: "ko",
|
||||||
name: "한국어",
|
name: "한국어",
|
||||||
iso: "ko-KR",
|
iso: "ko-KR",
|
||||||
file: "ko-KR.json",
|
file: "ko-KR.json",
|
||||||
|
country: "KR",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "in",
|
code: "in",
|
||||||
name: "हिंदी",
|
name: "हिंदी",
|
||||||
iso: "in-IN",
|
iso: "in-IN",
|
||||||
file: "in-IN.json",
|
file: "in-IN.json",
|
||||||
|
country: "IN",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "bn",
|
code: "bn",
|
||||||
name: "Bengali",
|
name: "Bengali",
|
||||||
iso: "bn-BD",
|
iso: "bn-BD",
|
||||||
file: "bn-BD.json",
|
file: "bn-BD.json",
|
||||||
|
country: "BD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "ml",
|
code: "ml",
|
||||||
name: "മലയാളം",
|
name: "മലയാളം",
|
||||||
iso: "ml-ML",
|
iso: "ml-ML",
|
||||||
file: "ml-ML.json",
|
file: "ml-ML.json",
|
||||||
|
country: "ML",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "vi",
|
code: "vi",
|
||||||
name: "Vietnamese",
|
name: "Vietnamese",
|
||||||
iso: "vi-VN",
|
iso: "vi-VN",
|
||||||
file: "vi-VN.json",
|
file: "vi-VN.json",
|
||||||
|
country: "VN",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "nl",
|
code: "nl",
|
||||||
name: "Dutch",
|
name: "Dutch",
|
||||||
iso: "nl-BE",
|
iso: "nl-BE",
|
||||||
file: "nl-BE.json",
|
file: "nl-BE.json",
|
||||||
|
country: "BE",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "nb",
|
code: "nb",
|
||||||
name: "Norwegian (Bokmål)",
|
name: "Norwegian (Bokmål)",
|
||||||
iso: "nb-NO",
|
iso: "nb-NO",
|
||||||
file: "nb-NO.json",
|
file: "nb-NO.json",
|
||||||
|
country: "NO",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
defaultLocale: "en",
|
defaultLocale: "en",
|
||||||
|
|||||||
59
package-lock.json
generated
59
package-lock.json
generated
@@ -38,8 +38,10 @@
|
|||||||
"v-tooltip": "^2.1.3",
|
"v-tooltip": "^2.1.3",
|
||||||
"vue-apollo": "^3.0.7",
|
"vue-apollo": "^3.0.7",
|
||||||
"vue-cli-plugin-apollo": "^0.22.2",
|
"vue-cli-plugin-apollo": "^0.22.2",
|
||||||
|
"vue-functional-data-merge": "^3.1.0",
|
||||||
"vue-github-button": "^1.3.0",
|
"vue-github-button": "^1.3.0",
|
||||||
"vue-rx": "^6.2.0",
|
"vue-rx": "^6.2.0",
|
||||||
|
"vue-tippy": "^4.10.2",
|
||||||
"vuejs-auto-complete": "^0.9.0",
|
"vuejs-auto-complete": "^0.9.0",
|
||||||
"vuex-persist": "^3.1.3",
|
"vuex-persist": "^3.1.3",
|
||||||
"yargs-parser": "^20.2.9"
|
"yargs-parser": "^20.2.9"
|
||||||
@@ -17009,6 +17011,11 @@
|
|||||||
"node": ">=10.17.0"
|
"node": ">=10.17.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/humps": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/humps/-/humps-2.0.1.tgz",
|
||||||
|
"integrity": "sha1-3QLqYIG9BWjcXQcxhEY5V7qe+ao="
|
||||||
|
},
|
||||||
"node_modules/husky": {
|
"node_modules/husky": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/husky/-/husky-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/husky/-/husky-7.0.0.tgz",
|
||||||
@@ -28053,6 +28060,14 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tippy.js": {
|
||||||
|
"version": "4.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-4.3.5.tgz",
|
||||||
|
"integrity": "sha512-NDq3efte8nGK6BOJ1dDN1/WelAwfmh3UtIYXXck6+SxLzbIQNZE/cmRSnwScZ/FyiKdIcvFHvYUgqmoGx8CcyA==",
|
||||||
|
"dependencies": {
|
||||||
|
"popper.js": "^1.14.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tmp": {
|
"node_modules/tmp": {
|
||||||
"version": "0.0.33",
|
"version": "0.0.33",
|
||||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||||
@@ -29420,6 +29435,11 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-functional-data-merge": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-functional-data-merge/-/vue-functional-data-merge-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-leT4kdJVQyeZNY1kmnS1xiUlQ9z1B/kdBFCILIjYYQDqZgLqCLa0UhjSSeRX6c3mUe6U5qYeM8LrEqkHJ1B4LA=="
|
||||||
|
},
|
||||||
"node_modules/vue-github-button": {
|
"node_modules/vue-github-button": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/vue-github-button/-/vue-github-button-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/vue-github-button/-/vue-github-button-1.3.0.tgz",
|
||||||
@@ -29681,6 +29701,18 @@
|
|||||||
"resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz",
|
||||||
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw=="
|
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-tippy": {
|
||||||
|
"version": "4.10.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-tippy/-/vue-tippy-4.10.2.tgz",
|
||||||
|
"integrity": "sha512-o1E4Q7gJHrL5VKpPF10Mdp9Grrqi9JGUBrkOQQUmTrklxctYvjpsSxePZVM0mgfGfRFAboOClw33X1ueB4Byjw==",
|
||||||
|
"dependencies": {
|
||||||
|
"humps": "^2.0.1",
|
||||||
|
"tippy.js": "^4.3.5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^2.5.9"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vue-toasted": {
|
"node_modules/vue-toasted": {
|
||||||
"version": "1.1.28",
|
"version": "1.1.28",
|
||||||
"resolved": "https://registry.npmjs.org/vue-toasted/-/vue-toasted-1.1.28.tgz",
|
"resolved": "https://registry.npmjs.org/vue-toasted/-/vue-toasted-1.1.28.tgz",
|
||||||
@@ -45859,6 +45891,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
||||||
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="
|
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="
|
||||||
},
|
},
|
||||||
|
"humps": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/humps/-/humps-2.0.1.tgz",
|
||||||
|
"integrity": "sha1-3QLqYIG9BWjcXQcxhEY5V7qe+ao="
|
||||||
|
},
|
||||||
"husky": {
|
"husky": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/husky/-/husky-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/husky/-/husky-7.0.0.tgz",
|
||||||
@@ -55001,6 +55038,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz",
|
||||||
"integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA=="
|
"integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA=="
|
||||||
},
|
},
|
||||||
|
"tippy.js": {
|
||||||
|
"version": "4.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-4.3.5.tgz",
|
||||||
|
"integrity": "sha512-NDq3efte8nGK6BOJ1dDN1/WelAwfmh3UtIYXXck6+SxLzbIQNZE/cmRSnwScZ/FyiKdIcvFHvYUgqmoGx8CcyA==",
|
||||||
|
"requires": {
|
||||||
|
"popper.js": "^1.14.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
"tmp": {
|
"tmp": {
|
||||||
"version": "0.0.33",
|
"version": "0.0.33",
|
||||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||||
@@ -56142,6 +56187,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"vue-functional-data-merge": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-functional-data-merge/-/vue-functional-data-merge-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-leT4kdJVQyeZNY1kmnS1xiUlQ9z1B/kdBFCILIjYYQDqZgLqCLa0UhjSSeRX6c3mUe6U5qYeM8LrEqkHJ1B4LA=="
|
||||||
|
},
|
||||||
"vue-github-button": {
|
"vue-github-button": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/vue-github-button/-/vue-github-button-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/vue-github-button/-/vue-github-button-1.3.0.tgz",
|
||||||
@@ -56381,6 +56431,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz",
|
||||||
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw=="
|
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw=="
|
||||||
},
|
},
|
||||||
|
"vue-tippy": {
|
||||||
|
"version": "4.10.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-tippy/-/vue-tippy-4.10.2.tgz",
|
||||||
|
"integrity": "sha512-o1E4Q7gJHrL5VKpPF10Mdp9Grrqi9JGUBrkOQQUmTrklxctYvjpsSxePZVM0mgfGfRFAboOClw33X1ueB4Byjw==",
|
||||||
|
"requires": {
|
||||||
|
"humps": "^2.0.1",
|
||||||
|
"tippy.js": "^4.3.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"vue-toasted": {
|
"vue-toasted": {
|
||||||
"version": "1.1.28",
|
"version": "1.1.28",
|
||||||
"resolved": "https://registry.npmjs.org/vue-toasted/-/vue-toasted-1.1.28.tgz",
|
"resolved": "https://registry.npmjs.org/vue-toasted/-/vue-toasted-1.1.28.tgz",
|
||||||
|
|||||||
@@ -54,8 +54,10 @@
|
|||||||
"v-tooltip": "^2.1.3",
|
"v-tooltip": "^2.1.3",
|
||||||
"vue-apollo": "^3.0.7",
|
"vue-apollo": "^3.0.7",
|
||||||
"vue-cli-plugin-apollo": "^0.22.2",
|
"vue-cli-plugin-apollo": "^0.22.2",
|
||||||
|
"vue-functional-data-merge": "^3.1.0",
|
||||||
"vue-github-button": "^1.3.0",
|
"vue-github-button": "^1.3.0",
|
||||||
"vue-rx": "^6.2.0",
|
"vue-rx": "^6.2.0",
|
||||||
|
"vue-tippy": "^4.10.2",
|
||||||
"vuejs-auto-complete": "^0.9.0",
|
"vuejs-auto-complete": "^0.9.0",
|
||||||
"vuex-persist": "^3.1.3",
|
"vuex-persist": "^3.1.3",
|
||||||
"yargs-parser": "^20.2.9"
|
"yargs-parser": "^20.2.9"
|
||||||
|
|||||||
@@ -1,42 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex p-4 justify-between">
|
<div>
|
||||||
<div class="max-w-md">
|
<LandingHero />
|
||||||
<h2
|
<LandingStats />
|
||||||
class="
|
<LandingUsers />
|
||||||
leading-none
|
<LandingFeatures />
|
||||||
tracking-tighter
|
<LandingPackage />
|
||||||
font-semibold
|
<LandingFooter />
|
||||||
text-accent text-5xl
|
|
||||||
md:text-6xl
|
|
||||||
lg:text-8xl
|
|
||||||
"
|
|
||||||
>
|
|
||||||
Open Source
|
|
||||||
</h2>
|
|
||||||
<h3
|
|
||||||
class="
|
|
||||||
text-3xl
|
|
||||||
my-8
|
|
||||||
font-mono
|
|
||||||
text-secondaryDark
|
|
||||||
md:text-4xl
|
|
||||||
lg:text-4xl
|
|
||||||
font-semibold
|
|
||||||
"
|
|
||||||
>
|
|
||||||
API Development Ecosystem
|
|
||||||
</h3>
|
|
||||||
<p class="text-lg my-4 text-secondaryLight max-w-4/5">
|
|
||||||
Millions of developers and companies build, ship, and maintain their
|
|
||||||
APIs on Hoppscotch — the largest and most advanced development platform
|
|
||||||
in the world.
|
|
||||||
</p>
|
|
||||||
<div class="my-8 flex items-center">
|
|
||||||
<button class="button rounded-2xl text-xl">Get Started</button>
|
|
||||||
<button class="button icon rounded-2xl text-xl">Login</button>
|
|
||||||
<AppGitHubStarButton class="ml-8" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<AppGlobe />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
7
plugins/formatCountry.js
Normal file
7
plugins/formatCountry.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import Vue from "vue"
|
||||||
|
|
||||||
|
Vue.filter("formatCountry", (countryCode) =>
|
||||||
|
String.fromCodePoint(
|
||||||
|
...[...countryCode.toUpperCase()].map((x) => 0x1f1a5 + x.charCodeAt())
|
||||||
|
)
|
||||||
|
)
|
||||||
5
plugins/v-tippy.js
Normal file
5
plugins/v-tippy.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import Vue from "vue"
|
||||||
|
import VueTippy, { TippyComponent } from "vue-tippy"
|
||||||
|
|
||||||
|
Vue.use(VueTippy)
|
||||||
|
Vue.component("Tippy", TippyComponent)
|
||||||
Reference in New Issue
Block a user