Next.jsReact企业官网

flight-kiosk-widget — Next.js 企业官网模板

作者 tovrr

面向实体店铺的自助机票预订终端模板,基于 Next.js 构建,通过 Travelpayouts 联盟链接赚取佣金,支持平板全屏 kiosk 模式与网站嵌入。

看看你的网站会是什么样

浏览真实页面截图,比较内容排版与手机效果。点击下方缩略图切换,放大查看整页细节。

2 个预览视图
桌面端首页1 / 2
桌面端截图首屏预览

由服务器浏览器实际访问页面后截取。

全部页面与视图 2

截图用于了解视觉与布局,交互效果请以实际项目为准。

采集于 2026-10-02查看来源

值得关注的模板亮点

从已有项目资料中,快速了解它的特点。

01

平板全屏 kiosk 模式,锁定视口、无滚动,并带闲置自动重置

02

通过 URL 中的 ?ref= 参数按店铺追踪,佣金由 Travelpayouts 联盟计划结算

03

提供 /embed 路由与 embed.js,可用一行 script 标签嵌入现有网站

04

断网时显示重试卡片,service worker 缓存应用外壳,屏幕保持常亮

05

品牌名、颜色、语言、货币、闲置时间等均通过环境变量配置

06

内置英语、法语、荷兰语,支持 PWA 安装

模板详细介绍

这是一个面向实体店铺的自助机票预订终端(kiosk)模板。顾客在平板或 iPad 上全屏搜索、比价并跳转到合作方完成预订,店铺通过 URL 中的 ?ref= 参数被追踪,佣金由 Travelpayouts 联盟计划结算。项目本身不处理支付,也不收集姓名、邮箱等个人数据,仅在 localStorage 中保存店铺 ref 代码用于归因。

模板通过环境变量完成品牌名、颜色、语言、货币、闲置重置时间等配置,无需改动代码。除全屏 kiosk 外,还提供 /embed 路由与 embed.js,可用一行 script 标签把搜索组件嵌入任意网站。内置英语、法语、荷兰语三种语言,并支持 PWA 安装。

使用前需要自行注册 Travelpayouts 账号,获取 marker 与 Flights Search Form 的 trs 标识,并填入环境变量。由于 NEXT_PUBLIC_* 变量在构建时写入客户端包,修改后需要重新部署。

Next.js企业官网

适合你的项目吗?

适用场景

  • 实体店铺在平板或 iPad 上放置全屏机票搜索终端,顾客自助查询并跳转预订
  • 把机票搜索组件以 iframe 形式嵌入已有网站,按店铺或渠道追踪转化
  • 需要按不同店铺或子渠道区分佣金来源的联盟营销场景
  • 在店内网络不稳定时仍希望展示可重试的搜索入口

适合人群

  • 拥有实体门店并希望增加机票预订佣金收入的商家
  • 已注册或计划注册 Travelpayouts 的联盟营销人员
  • 需要快速部署品牌化机票搜索终端、不想从零开发的前端开发者
  • 希望把机票搜索嵌入现有网站并保留渠道追踪的运营方

上手与定制指南

结合仓库当前版本的说明,按下面的资料检查内容、配置与运行要求。

  1. 1

    需先注册 Travelpayouts 账号,获取 marker 与 Flights Search Form 的 trs,并填入对应环境变量

  2. 2

    NEXT_PUBLIC_* 变量在构建时写入客户端包,修改后需重新部署并关闭构建缓存

  3. 3

    本地开发可复制 .env.example 为 .env.local,运行 npm install 与 npm run dev

  4. 4

    Travelpayouts 组件脚本从 tpwidg.com 加载,网络受限时会显示离线回退

  5. 5

    演示中的搜索组件为模拟内容,生产环境会替换为真实的 Travelpayouts 表单

查看仓库使用说明

授权与来源资料

使用条件与限制

免费使用 · 保留许可声明

本次收录的是公开仓库中采用 MIT 许可的免费版本;免费范围为该版本代码,不代表外部服务或第三方素材免费。

使用时需要遵守

  • 允许免费使用、修改、商用和分发该版本代码。
  • 分发代码副本或实质性部分时,保留原作者版权声明和完整 MIT 许可声明。
  • 代码按现状提供;担保与责任限制以原许可证及适用法律为准。

额外费用与待核对事项

  • 使用前必须注册 Travelpayouts 账号,并获取 marker 与 Flights Search Form 的 trs 标识填入环境变量,否则无法正常展示搜索组件。
  • 必须提供 Travelpayouts 的 partner marker 与 trs 等凭据,属于外部服务依赖,非纯本地即可运行。
  • 搜索组件脚本从第三方域名 tpwidg.com 加载,网络受限或被屏蔽时会显示离线回退,无法正常搜索。
  • NEXT_PUBLIC_* 变量在构建时写入客户端包,修改后必须重新部署并关闭构建缓存,无法运行时热更新。
  • README 中的 Travelpayouts 注册链接带有维护者的推荐 marker,通过该链接注册会为维护者带来推荐收益(不影响用户佣金)。
  • 演示图片、字体、图标及其他第三方素材需按各自许可核对,不能仅凭代码的 MIT 许可判断。
  • 域名、托管、数据库、支付或 AI 等外部服务可能另外收费。
查看原文依据

Permission is hereby granted, free of charge

许可证原文

Create a free Travelpayouts account

README 原文

your **marker / Partner ID** → `NEXT_PUBLIC_TRAVELPAYOUTS_MARKER`

README 原文

The Travelpayouts widget loads its script from `tpwidg.com`

README 原文

changing them later requires a redeploy

README 原文

the Travelpayouts sign-up link above carries the > maintainer's *refer-a-partner* marker

README 原文
https://github.com/tovrr/flight-kiosk-widget/blob/main/LICENSEhttps://github.com/tovrr/flight-kiosk-widget/blob/main/README.md

DeepSeek 根据仓库许可证和 README 整理 ·2026-10-02。结果仅覆盖已读取资料,依赖、图片、字体及后续条款变更以各自原文为准。

项目核对记录与介绍依据

模板资料

来源平台
GitHub
资料与维护参考分
资料较完整 · 80 / 100
技术栈
Next.js · React
网站类型
企业官网
这个分数如何计算

本站按许可资料(最高30分)、演示链接(12分)、预览图(10分)、Star数(15分)、记录的维护时间(15分)、描述完整度(8分)、功能记录(5分)和分类资料(5分)计算。它不是代码、安全或性能测试,也不是 Google 评分;有链接不代表已实测可用。

这个项目需要核对什么

记录的仓库更新时间
2026-09-13
截图检查日期
2026-10-02

已收录演示链接。请用你的内容与屏幕尺寸检查;有演示不代表表单、认证或支付已经可用。

目录记录的主要技术栈是 Next.js。请通过依赖清单和锁文件核对实际版本与托管要求。这些说明基于收录资料,不代表代码审计或部署实测。

查看具体选型方法 →

介绍的制作与核对状态

介绍由 AI 辅助整理目录与仓库资料。仓库作者不等于这篇介绍的审核者。

已完成服务器许可规则与 AI 来源核对;未经过人工编辑审核。

查看当时使用的来源资料

SHA-256: 4c974969f0c072d604c597ec41ac966d990c5ca04a0825aaaeca7f6b5188131c

2026-10-02T07:24:14.143Z

来源文件 / 仓库
# Flight Kiosk Widget

<p align="center">
  <a href="https://vercel.com/new/clone?repository-url=https://github.com/tovrr/flight-kiosk-widget">
    <img src="https://vercel.com/button" alt="Deploy with Vercel" height="34">
  </a>
  &nbsp;
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-black.svg" alt="MIT License"></a>
  <img src="https://img.shields.io/badge/Next.js-16-black?logo=nextdotjs&logoColor=white" alt="Next.js 16">
  <img src="https://img.shields.io/badge/Travelpayouts-affiliate-ffe800?labelColor=0a0a0a" alt="Travelpayouts affiliate">
</p>

A self-service **flight-booking kiosk** for physical shops — designed to run
fullscreen on a tablet/iPad in kiosk mode. A customer searches for a flight,
compares prices, and books, while the partner shop is tracked via a `?ref=`
in the URL. Monetisation is
**[Travelpayouts](https://www.travelpayouts.com/?marker=749997) affiliate**
(you earn a commission on every booking).

Fork it, plug in your own Travelpayouts IDs, set a brand, and deploy — no code
changes required. Everything is configured through environment variables.

![Flight Kiosk — booking screen with search widget, per-shop tracking badge and mobile-continuity QR](docs/screenshot.png)

<p align="center"><em>Booking screen · the attract screen shown between customers 👇</em></p>

![Flight Kiosk — attract screen](docs/attract.png)

> The widget above is rendered from a mock in this demo; in production the real
> Travelpayouts flight-search form loads in its place.

---

## 💸 Deploy your own & earn — in 5 minutes

> 🏗️ Built by [**DevForge Systems**](https://devforge.systems) — enterprise software development, from build to deploy.

Every flight booked through your kiosk pays **you** an affiliate commission via
Travelpayouts. This template is the fastest way to get a branded,
production-ready booking kiosk (or an embeddable widget) live — **no code, just
environment variables**.

<p align="center">
  <a href="https://vercel.com/new/clone?repository-url=https://github.com/tovrr/flight-kiosk-widget">
    <img src="https://vercel.com/button" alt="Deploy with Vercel" height="34">
  </a>
</p>

1. **[Create a free Travelpayouts account](https://www.travelpayouts.com/?marker=749997)** and grab your marker + a Flights Search Form `trs`.
2. **Deploy** (one click above), paste those two values as env vars.
3. **Put a tablet in a shop** — or drop the `<script>` on any site — and earn on every booking. You keep **100 % of the affiliate commission**.

> **Transparency:** the Travelpayouts sign-up link above carries the
> maintainer's *refer-a-partner* marker. It costs you **nothing** and does **not**
> reduce your commissions — Travelpayouts simply shares a small slice of *their*
> own margin with the referrer. Prefer not to? Just sign up directly at
> [travelpayouts.com](https://www.travelpayouts.com/). Either way, the code is
> yours under MIT.

---

## Features

- **Kiosk mode** — fullscreen, no scroll, locked viewport, tablet-first.
- **Attract screen** ("Touch to start") + **idle reset** between customers.
- **Travelpayouts flight-search widget** with per-shop tracking (`shmarker`),
  no Aviasales logo / "Powered by".
- **Offline fallback** — a clean "service unavailable / retry" card when the
  in-store wifi drops, instead of an empty frame.
- **Mobile-continuity QR** — the customer scans it to finish on their phone,
  keeping the shop `?ref=` intact.
- **Optional "Popular flights"** button to your results / White Label page.
- **Embeddable** on any website with a one-line `<script>` (`/embed` + `embed.js`).
- Fully **rebrandable** (name + colours) via env vars, **installable PWA**.
- **Resilient by design** — service worker caches the app shell (reloads offline
  if the wifi drops), self-healing error screen, and the screen stays awake.
- **Built-in languages** (EN / FR / NL) via `NEXT_PUBLIC_LOCALE`.

---

## How the affiliate model works

1. A shop's kiosk URL carries its name: `https://your-app.com/?ref=shop-name`.
2. That `ref` is stored and folded into the Travelpayouts marker as
   `MARKER.shop-name` (`shmarker`), so every booking is traced to the shop.
3. The customer searches → is redirected to the results page → books with the
   seller. **Travelpayouts pays you the commission** (marker), and you know
   which shop drove it (sub-marker).

---

## Deploy your own

### 1. Get a Travelpayouts account

Sign up at [travelpayouts.com](https://www.travelpayouts.com/?marker=749997).
From the dashboard you need:

- your **marker / Partner ID** → `NEXT_PUBLIC_TRAVELPAYOUTS_MARKER`
- a **"Flights Search Form"** widget → copy its **`trs`** →
  `NEXT_PUBLIC_TP_TRS`
- *(optional)* the **Drive** domain-verification script URL →
  `NEXT_PUBLIC_TP_DRIVE_SRC`
- *(optional)* a **White Label** domain for branded results →
  `NEXT_PUBLIC_TP_SEARCH_URL` / `NEXT_PUBLIC_RESULTS_URL`

### 2. One-click deploy (Vercel)

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/tovrr/flight-kiosk-widget)

Set the environment variables (see below) during the import, then deploy.
Because `NEXT_PUBLIC_*` values are baked in at build time, **changing them
later requires a redeploy** (uncheck "Use existing Build Cache").

### 3. Point your kiosk at it

Open the deployed URL with a shop ref, e.g.
`https://your-app.com/?ref=shop-name`, and put the tablet in guided-access /
kiosk mode.

---

## Embed on an existing website

Besides the full-screen kiosk, the search widget can be dropped into any
website with **one line** — like a Calendly/Typeform embed:

```html
<script src="https://your-app.com/embed.js" data-ref="your-shop" async></script>
```

- Injects a responsive `<iframe>` of the flight-search widget right where the
  script is placed (or into `data-target="#some-element"`).
- Auto-resizes to its content height, transparent background to blend in.
- Tracked by `data-ref` (same `?ref=` → marker model as the kiosk).

The widget lives at `/embed?ref=...` and is the only route allowed to be framed
by third-party sites (every other route stays `X-Frame-Options: SAMEORIGIN`).

---

## Environment variables

| Variable | Required | Default | Role |
| --- | :---: | --- | --- |
| `NEXT_PUBLIC_TRAVELPAYOUTS_MARKER` | ✅ | `000000` | Your partner marker (base of `shmarker`). Placeholder = no attribution. |
| `NEXT_PUBLIC_TP_TRS` | ✅ | — | Tracking source id of your Flights Search Form widget. |
| `NEXT_PUBLIC_TP_DRIVE_SRC` | | — | Drive domain-verification script URL (injected only if set). |
| `NEXT_PUBLIC_TP_SEARCH_URL` | | — | Host (no protocol) where results open, e.g. your White Label. |
| `NEXT_PUBLIC_SHOW_HOTELS` | | `false` | Show the "also search hotels" checkbox in the flight widget. |
| `NEXT_PUBLIC_BRAND_PREFIX` | | `Flight` | Brand name, first tone (foreground). |
| `NEXT_PUBLIC_BRAND_SUFFIX` | | `Kiosk` | Brand name, second tone (accent). |
| `NEXT_PUBLIC_COLOR_PRIMARY` | | `#0A0A0A` | Widget primary colour. |
| `NEXT_PUBLIC_COLOR_ACCENT` | | `#FFE800` | Widget accent colour. |
| `NEXT_PUBLIC_SITE_URL` | | current origin | Canonical URL for the mobile-continue QR. |
| `NEXT_PUBLIC_RESULTS_URL` | | — | Full URL for the "Popular flights" button (hidden if empty). |
| `NEXT_PUBLIC_LOCALE` | | `en` | Widget / page language. |
| `NEXT_PUBLIC_CURRENCY` | | `usd` | Widget currency. |
| `NEXT_PUBLIC_IDLE_TIMEOUT_MS` | | `90000` | Idle delay before the kiosk resets. |

> ⚠️ These are **identifiers, not secrets** — they ship in the client bundle by
> design. **Never** put a Travelpayouts API token in a `NEXT_PUBLIC_*` variable.

---

## Local development

```bash
cp .env.example .env.local   # fill in your values
npm install
npm run dev                  # http://localhost:3000/?ref=demo-shop
npm run lint                 # ESLint (next/core-web-vitals)
npm test                     # unit tests (Vitest)
```

The Travelpayouts widget loads its script from `tpwidg.com`; if your network
blocks it you'll see the offline fallback — that's expected locally.

## Customisation

- **Name / colours** → env vars above. To also restyle the app chrome (not just
  the widget), edit the two colours in `app/globals.css` (Tailwind v4 `@theme`
  is static, so it can't read env at runtime).
- **Language** → set `NEXT_PUBLIC_LOCALE` (`en`, `fr`, `nl` built in). Add a
  locale by extending the dictionary in `lib/i18n.js`; the widget follows the
  same variable.
- **Icon** → replace `app/icon.svg` (also used as the PWA icon).

## Data & privacy

This app is a thin, brand-able shell around Travelpayouts — it runs almost no
logic of its own, and **collects no personal data**.

- **What it stores:** only the `?ref=` shop code, in `localStorage`, to keep
  per-shop attribution across a reload. No names, emails, accounts, or payment
  data — ever. No first-party tracking cookies.
- **What flows where:** the search widget and the results page are both hosted
  by **Travelpayouts**. When a visitor searches, only the **search query**
  (route, dates, passengers) and your **marker** are passed — via the URL — to
  the results page. There is no shared backend and no database.
- **Payments** happen on the airline/OTA's own checkout, never here, so there is
  no card handling or PCI scope.
- **Isolation:** every deployment uses its own marker/White Label (its own env
  vars). One fork can never read another's traffic or bookings.
- **`NEXT_PUBLIC_*` values are identifiers, not secrets** — they ship in the
  client bundle by design. Never put an API token in one.

Add your own privacy notice if your jurisdiction requires one; the third-party
Travelpayouts scripts have their own policy.

## Stack

Next.js 16 (App Router) · React 19 · Tailwind CSS 4 · `react-qr-code` ·
`lucide-react` · Node 22.

## License

[MIT](LICENSE) — do whatever you want, no warranty.
反馈内容错误

看看同类模板

对比同技术栈与用途的模板,找到更适合的视觉与内容结构。