♻️ Restructure: Move Astro to repository root
BREAKING CHANGE: Astro project is now at repository root - Removed dealplustech-astro subdirectory - Moved all Astro files to root - Updated PostCSS config to .cjs - Removed old Next.js files ✅ 11 pages built successfully ✅ Cookie consent banner included ✅ Privacy/Terms links in footer ✅ Ready for Easypanel deployment (no root dir needed) Migration path: - Old structure: /dealplustech-astro/ - New structure: / (root)
This commit is contained in:
@@ -1 +0,0 @@
|
||||
export default new Map();
|
||||
@@ -1 +0,0 @@
|
||||
export default new Map();
|
||||
207
dealplustech-astro/.astro/content.d.ts
vendored
207
dealplustech-astro/.astro/content.d.ts
vendored
@@ -1,207 +0,0 @@
|
||||
declare module 'astro:content' {
|
||||
export interface RenderResult {
|
||||
Content: import('astro/runtime/server/index.js').AstroComponentFactory;
|
||||
headings: import('astro').MarkdownHeading[];
|
||||
remarkPluginFrontmatter: Record<string, any>;
|
||||
}
|
||||
interface Render {
|
||||
'.md': Promise<RenderResult>;
|
||||
}
|
||||
|
||||
export interface RenderedContent {
|
||||
html: string;
|
||||
metadata?: {
|
||||
imagePaths: Array<string>;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'astro:content' {
|
||||
type Flatten<T> = T extends { [K: string]: infer U } ? U : never;
|
||||
|
||||
export type CollectionKey = keyof AnyEntryMap;
|
||||
export type CollectionEntry<C extends CollectionKey> = Flatten<AnyEntryMap[C]>;
|
||||
|
||||
export type ContentCollectionKey = keyof ContentEntryMap;
|
||||
export type DataCollectionKey = keyof DataEntryMap;
|
||||
|
||||
type AllValuesOf<T> = T extends any ? T[keyof T] : never;
|
||||
type ValidContentEntrySlug<C extends keyof ContentEntryMap> = AllValuesOf<
|
||||
ContentEntryMap[C]
|
||||
>['slug'];
|
||||
|
||||
export type ReferenceDataEntry<
|
||||
C extends CollectionKey,
|
||||
E extends keyof DataEntryMap[C] = string,
|
||||
> = {
|
||||
collection: C;
|
||||
id: E;
|
||||
};
|
||||
export type ReferenceContentEntry<
|
||||
C extends keyof ContentEntryMap,
|
||||
E extends ValidContentEntrySlug<C> | (string & {}) = string,
|
||||
> = {
|
||||
collection: C;
|
||||
slug: E;
|
||||
};
|
||||
export type ReferenceLiveEntry<C extends keyof LiveContentConfig['collections']> = {
|
||||
collection: C;
|
||||
id: string;
|
||||
};
|
||||
|
||||
/** @deprecated Use `getEntry` instead. */
|
||||
export function getEntryBySlug<
|
||||
C extends keyof ContentEntryMap,
|
||||
E extends ValidContentEntrySlug<C> | (string & {}),
|
||||
>(
|
||||
collection: C,
|
||||
// Note that this has to accept a regular string too, for SSR
|
||||
entrySlug: E,
|
||||
): E extends ValidContentEntrySlug<C>
|
||||
? Promise<CollectionEntry<C>>
|
||||
: Promise<CollectionEntry<C> | undefined>;
|
||||
|
||||
/** @deprecated Use `getEntry` instead. */
|
||||
export function getDataEntryById<C extends keyof DataEntryMap, E extends keyof DataEntryMap[C]>(
|
||||
collection: C,
|
||||
entryId: E,
|
||||
): Promise<CollectionEntry<C>>;
|
||||
|
||||
export function getCollection<C extends keyof AnyEntryMap, E extends CollectionEntry<C>>(
|
||||
collection: C,
|
||||
filter?: (entry: CollectionEntry<C>) => entry is E,
|
||||
): Promise<E[]>;
|
||||
export function getCollection<C extends keyof AnyEntryMap>(
|
||||
collection: C,
|
||||
filter?: (entry: CollectionEntry<C>) => unknown,
|
||||
): Promise<CollectionEntry<C>[]>;
|
||||
|
||||
export function getLiveCollection<C extends keyof LiveContentConfig['collections']>(
|
||||
collection: C,
|
||||
filter?: LiveLoaderCollectionFilterType<C>,
|
||||
): Promise<
|
||||
import('astro').LiveDataCollectionResult<LiveLoaderDataType<C>, LiveLoaderErrorType<C>>
|
||||
>;
|
||||
|
||||
export function getEntry<
|
||||
C extends keyof ContentEntryMap,
|
||||
E extends ValidContentEntrySlug<C> | (string & {}),
|
||||
>(
|
||||
entry: ReferenceContentEntry<C, E>,
|
||||
): E extends ValidContentEntrySlug<C>
|
||||
? Promise<CollectionEntry<C>>
|
||||
: Promise<CollectionEntry<C> | undefined>;
|
||||
export function getEntry<
|
||||
C extends keyof DataEntryMap,
|
||||
E extends keyof DataEntryMap[C] | (string & {}),
|
||||
>(
|
||||
entry: ReferenceDataEntry<C, E>,
|
||||
): E extends keyof DataEntryMap[C]
|
||||
? Promise<DataEntryMap[C][E]>
|
||||
: Promise<CollectionEntry<C> | undefined>;
|
||||
export function getEntry<
|
||||
C extends keyof ContentEntryMap,
|
||||
E extends ValidContentEntrySlug<C> | (string & {}),
|
||||
>(
|
||||
collection: C,
|
||||
slug: E,
|
||||
): E extends ValidContentEntrySlug<C>
|
||||
? Promise<CollectionEntry<C>>
|
||||
: Promise<CollectionEntry<C> | undefined>;
|
||||
export function getEntry<
|
||||
C extends keyof DataEntryMap,
|
||||
E extends keyof DataEntryMap[C] | (string & {}),
|
||||
>(
|
||||
collection: C,
|
||||
id: E,
|
||||
): E extends keyof DataEntryMap[C]
|
||||
? string extends keyof DataEntryMap[C]
|
||||
? Promise<DataEntryMap[C][E]> | undefined
|
||||
: Promise<DataEntryMap[C][E]>
|
||||
: Promise<CollectionEntry<C> | undefined>;
|
||||
export function getLiveEntry<C extends keyof LiveContentConfig['collections']>(
|
||||
collection: C,
|
||||
filter: string | LiveLoaderEntryFilterType<C>,
|
||||
): Promise<import('astro').LiveDataEntryResult<LiveLoaderDataType<C>, LiveLoaderErrorType<C>>>;
|
||||
|
||||
/** Resolve an array of entry references from the same collection */
|
||||
export function getEntries<C extends keyof ContentEntryMap>(
|
||||
entries: ReferenceContentEntry<C, ValidContentEntrySlug<C>>[],
|
||||
): Promise<CollectionEntry<C>[]>;
|
||||
export function getEntries<C extends keyof DataEntryMap>(
|
||||
entries: ReferenceDataEntry<C, keyof DataEntryMap[C]>[],
|
||||
): Promise<CollectionEntry<C>[]>;
|
||||
|
||||
export function render<C extends keyof AnyEntryMap>(
|
||||
entry: AnyEntryMap[C][string],
|
||||
): Promise<RenderResult>;
|
||||
|
||||
export function reference<C extends keyof AnyEntryMap>(
|
||||
collection: C,
|
||||
): import('astro/zod').ZodEffects<
|
||||
import('astro/zod').ZodString,
|
||||
C extends keyof ContentEntryMap
|
||||
? ReferenceContentEntry<C, ValidContentEntrySlug<C>>
|
||||
: ReferenceDataEntry<C, keyof DataEntryMap[C]>
|
||||
>;
|
||||
// Allow generic `string` to avoid excessive type errors in the config
|
||||
// if `dev` is not running to update as you edit.
|
||||
// Invalid collection names will be caught at build time.
|
||||
export function reference<C extends string>(
|
||||
collection: C,
|
||||
): import('astro/zod').ZodEffects<import('astro/zod').ZodString, never>;
|
||||
|
||||
type ReturnTypeOrOriginal<T> = T extends (...args: any[]) => infer R ? R : T;
|
||||
type InferEntrySchema<C extends keyof AnyEntryMap> = import('astro/zod').infer<
|
||||
ReturnTypeOrOriginal<Required<ContentConfig['collections'][C]>['schema']>
|
||||
>;
|
||||
|
||||
type ContentEntryMap = {
|
||||
|
||||
};
|
||||
|
||||
type DataEntryMap = {
|
||||
"blog": Record<string, {
|
||||
id: string;
|
||||
body?: string;
|
||||
collection: "blog";
|
||||
data: any;
|
||||
rendered?: RenderedContent;
|
||||
filePath?: string;
|
||||
}>;
|
||||
|
||||
};
|
||||
|
||||
type AnyEntryMap = ContentEntryMap & DataEntryMap;
|
||||
|
||||
type ExtractLoaderTypes<T> = T extends import('astro/loaders').LiveLoader<
|
||||
infer TData,
|
||||
infer TEntryFilter,
|
||||
infer TCollectionFilter,
|
||||
infer TError
|
||||
>
|
||||
? { data: TData; entryFilter: TEntryFilter; collectionFilter: TCollectionFilter; error: TError }
|
||||
: { data: never; entryFilter: never; collectionFilter: never; error: never };
|
||||
type ExtractDataType<T> = ExtractLoaderTypes<T>['data'];
|
||||
type ExtractEntryFilterType<T> = ExtractLoaderTypes<T>['entryFilter'];
|
||||
type ExtractCollectionFilterType<T> = ExtractLoaderTypes<T>['collectionFilter'];
|
||||
type ExtractErrorType<T> = ExtractLoaderTypes<T>['error'];
|
||||
|
||||
type LiveLoaderDataType<C extends keyof LiveContentConfig['collections']> =
|
||||
LiveContentConfig['collections'][C]['schema'] extends undefined
|
||||
? ExtractDataType<LiveContentConfig['collections'][C]['loader']>
|
||||
: import('astro/zod').infer<
|
||||
Exclude<LiveContentConfig['collections'][C]['schema'], undefined>
|
||||
>;
|
||||
type LiveLoaderEntryFilterType<C extends keyof LiveContentConfig['collections']> =
|
||||
ExtractEntryFilterType<LiveContentConfig['collections'][C]['loader']>;
|
||||
type LiveLoaderCollectionFilterType<C extends keyof LiveContentConfig['collections']> =
|
||||
ExtractCollectionFilterType<LiveContentConfig['collections'][C]['loader']>;
|
||||
type LiveLoaderErrorType<C extends keyof LiveContentConfig['collections']> = ExtractErrorType<
|
||||
LiveContentConfig['collections'][C]['loader']
|
||||
>;
|
||||
|
||||
export type ContentConfig = typeof import("../src/content.config.mjs");
|
||||
export type LiveContentConfig = never;
|
||||
}
|
||||
2
dealplustech-astro/.astro/types.d.ts
vendored
2
dealplustech-astro/.astro/types.d.ts
vendored
@@ -1,2 +0,0 @@
|
||||
/// <reference types="astro/client" />
|
||||
/// <reference path="content.d.ts" />
|
||||
@@ -1,14 +0,0 @@
|
||||
# Astro Production Dockerfile
|
||||
FROM node:20-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm ci --omit=dev
|
||||
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
EXPOSE 4321
|
||||
|
||||
CMD ["npm", "run", "preview", "--", "--host", "0.0.0.0", "--port", "4321"]
|
||||
@@ -1,7 +0,0 @@
|
||||
node_modules
|
||||
dist
|
||||
.git
|
||||
.gitignore
|
||||
*.md
|
||||
.env*
|
||||
!package*.json
|
||||
1
dealplustech-astro/.gitignore
vendored
1
dealplustech-astro/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
.node-version
|
||||
@@ -1,221 +0,0 @@
|
||||
# 🔬 Easypanel API Testing Results
|
||||
|
||||
## ✅ What Works
|
||||
|
||||
### 1. Authentication
|
||||
```bash
|
||||
curl -H "Authorization: Bearer TOKEN" \
|
||||
http://110.164.146.46:3000/api/trpc/setup.getStatus
|
||||
# ✅ Returns: {"result":{"data":{"json":{"isComplete":true}}}}
|
||||
```
|
||||
|
||||
### 2. List Projects
|
||||
```bash
|
||||
curl -H "Authorization: Bearer TOKEN" \
|
||||
http://110.164.146.46:3000/api/trpc/projects.listProjectsAndServices
|
||||
# ✅ Returns project list including "customerwebsite"
|
||||
```
|
||||
|
||||
### 3. Inspect Service
|
||||
```bash
|
||||
curl -H "Authorization: Bearer TOKEN" \
|
||||
http://110.164.146.46:3000/api/trpc/services.app.inspectService
|
||||
# ✅ Works when service exists
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❌ What Fails - Service Creation
|
||||
|
||||
### Endpoint
|
||||
```
|
||||
POST /api/trpc/services.app.createService
|
||||
```
|
||||
|
||||
### Schema (from OpenAPI)
|
||||
```json
|
||||
{
|
||||
"input": {
|
||||
"json": {
|
||||
"projectName": "customerwebsite",
|
||||
"serviceName": "my-app",
|
||||
"source": {
|
||||
"type": "image" | "github",
|
||||
// For "image":
|
||||
"image": "nginx:alpine",
|
||||
"username": "...",
|
||||
"password": "...",
|
||||
// For "github":
|
||||
"owner": "...",
|
||||
"repo": "...",
|
||||
"ref": "main",
|
||||
"path": "..."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Attempts & Errors
|
||||
|
||||
#### Attempt 1: Basic Image
|
||||
```json
|
||||
{
|
||||
"input": {
|
||||
"json": {
|
||||
"projectName": "customerwebsite",
|
||||
"serviceName": "test",
|
||||
"source": {
|
||||
"type": "image",
|
||||
"image": "nginx:alpine",
|
||||
"port": 80
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
**Result:** ❌ 500 Error
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"json": {
|
||||
"message": "[{\"code\":\"invalid_type\",\"expected\":\"object\",\"received\":\"undefined\",\"path\":[],\"message\":\"Required\"}]"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Attempt 2: With Git Source
|
||||
```json
|
||||
{
|
||||
"input": {
|
||||
"json": {
|
||||
"projectName": "customerwebsite",
|
||||
"serviceName": "test-git",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"repository": "http://...",
|
||||
"branch": "main"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
**Result:** ❌ Same "Required" error
|
||||
|
||||
#### Attempt 3: Using `project` instead of `projectName`
|
||||
```json
|
||||
{
|
||||
"input": {
|
||||
"json": {
|
||||
"project": "customerwebsite",
|
||||
"name": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
**Result:** ❌ Same error
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Analysis
|
||||
|
||||
The Zod validation error `"expected":"object","received":"undefined","path":[]` suggests:
|
||||
|
||||
1. **Missing required field** at root level
|
||||
2. **Schema mismatch** - the API expects additional fields not in OpenAPI spec
|
||||
3. **Possible tRPC format issue** - Easypanel might use a different input format
|
||||
|
||||
---
|
||||
|
||||
## 💡 Hypothesis
|
||||
|
||||
Easypanel's `createService` endpoint might require:
|
||||
|
||||
### Option A: Additional Required Fields
|
||||
```json
|
||||
{
|
||||
"input": {
|
||||
"json": {
|
||||
"projectName": "...",
|
||||
"serviceName": "...",
|
||||
"source": {...},
|
||||
// Missing required fields:
|
||||
"environmentVariables": [],
|
||||
"domains": [],
|
||||
"ports": [],
|
||||
"mounts": []
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Option B: Different tRPC Format
|
||||
```json
|
||||
{
|
||||
"type": "query",
|
||||
"input": {...}
|
||||
}
|
||||
```
|
||||
|
||||
### Option C: Requires Project ID (not name)
|
||||
```json
|
||||
{
|
||||
"input": {
|
||||
"json": {
|
||||
"project": "cmkw22b00000007tu4gim48q9", // Actual ID
|
||||
"name": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Next Steps to Debug
|
||||
|
||||
### 1. Capture Browser Network Traffic
|
||||
1. Open Easypanel dashboard
|
||||
2. Open DevTools → Network tab
|
||||
3. Create a service manually
|
||||
4. Inspect the exact API request
|
||||
5. Copy request payload
|
||||
|
||||
### 2. Test with cURL
|
||||
Use the exact payload from browser
|
||||
|
||||
### 3. Alternative: Use Easypanel CLI (if exists)
|
||||
Check if Easypanel provides official CLI
|
||||
|
||||
### 4. Contact Easypanel Support
|
||||
Ask for correct API schema for `services.app.createService`
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Current Recommendation
|
||||
|
||||
Until API is figured out, use **manual creation**:
|
||||
|
||||
1. **Create service via dashboard** (2 minutes)
|
||||
2. **Copy service ID**
|
||||
3. **Register with skill**: `./deploy.sh register SERVICE_ID`
|
||||
4. **Future updates**: Automated via `./deploy.sh update`
|
||||
|
||||
This is still 80% automated!
|
||||
|
||||
---
|
||||
|
||||
## 📞 Need Your Help
|
||||
|
||||
**Can you:**
|
||||
1. Open browser DevTools when creating service in Easypanel
|
||||
2. Copy the exact API request payload
|
||||
3. Share it so I can update the skill?
|
||||
|
||||
Or if you know the correct schema, let me know!
|
||||
|
||||
---
|
||||
|
||||
**Status:** ⚠️ API schema unclear
|
||||
**Workaround:** Manual creation + automated updates
|
||||
**Automation Level:** 80% (will be 100% with correct schema)
|
||||
@@ -1,132 +0,0 @@
|
||||
# 🚀 Fully Automated Deployment - v5.0
|
||||
|
||||
## ✅ Complete Workflow
|
||||
|
||||
The skill now automates ALL steps:
|
||||
|
||||
### Step 1: Create Service
|
||||
```bash
|
||||
POST /api/trpc/services.app.createService
|
||||
{
|
||||
"json": {
|
||||
"projectName": "customerwebsite",
|
||||
"domains": [{"host": "$(EASYPANEL_DOMAIN)"}],
|
||||
"serviceName": "dealplustech-astro"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Configure Git
|
||||
```bash
|
||||
POST /api/trpc/services.app.updateSourceGit
|
||||
{
|
||||
"json": {
|
||||
"projectName": "customerwebsite",
|
||||
"serviceName": "dealplustech-astro",
|
||||
"repo": "http://110.164.146.46:3001/dealplustech/dealplustech-astro.git",
|
||||
"ref": "main",
|
||||
"path": "/"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Set Build Type
|
||||
```bash
|
||||
POST /api/trpc/services.app.updateBuild
|
||||
{
|
||||
"json": {
|
||||
"projectName": "customerwebsite",
|
||||
"serviceName": "dealplustech-astro",
|
||||
"build": {"type": "nixpacks"}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Get Primary Domain
|
||||
```bash
|
||||
GET /api/trpc/domains.getPrimaryDomain
|
||||
{
|
||||
"json": {
|
||||
"projectName": "customerwebsite",
|
||||
"serviceName": "dealplustech-astro"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: Wait for Deployment
|
||||
- Polls service status every 10 seconds
|
||||
- Waits up to 5 minutes (30 attempts)
|
||||
- Reports when status is "running" or "ready"
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Usage
|
||||
|
||||
### First Deployment
|
||||
```bash
|
||||
cd dealplustech-astro
|
||||
./skills/easypanel-deploy/deploy.sh deploy
|
||||
```
|
||||
|
||||
**That's it!** The script handles everything automatically!
|
||||
|
||||
### Redeploy After Changes
|
||||
```bash
|
||||
git push # Push your changes
|
||||
./skills/easypanel-deploy/deploy.sh redeploy # Trigger redeploy
|
||||
```
|
||||
|
||||
### Check Status
|
||||
```bash
|
||||
./skills/easypanel-deploy/deploy.sh status
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Benefits
|
||||
|
||||
| Feature | Before v5.0 | v5.0 |
|
||||
|---------|-------------|------|
|
||||
| Manual steps | 4-6 steps | **0 steps** |
|
||||
| Time required | 5-10 minutes | **1 command** |
|
||||
| API calls | N/A | **5 automated calls** |
|
||||
| Error handling | Manual | **Automatic** |
|
||||
| Wait for deploy | Manual | **Automatic** |
|
||||
| Domain info | Manual lookup | **Automatic** |
|
||||
|
||||
---
|
||||
|
||||
## 📋 What Happens
|
||||
|
||||
```
|
||||
1. ./deploy.sh deploy
|
||||
↓
|
||||
2. Creates service in Easypanel
|
||||
↓
|
||||
3. Configures Git repository
|
||||
↓
|
||||
4. Sets build type (nixpacks)
|
||||
↓
|
||||
5. Gets auto-generated domain
|
||||
↓
|
||||
6. Waits for deployment
|
||||
↓
|
||||
7. ✅ Deployment complete!
|
||||
```
|
||||
|
||||
**Zero manual steps!**
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Ready to Test!
|
||||
|
||||
```bash
|
||||
# Deploy now!
|
||||
./skills/easypanel-deploy/deploy.sh deploy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Status:** ✅ Fully Automated
|
||||
**Automation Level:** 100%
|
||||
**Manual Steps:** 0
|
||||
@@ -1,284 +0,0 @@
|
||||
# 🚀 Easypanel Deployment Guide
|
||||
|
||||
**Project:** Deal Plus Tech Astro Migration
|
||||
**Deployment Target:** Easypanel (Docker-based)
|
||||
**Build Command:** `npm run build`
|
||||
**Output:** Static site served via `npm run preview`
|
||||
|
||||
---
|
||||
|
||||
## 📋 Prerequisites
|
||||
|
||||
1. **Easypanel Account** - Access to Easypanel instance at `http://110.164.146.46:3000`
|
||||
2. **Git Repository** - Code pushed to Git (Gitea/GitHub/GitLab)
|
||||
3. **Domain** (optional) - Custom domain for production
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Deployment Steps
|
||||
|
||||
### Option 1: Deploy from Git Repository (Recommended)
|
||||
|
||||
#### Step 1: Connect Git Repository
|
||||
|
||||
1. Login to Easypanel: `http://110.164.146.46:3000`
|
||||
2. Click **"New Project"** or select existing project
|
||||
3. Click **"New Service"** → **"Git Repository"**
|
||||
4. Connect your Git provider (Gitea, GitHub, GitLab)
|
||||
5. Select repository: `dealplustech/dealplustech-astro`
|
||||
6. Select branch: `main`
|
||||
|
||||
#### Step 2: Configure Build Settings
|
||||
|
||||
**Build Configuration:**
|
||||
- **Build Command:** `npm run build`
|
||||
- **Publish Directory:** `dist`
|
||||
- **Dockerfile:** (Leave empty - uses auto-detection)
|
||||
- **Node Version:** `20`
|
||||
|
||||
**Environment Variables:**
|
||||
```bash
|
||||
NODE_ENV=production
|
||||
PORT=4321
|
||||
HOST=0.0.0.0
|
||||
```
|
||||
|
||||
#### Step 3: Deploy
|
||||
|
||||
1. Click **"Deploy"**
|
||||
2. Wait for build to complete (~2-3 minutes)
|
||||
3. Easypanel will automatically assign a URL (e.g., `dealplustech-astro.easypanel.app`)
|
||||
4. Test the deployment
|
||||
|
||||
#### Step 4: Auto-Deploy (Optional)
|
||||
|
||||
Enable auto-deploy on push:
|
||||
1. Go to Service Settings → **Git**
|
||||
2. Enable **"Auto Deploy"**
|
||||
3. Select branch: `main`
|
||||
|
||||
Now every push to `main` will trigger automatic deployment!
|
||||
|
||||
---
|
||||
|
||||
### Option 2: Deploy with Dockerfile
|
||||
|
||||
If you prefer using the provided Dockerfile:
|
||||
|
||||
#### Step 1: Build Docker Image Locally
|
||||
|
||||
```bash
|
||||
cd dealplustech-astro
|
||||
|
||||
# Build Docker image
|
||||
docker build -t dealplustech-astro:latest .
|
||||
|
||||
# Test locally
|
||||
docker run -p 4321:4321 dealplustech-astro:latest
|
||||
```
|
||||
|
||||
Visit `http://localhost:4321` to test
|
||||
|
||||
#### Step 2: Push to Container Registry
|
||||
|
||||
```bash
|
||||
# Tag for your registry
|
||||
docker tag dealplustech-astro:latest your-registry.com/dealplustech-astro:latest
|
||||
|
||||
# Push to registry
|
||||
docker push your-registry.com/dealplustech-astro:latest
|
||||
```
|
||||
|
||||
#### Step 3: Deploy on Easypanel
|
||||
|
||||
1. Login to Easypanel
|
||||
2. **New Service** → **"Docker Image"**
|
||||
3. Enter image URL: `your-registry.com/dealplustech-astro:latest`
|
||||
4. Configure port: `4321`
|
||||
5. Click **"Deploy"**
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Value | Description |
|
||||
|----------|-------|-------------|
|
||||
| `NODE_ENV` | `production` | Production mode |
|
||||
| `PORT` | `4321` | Astro preview server port |
|
||||
| `HOST` | `0.0.0.0` | Listen on all interfaces |
|
||||
|
||||
### Resource Allocation
|
||||
|
||||
**Recommended Resources:**
|
||||
- **CPU:** 0.5 - 1 vCPU
|
||||
- **Memory:** 512MB - 1GB
|
||||
- **Storage:** 1GB (for logs and assets)
|
||||
|
||||
### Custom Domain
|
||||
|
||||
To add a custom domain:
|
||||
|
||||
1. Go to Service Settings → **Domains**
|
||||
2. Click **"Add Domain"**
|
||||
3. Enter your domain: `dealplustech.co.th`
|
||||
4. Update DNS records:
|
||||
```
|
||||
Type: CNAME
|
||||
Name: www
|
||||
Value: your-easypanel-url.easypanel.app
|
||||
```
|
||||
5. Enable SSL (Easypanel provides auto-SSL)
|
||||
|
||||
---
|
||||
|
||||
## 📊 Monitoring
|
||||
|
||||
### Health Check
|
||||
|
||||
The Dockerfile includes a health check endpoint:
|
||||
- **URL:** `http://your-domain:4321/`
|
||||
- **Expected:** HTTP 200 OK
|
||||
|
||||
### Logs
|
||||
|
||||
View logs in Easypanel:
|
||||
1. Select Service
|
||||
2. Click **"Logs"** tab
|
||||
3. Filter by date/time
|
||||
|
||||
### Metrics
|
||||
|
||||
Easypanel provides:
|
||||
- CPU usage
|
||||
- Memory usage
|
||||
- Network traffic
|
||||
- Request count
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Update Deployment
|
||||
|
||||
### Automatic Updates (Git Auto-Deploy)
|
||||
|
||||
If auto-deploy is enabled:
|
||||
1. Push changes to `main` branch
|
||||
2. Easypanel automatically rebuilds
|
||||
3. New version deploys in ~2-3 minutes
|
||||
|
||||
### Manual Updates
|
||||
|
||||
1. Go to Service → **Deployments**
|
||||
2. Click **"Redeploy"**
|
||||
3. Select latest commit
|
||||
4. Click **"Deploy Now"**
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Build Fails
|
||||
|
||||
**Issue:** `npm run build` fails
|
||||
|
||||
**Solution:**
|
||||
1. Check build logs in Easypanel
|
||||
2. Verify `package.json` scripts
|
||||
3. Test build locally: `npm run build`
|
||||
4. Check Node version (must be 20+)
|
||||
|
||||
### 502 Bad Gateway
|
||||
|
||||
**Issue:** Service returns 502 error
|
||||
|
||||
**Solution:**
|
||||
1. Check if container is running
|
||||
2. Verify port is 4321
|
||||
3. Check health check endpoint
|
||||
4. Review container logs
|
||||
|
||||
### Static Assets Not Loading
|
||||
|
||||
**Issue:** Images/CSS return 404
|
||||
|
||||
**Solution:**
|
||||
1. Verify `public/` folder is copied in Dockerfile
|
||||
2. Check asset paths in code
|
||||
3. Rebuild and redeploy
|
||||
|
||||
---
|
||||
|
||||
## 📝 Post-Deployment Checklist
|
||||
|
||||
- [ ] Test homepage loads
|
||||
- [ ] Test product pages (6 products)
|
||||
- [ ] Test blog posts (3 posts)
|
||||
- [ ] Test mobile responsiveness
|
||||
- [ ] Verify FloatingContact buttons work
|
||||
- [ ] Test all navigation links
|
||||
- [ ] Check SEO metadata
|
||||
- [ ] Setup custom domain (if needed)
|
||||
- [ ] Enable SSL certificate
|
||||
- [ ] Configure CDN (optional)
|
||||
- [ ] Setup monitoring alerts
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Production Optimization
|
||||
|
||||
### Enable Compression
|
||||
|
||||
Easypanel automatically enables gzip compression for static assets.
|
||||
|
||||
### CDN Integration
|
||||
|
||||
For better performance:
|
||||
|
||||
1. Sign up for CDN (Cloudflare, BunnyCDN, etc.)
|
||||
2. Point CDN to Easypanel URL
|
||||
3. Update DNS to point to CDN
|
||||
4. Configure cache rules
|
||||
|
||||
### Caching Headers
|
||||
|
||||
Astro sets optimal cache headers by default:
|
||||
- **HTML:** No cache (always fresh)
|
||||
- **Assets:** 1 year (immutable)
|
||||
- **Images:** 1 year (immutable)
|
||||
|
||||
---
|
||||
|
||||
## 📞 Support
|
||||
|
||||
**Easypanel Documentation:** https://docs.easypanel.io
|
||||
**Astro Documentation:** https://docs.astro.build
|
||||
**Project Repository:** [Your Git Repo]
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Deploy Commands
|
||||
|
||||
```bash
|
||||
# Build locally
|
||||
npm run build
|
||||
|
||||
# Test production build locally
|
||||
npm run preview
|
||||
|
||||
# Build Docker image
|
||||
docker build -t dealplustech-astro:latest .
|
||||
|
||||
# Run Docker container
|
||||
docker run -p 4321:4321 dealplustech-astro:latest
|
||||
|
||||
# Push to registry
|
||||
docker push your-registry.com/dealplustech-astro:latest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Deployment Status:** ✅ Ready to Deploy
|
||||
**Estimated Deploy Time:** 2-3 minutes
|
||||
**First Deploy:** Manual
|
||||
**Subsequent Deploys:** Automatic (if enabled)
|
||||
@@ -1,118 +0,0 @@
|
||||
# 🚢 Image Deployment Options
|
||||
|
||||
## The Issue
|
||||
|
||||
When you built `dealplustech-astro:latest`, it's only on your **local Docker**. Easypanel server can't access it.
|
||||
|
||||
## ✅ Solutions
|
||||
|
||||
### Option 1: Easypanel Docker Registry (Recommended)
|
||||
|
||||
Easypanel provides a built-in Docker registry.
|
||||
|
||||
**Steps:**
|
||||
|
||||
```bash
|
||||
# 1. Get registry URL (usually SERVER_IP:3001)
|
||||
# For your setup: 110.164.146.46:3001
|
||||
|
||||
# 2. Login to registry
|
||||
docker login 110.164.146.46:3001
|
||||
# Use Easypanel credentials
|
||||
|
||||
# 3. Tag image
|
||||
docker tag dealplustech-astro:latest 110.164.146.46:3001/customerwebsite/dealplustech-astro:latest
|
||||
|
||||
# 4. Push
|
||||
docker push 110.164.146.46:3001/customerwebsite/dealplustech-astro:latest
|
||||
|
||||
# 5. In Easypanel dashboard, use:
|
||||
# Image: 110.164.146.46:3001/customerwebsite/dealplustech-astro:latest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Option 2: Docker Hub (Public)
|
||||
|
||||
```bash
|
||||
# Tag with your Docker Hub username
|
||||
docker tag dealplustech-astro:latest yourusername/dealplustech-astro:latest
|
||||
|
||||
# Push
|
||||
docker push yourusername/dealplustech-astro:latest
|
||||
|
||||
# In Easypanel, use:
|
||||
# Image: yourusername/dealplustech-astro:latest
|
||||
```
|
||||
|
||||
**Note:** Public repository - anyone can see it
|
||||
|
||||
---
|
||||
|
||||
### Option 3: Private Registry (Harbor, GitLab, etc.)
|
||||
|
||||
```bash
|
||||
# Tag for your registry
|
||||
docker tag dealplustech-astro:latest registry.yourcompany.com/project/dealplustech-astro:latest
|
||||
|
||||
# Login
|
||||
docker login registry.yourcompany.com
|
||||
|
||||
# Push
|
||||
docker push registry.yourcompany.com/project/dealplustech-astro:latest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Option 4: Direct Server Deployment
|
||||
|
||||
If you have SSH access to Easypanel server:
|
||||
|
||||
```bash
|
||||
# Export image
|
||||
docker save dealplustech-astro:latest > dealplustech-astro.tar
|
||||
|
||||
# Copy to server
|
||||
scp dealplustech-astro.tar user@110.164.146.46:/tmp/
|
||||
|
||||
# SSH to server and load
|
||||
ssh user@110.164.146.46
|
||||
docker load < /tmp/dealplustech-astro.tar
|
||||
|
||||
# In Easypanel, use:
|
||||
# Image: dealplustech-astro:latest (local)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Recommended for Your Setup
|
||||
|
||||
**Use Easypanel's built-in registry:**
|
||||
|
||||
```bash
|
||||
# 1. Login
|
||||
docker login 110.164.146.46:3001
|
||||
|
||||
# 2. Tag
|
||||
docker tag dealplustech-astro:latest 110.164.146.46:3001/customerwebsite/dealplustech-astro:latest
|
||||
|
||||
# 3. Push
|
||||
docker push 110.164.146.46:3001/customerwebsite/dealplustech-astro:latest
|
||||
|
||||
# 4. Create service in Easypanel with:
|
||||
# Image: 110.164.146.46:3001/customerwebsite/dealplustech-astro:latest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Checklist
|
||||
|
||||
- [ ] Choose registry option
|
||||
- [ ] Login to registry
|
||||
- [ ] Tag image correctly
|
||||
- [ ] Push to registry
|
||||
- [ ] Use full image name in Easypanel
|
||||
|
||||
---
|
||||
|
||||
**Next Step:** Push to Easypanel registry, then create service!
|
||||
@@ -1,177 +0,0 @@
|
||||
# 🚀 Deployment Summary & Next Steps
|
||||
|
||||
## ✅ What's Complete
|
||||
|
||||
### 1. Docker Image Built
|
||||
- **Image:** `dealplustech-astro:latest`
|
||||
- **Size:** ~564MB
|
||||
- **Status:** Ready to deploy
|
||||
|
||||
### 2. Easypanel Connection
|
||||
- **URL:** http://110.164.146.46:3000
|
||||
- **Token:** ✅ Configured
|
||||
- **Project Found:** `customerwebsite`
|
||||
|
||||
### 3. Skill Created
|
||||
- **Location:** `skills/easypanel-deploy/`
|
||||
- **Version:** 2.2
|
||||
- **Features:** State management, lifecycle control
|
||||
|
||||
---
|
||||
|
||||
## 📋 Manual Steps Required
|
||||
|
||||
Easypanel API has limitations for service creation. Follow these steps:
|
||||
|
||||
### Step 1: Create Service in Dashboard
|
||||
|
||||
1. **Open Easypanel:**
|
||||
```
|
||||
http://110.164.146.46:3000
|
||||
```
|
||||
|
||||
2. **Select Project:**
|
||||
- Click on: `customerwebsite`
|
||||
|
||||
3. **Create New Service:**
|
||||
- Click: **"New Service"**
|
||||
- Choose: **"Docker image"**
|
||||
|
||||
4. **Configure Service:**
|
||||
```
|
||||
Name: dealplustech-astro
|
||||
Image: dealplustech-astro:latest
|
||||
Port: 4321
|
||||
```
|
||||
|
||||
5. **Deploy:**
|
||||
- Click: **"Create"** or **"Deploy"**
|
||||
- Wait for deployment (~2-3 minutes)
|
||||
|
||||
6. **Copy Service ID:**
|
||||
- Go to service settings
|
||||
- Copy the ID (looks like: `svc_abc123...`)
|
||||
|
||||
### Step 2: Register Service ID
|
||||
|
||||
```bash
|
||||
cd dealplustech-astro
|
||||
|
||||
# Register the service ID you copied
|
||||
./skills/easypanel-deploy/deploy.sh register svc_abc123...
|
||||
```
|
||||
|
||||
### Step 3: Verify
|
||||
|
||||
```bash
|
||||
# Check status
|
||||
./skills/easypanel-deploy/deploy.sh status
|
||||
|
||||
# Should show:
|
||||
# ✅ Service: dealplustech-astro
|
||||
# ID: svc_abc123...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Future Updates
|
||||
|
||||
After registration, updates are easy:
|
||||
|
||||
```bash
|
||||
# Make code changes
|
||||
git pull
|
||||
|
||||
# Update deployment
|
||||
./skills/easypanel-deploy/deploy.sh update
|
||||
|
||||
# This will:
|
||||
# 1. Rebuild Docker image
|
||||
# 2. Ready for deployment
|
||||
# 3. Click "Deploy" in Easypanel to apply
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Quick Commands
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `./deploy.sh deploy` | Initial deployment |
|
||||
| `./deploy.sh register ID` | Register service |
|
||||
| `./deploy.sh update` | Update service |
|
||||
| `./deploy.sh status` | Check status |
|
||||
| `./deploy.sh list` | List projects |
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Docker Build Fails
|
||||
```bash
|
||||
# Rebuild manually
|
||||
cd dealplustech-astro
|
||||
docker build -t dealplustech-astro:latest .
|
||||
```
|
||||
|
||||
### Can't Access Easypanel
|
||||
- Check VPN/connection
|
||||
- URL: http://110.164.146.46:3000
|
||||
- Contact admin if needed
|
||||
|
||||
### Service Won't Start
|
||||
1. Check logs in Easypanel dashboard
|
||||
2. Verify port 4321 is available
|
||||
3. Check resource allocation
|
||||
|
||||
---
|
||||
|
||||
## 📁 Files Created
|
||||
|
||||
```
|
||||
dealplustech-astro/
|
||||
├── skills/easypanel-deploy/
|
||||
│ ├── deploy.sh # Main script
|
||||
│ ├── SKILL_v2.md # Documentation
|
||||
│ └── README.md # Quick start
|
||||
├── easypanel.config.json # Configuration
|
||||
├── Dockerfile # Docker config
|
||||
└── DEPLOYMENT_SUMMARY.md # This file
|
||||
|
||||
~/.easypanel/
|
||||
├── credentials # API token
|
||||
└── state.json # Service IDs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Checklist
|
||||
|
||||
- [ ] Docker image built ✅
|
||||
- [ ] Easypanel token configured ✅
|
||||
- [ ] Project identified (`customerwebsite`) ✅
|
||||
- [ ] Create service in dashboard ⏳
|
||||
- [ ] Register service ID ⏳
|
||||
- [ ] Verify deployment ⏳
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Next Action
|
||||
|
||||
**Go to Easypanel dashboard and create the service:**
|
||||
|
||||
1. Open: http://110.164.146.46:3000
|
||||
2. Select: `customerwebsite` project
|
||||
3. New Service → Docker image
|
||||
4. Name: `dealplustech-astro`
|
||||
5. Image: `dealplustech-astro:latest`
|
||||
6. Port: `4321`
|
||||
7. Deploy!
|
||||
|
||||
Then run: `./deploy.sh register YOUR_SERVICE_ID`
|
||||
|
||||
---
|
||||
|
||||
**Status:** Ready for manual service creation
|
||||
**Estimated Time:** 5 minutes
|
||||
**Difficulty:** Easy
|
||||
@@ -1,302 +0,0 @@
|
||||
# 🚀 Easypanel API Deployment Guide
|
||||
|
||||
## Overview
|
||||
|
||||
This guide shows how to deploy the Deal Plus Tech Astro site to Easypanel using their API.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. **Easypanel Access**
|
||||
- URL: `http://110.164.146.46:3000`
|
||||
- Admin credentials
|
||||
|
||||
2. **API Token**
|
||||
- Login to Easypanel
|
||||
- Go to Settings → API
|
||||
- Generate new API token
|
||||
|
||||
3. **Docker Image**
|
||||
- Already built locally: `dealplustech-astro:latest`
|
||||
- Size: 564MB
|
||||
|
||||
---
|
||||
|
||||
## Method 1: Manual Deployment (Recommended)
|
||||
|
||||
### Step 1: Login to Easypanel
|
||||
|
||||
```
|
||||
URL: http://110.164.146.46:3000
|
||||
```
|
||||
|
||||
### Step 2: Create Project
|
||||
|
||||
1. Click **"New Project"**
|
||||
2. Name: `dealplustech`
|
||||
3. Description: "Deal Plus Tech Websites"
|
||||
4. Click **"Create"**
|
||||
|
||||
### Step 3: Deploy Docker Image
|
||||
|
||||
1. Select project: `dealplustech`
|
||||
2. Click **"New Service"**
|
||||
3. Choose: **"Docker Image"**
|
||||
4. Configure:
|
||||
- **Name:** `dealplustech-astro`
|
||||
- **Image:** `dealplustech-astro:latest`
|
||||
- **Port:** `4321`
|
||||
5. Click **"Deploy"**
|
||||
|
||||
### Step 4: Verify Deployment
|
||||
|
||||
1. Wait for build to complete (~2-3 minutes)
|
||||
2. Click on service to view logs
|
||||
3. Look for: "Astro preview ready"
|
||||
4. Access URL provided by Easypanel
|
||||
|
||||
---
|
||||
|
||||
## Method 2: Automated Deployment (API)
|
||||
|
||||
### Step 1: Get API Token
|
||||
|
||||
```bash
|
||||
# Login to Easypanel and get token from Settings → API
|
||||
export EASYPANEL_API_TOKEN="your-api-token-here"
|
||||
```
|
||||
|
||||
### Step 2: Run Deployment Script
|
||||
|
||||
```bash
|
||||
cd dealplustech-astro
|
||||
|
||||
# Option A: With token as argument
|
||||
./deploy-easypanel.sh your-api-token
|
||||
|
||||
# Option B: With environment variable
|
||||
export EASYPANEL_API_TOKEN="your-api-token"
|
||||
./deploy-easypanel.sh
|
||||
```
|
||||
|
||||
### Step 3: Monitor Deployment
|
||||
|
||||
```bash
|
||||
# View service status
|
||||
curl -s "http://110.164.146.46:3000/api/trpc/services.app.inspectService" \
|
||||
-H "Authorization: Bearer $EASYPANEL_API_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"input":{"json":{"projectName":"dealplustech","serviceName":"dealplustech-astro"}}}' \
|
||||
--insecure | python3 -m json.tool
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Method 3: Direct Docker Deployment
|
||||
|
||||
If you have direct Docker access to the Easypanel server:
|
||||
|
||||
```bash
|
||||
# SSH to Easypanel server
|
||||
ssh user@110.164.146.46
|
||||
|
||||
# Run container directly
|
||||
docker run -d \
|
||||
-p 4321:4321 \
|
||||
--name dealplustech-astro \
|
||||
--restart unless-stopped \
|
||||
-e NODE_ENV=production \
|
||||
-e PORT=4321 \
|
||||
-e HOST=0.0.0.0 \
|
||||
dealplustech-astro:latest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### List Projects
|
||||
|
||||
```bash
|
||||
curl -X GET "http://110.164.146.46:3000/api/trpc/projects.listProjects" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
--insecure
|
||||
```
|
||||
|
||||
### Create Service
|
||||
|
||||
```bash
|
||||
curl -X POST "http://110.164.146.46:3000/api/trpc/services.app.create" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-d '{
|
||||
"projectName": "dealplustech",
|
||||
"name": "dealplustech-astro",
|
||||
"type": "docker",
|
||||
"docker": {
|
||||
"image": "dealplustech-astro:latest",
|
||||
"port": 4321
|
||||
},
|
||||
"env": {
|
||||
"NODE_ENV": "production",
|
||||
"PORT": "4321"
|
||||
}
|
||||
}' \
|
||||
--insecure
|
||||
```
|
||||
|
||||
### Inspect Service
|
||||
|
||||
```bash
|
||||
curl -X GET "http://110.164.146.46:3000/api/trpc/services.app.inspectService" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-d '{"input":{"json":{"projectName":"dealplustech","serviceName":"dealplustech-astro"}}}' \
|
||||
--insecure
|
||||
```
|
||||
|
||||
### Get Service Logs
|
||||
|
||||
```bash
|
||||
curl -X GET "http://110.164.146.46:3000/api/trpc/services.common.getLogs" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-d '{"input":{"json":{"projectName":"dealplustech","serviceName":"dealplustech-astro","lines":50}}}' \
|
||||
--insecure
|
||||
```
|
||||
|
||||
### Deploy/Redeploy Service
|
||||
|
||||
```bash
|
||||
curl -X POST "http://110.164.146.46:3000/api/trpc/services.app.deploy" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-d '{"input":{"json":{"projectName":"dealplustech","serviceName":"dealplustech-astro"}}}' \
|
||||
--insecure
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Value | Required |
|
||||
|----------|-------|----------|
|
||||
| `NODE_ENV` | `production` | ✅ Yes |
|
||||
| `PORT` | `4321` | ✅ Yes |
|
||||
| `HOST` | `0.0.0.0` | ✅ Yes |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### API Returns 401 Unauthorized
|
||||
|
||||
**Problem:** Invalid or missing API token
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Verify token is set
|
||||
echo $EASYPANEL_API_TOKEN
|
||||
|
||||
# Regenerate token in Easypanel dashboard
|
||||
```
|
||||
|
||||
### Service Won't Start
|
||||
|
||||
**Problem:** Container crashes on startup
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Check logs
|
||||
docker logs dealplustech-astro
|
||||
|
||||
# Common issues:
|
||||
# - Port already in use
|
||||
# - Missing environment variables
|
||||
# - Image build failed
|
||||
```
|
||||
|
||||
### Build Fails
|
||||
|
||||
**Problem:** Docker build errors
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Rebuild with verbose output
|
||||
cd dealplustech-astro
|
||||
docker build --no-cache -t dealplustech-astro:latest .
|
||||
|
||||
# Check for errors in output
|
||||
```
|
||||
|
||||
### Can't Access Easypanel
|
||||
|
||||
**Problem:** Connection timeout
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Test connection
|
||||
curl -I http://110.164.146.46:3000
|
||||
|
||||
# Check if Easypanel is running
|
||||
# Contact server administrator if needed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Post-Deployment
|
||||
|
||||
### 1. Verify Service
|
||||
|
||||
```bash
|
||||
curl http://your-easypanel-url:4321/
|
||||
```
|
||||
|
||||
Should return HTML with Thai content
|
||||
|
||||
### 2. Check Health
|
||||
|
||||
```bash
|
||||
curl -I http://your-easypanel-url:4321/
|
||||
```
|
||||
|
||||
Should return `HTTP/1.1 200 OK`
|
||||
|
||||
### 3. Setup Domain (Optional)
|
||||
|
||||
1. Go to Easypanel → Service Settings → Domains
|
||||
2. Add domain: `dealplustech.co.th`
|
||||
3. Update DNS records
|
||||
4. Enable SSL
|
||||
|
||||
### 4. Enable Auto-Deploy
|
||||
|
||||
For Git-based auto-deploy:
|
||||
1. Go to Service Settings → Git
|
||||
2. Connect repository
|
||||
3. Enable auto-deploy on push
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
- **Easypanel Dashboard:** http://110.164.146.46:3000
|
||||
- **API Documentation:** http://110.164.146.46:3000/api
|
||||
- **Swagger UI:** http://110.164.146.46:3000/api (Swagger UI)
|
||||
- **Easypanel Docs:** https://docs.easypanel.io
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
For issues:
|
||||
1. Check service logs in Easypanel
|
||||
2. Review deployment script output
|
||||
3. Contact Easypanel support
|
||||
4. Check project documentation
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2026-03-02
|
||||
**Status:** ✅ Ready for Deployment
|
||||
@@ -1,112 +0,0 @@
|
||||
# 🚀 Deployment Instructions - Deal Plus Tech Astro
|
||||
|
||||
## ✅ Git Pushed Successfully!
|
||||
|
||||
**Repository:** https://git.moreminimore.com/kunthawat/dealplustech.git
|
||||
**Branch:** main
|
||||
**Commit:** 6402d88 - Complete Astro migration
|
||||
|
||||
---
|
||||
|
||||
## 📦 Deploy to Easypanel
|
||||
|
||||
### Option 1: Via Easypanel UI (Recommended)
|
||||
|
||||
1. **Login to Easypanel:** http://110.164.146.46:3000
|
||||
|
||||
2. **Go to Project:** `customerwebsite`
|
||||
|
||||
3. **Create New Service:**
|
||||
- Click "New Service" → "Git Repository"
|
||||
- Repository URL: `https://git.moreminimore.com/kunthawat/dealplustech.git`
|
||||
- Branch: `main`
|
||||
- Service Name: `dealplustech-astro`
|
||||
|
||||
4. **Configure Build:**
|
||||
- Build Type: **Dockerfile**
|
||||
- Dockerfile Path: `./dealplustech-astro/Dockerfile`
|
||||
- Port: `3000`
|
||||
|
||||
5. **Click "Deploy"**
|
||||
|
||||
6. **Wait for build** (~2-3 minutes)
|
||||
|
||||
7. **Access your site:** Easypanel will provide the URL
|
||||
|
||||
---
|
||||
|
||||
### Option 2: If Service Already Exists
|
||||
|
||||
If you have an existing service for this repo:
|
||||
|
||||
1. The git push should trigger **auto-deploy** automatically
|
||||
2. Check the service deployment logs in Easypanel
|
||||
3. If auto-deploy didn't trigger, click "Redeploy" manually
|
||||
|
||||
---
|
||||
|
||||
## ✅ Verify Deployment
|
||||
|
||||
After deployment completes:
|
||||
|
||||
- [ ] Visit your site URL
|
||||
- [ ] Cookie consent banner appears
|
||||
- [ ] Homepage loads correctly
|
||||
- [ ] Privacy Policy accessible (`/privacy-policy/`)
|
||||
- [ ] Terms & Conditions accessible (`/terms-and-conditions/`)
|
||||
- [ ] Blog posts load (`/blog/`)
|
||||
- [ ] All navigation works
|
||||
- [ ] Mobile responsive
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Post-Deployment Configuration
|
||||
|
||||
### Enable Umami Analytics
|
||||
|
||||
Edit `src/layouts/BaseLayout.astro` (lines ~103-105):
|
||||
|
||||
```javascript
|
||||
function loadAnalytics() {
|
||||
const umamiEnabled = true; // Change to true
|
||||
const umamiWebsiteId = 'xxx-xxx-xxx'; // Your Umami ID
|
||||
const umamiDomain = 'analytics.moreminimore.com'; // Your domain
|
||||
|
||||
if (umamiEnabled && umamiWebsiteId && umamiDomain) {
|
||||
// Loads Umami script
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then commit and push:
|
||||
```bash
|
||||
git add src/layouts/BaseLayout.astro
|
||||
git commit -m "Enable Umami Analytics"
|
||||
git push
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎉 What's Deployed
|
||||
|
||||
✅ Astro static site (184KB, 11 pages)
|
||||
✅ PDPA-compliant Privacy Policy (Thai)
|
||||
✅ PDPA-compliant Terms & Conditions (Thai)
|
||||
✅ Cookie Policy with disclosure (Thai)
|
||||
✅ Cookie consent banner (client-side)
|
||||
✅ Blog with 3 posts
|
||||
✅ Umami Analytics placeholder
|
||||
✅ Production Docker configuration
|
||||
|
||||
---
|
||||
|
||||
## 📞 Support
|
||||
|
||||
**Easypanel URL:** http://110.164.146.46:3000
|
||||
**Git Repository:** https://git.moreminimore.com/kunthawat/dealplustech.git
|
||||
|
||||
**If build fails:**
|
||||
1. Check Easypanel build logs
|
||||
2. Verify Dockerfile is at correct path
|
||||
3. Check port is set to 3000
|
||||
4. Review error messages in logs
|
||||
@@ -1,15 +0,0 @@
|
||||
# Production Docker for Astro Static Site
|
||||
FROM node:20-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
FROM node:20-alpine
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/dist ./dist
|
||||
RUN npm install -g serve
|
||||
EXPOSE 3000
|
||||
ENV NODE_ENV=production PORT=3000 HOST=0.0.0.0
|
||||
CMD ["serve", "dist", "-l", "3000", "--single"]
|
||||
@@ -1,310 +0,0 @@
|
||||
# Easypanel Deployment Skill
|
||||
|
||||
**Skill Name:** `easypanel-deploy`
|
||||
**Description:** Deploy Astro/Next.js/Vite apps to Easypanel with Docker
|
||||
**Version:** 1.0.0
|
||||
**Author:** Deal Plus Tech DevOps
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
This skill provides a complete deployment workflow for static site generators (Astro, Next.js, Vite) to Easypanel using Docker containers.
|
||||
|
||||
---
|
||||
|
||||
## Capabilities
|
||||
|
||||
- ✅ **Dockerfile Generation** - Optimized multi-stage Dockerfile
|
||||
- ✅ **Easypanel Configuration** - Pre-configured for Easypanel deployment
|
||||
- ✅ **Git Integration** - Auto-deploy on push
|
||||
- ✅ **Environment Setup** - Environment variables and secrets
|
||||
- ✅ **Domain Configuration** - Custom domain + SSL setup
|
||||
- ✅ **Health Checks** - Container health monitoring
|
||||
- ✅ **Resource Optimization** - Recommended resource allocation
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Easypanel instance (self-hosted or cloud)
|
||||
2. Git repository with Astro/Next.js/Vite project
|
||||
3. Docker installed (for local testing)
|
||||
|
||||
### Step 1: Prepare Project
|
||||
|
||||
```bash
|
||||
# Navigate to project
|
||||
cd your-project
|
||||
|
||||
# Ensure build script exists
|
||||
npm run build
|
||||
|
||||
# Test production build
|
||||
npm run preview
|
||||
```
|
||||
|
||||
### Step 2: Add Deployment Files
|
||||
|
||||
Create these files in project root:
|
||||
|
||||
**Dockerfile:**
|
||||
```dockerfile
|
||||
FROM node:20-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
FROM node:20-alpine
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci --production
|
||||
COPY --from=builder /app/dist ./dist
|
||||
COPY --from=builder /app/public ./public
|
||||
EXPOSE 4321
|
||||
CMD ["npm", "run", "preview", "--", "--host", "0.0.0.0", "--port", "4321"]
|
||||
```
|
||||
|
||||
**.dockerignore:**
|
||||
```
|
||||
node_modules
|
||||
dist
|
||||
*.log
|
||||
.git
|
||||
.env
|
||||
```
|
||||
|
||||
### Step 3: Deploy to Easypanel
|
||||
|
||||
#### Option A: Git Repository (Recommended)
|
||||
|
||||
1. Login to Easypanel
|
||||
2. **New Service** → **Git Repository**
|
||||
3. Select repository and branch
|
||||
4. Configure:
|
||||
- **Build Command:** `npm run build`
|
||||
- **Publish Directory:** `dist`
|
||||
- **Port:** `4321`
|
||||
5. Click **Deploy**
|
||||
|
||||
#### Option B: Docker Image
|
||||
|
||||
1. Build image:
|
||||
```bash
|
||||
docker build -t your-app:latest .
|
||||
docker push your-registry.com/your-app:latest
|
||||
```
|
||||
|
||||
2. Deploy on Easypanel:
|
||||
- **New Service** → **Docker Image**
|
||||
- Enter image URL
|
||||
- Set port: `4321`
|
||||
- Click **Deploy**
|
||||
|
||||
### Step 4: Configure Domain (Optional)
|
||||
|
||||
1. Go to Service Settings → **Domains**
|
||||
2. Add domain: `your-domain.com`
|
||||
3. Update DNS:
|
||||
```
|
||||
Type: CNAME
|
||||
Name: @
|
||||
Value: your-service.easypanel.app
|
||||
```
|
||||
4. Enable SSL
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| `NODE_ENV` | No | `production` | Node environment |
|
||||
| `PORT` | No | `4321` | Server port |
|
||||
| `HOST` | No | `0.0.0.0` | Bind address |
|
||||
|
||||
---
|
||||
|
||||
## Resource Recommendations
|
||||
|
||||
| Project Size | CPU | Memory | Storage |
|
||||
|--------------|-----|--------|---------|
|
||||
| **Small** (< 100MB) | 0.5 vCPU | 512MB | 1GB |
|
||||
| **Medium** (< 500MB) | 1 vCPU | 1GB | 2GB |
|
||||
| **Large** (> 500MB) | 2 vCPU | 2GB | 5GB |
|
||||
|
||||
---
|
||||
|
||||
## Health Check
|
||||
|
||||
**Endpoint:** `GET /`
|
||||
**Expected:** HTTP 200 OK
|
||||
**Timeout:** 3 seconds
|
||||
**Interval:** 30 seconds
|
||||
|
||||
### Manual Health Check
|
||||
|
||||
```bash
|
||||
curl http://your-service:4321/
|
||||
```
|
||||
|
||||
### Docker Health Check
|
||||
|
||||
```bash
|
||||
docker inspect --format='{{.State.Health.Status}}' your-container
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Build Fails
|
||||
|
||||
**Symptoms:** Build command returns error
|
||||
|
||||
**Solutions:**
|
||||
1. Check build logs
|
||||
2. Verify `package.json` scripts
|
||||
3. Test locally: `npm run build`
|
||||
4. Check Node version compatibility
|
||||
|
||||
### Container Crashes
|
||||
|
||||
**Symptoms:** Container exits immediately
|
||||
|
||||
**Solutions:**
|
||||
1. Check container logs: `docker logs <container>`
|
||||
2. Verify port configuration
|
||||
3. Check environment variables
|
||||
4. Review Dockerfile CMD instruction
|
||||
|
||||
### 502 Bad Gateway
|
||||
|
||||
**Symptoms:** Service returns 502 error
|
||||
|
||||
**Solutions:**
|
||||
1. Verify container is running
|
||||
2. Check port mapping
|
||||
3. Review health check status
|
||||
4. Inspect application logs
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Security
|
||||
|
||||
- ✅ Use `.dockerignore` to exclude sensitive files
|
||||
- ✅ Run as non-root user (add `USER node` to Dockerfile)
|
||||
- ✅ Use production dependencies only
|
||||
- ✅ Enable SSL for custom domains
|
||||
- ✅ Regular security updates
|
||||
|
||||
### Performance
|
||||
|
||||
- ✅ Multi-stage Docker builds
|
||||
- ✅ Minimize Docker image size
|
||||
- ✅ Enable compression (Easypanel default)
|
||||
- ✅ Use CDN for static assets
|
||||
- ✅ Configure proper caching
|
||||
|
||||
### Monitoring
|
||||
|
||||
- ✅ Enable health checks
|
||||
- ✅ Monitor resource usage
|
||||
- ✅ Set up log aggregation
|
||||
- ✅ Configure alerts for failures
|
||||
- ✅ Regular backup strategy
|
||||
|
||||
---
|
||||
|
||||
## Examples
|
||||
|
||||
### Astro Project
|
||||
|
||||
```bash
|
||||
# Astro specific configuration
|
||||
npm create astro@latest
|
||||
npm run build # Output: dist/
|
||||
npm run preview # Port: 4321
|
||||
```
|
||||
|
||||
### Next.js Project
|
||||
|
||||
```bash
|
||||
# Next.js specific configuration
|
||||
npx create-next-app
|
||||
npm run build # Output: .next/
|
||||
npm run start # Port: 3000
|
||||
```
|
||||
|
||||
Update Dockerfile PORT to 3000 for Next.js.
|
||||
|
||||
### Vite Project
|
||||
|
||||
```bash
|
||||
# Vite specific configuration
|
||||
npm create vite@latest
|
||||
npm run build # Output: dist/
|
||||
npx serve dist # Port: 3000
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integration with CI/CD
|
||||
|
||||
### GitHub Actions Example
|
||||
|
||||
```yaml
|
||||
name: Deploy to Easypanel
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Build Docker Image
|
||||
run: docker build -t my-app:latest .
|
||||
|
||||
- name: Push to Registry
|
||||
run: docker push registry.com/my-app:latest
|
||||
|
||||
- name: Deploy to Easypanel
|
||||
run: |
|
||||
# Use Easypanel API or CLI
|
||||
easypanel deploy my-app:latest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
- **Easypanel Docs:** https://docs.easypanel.io
|
||||
- **Docker Docs:** https://docs.docker.com
|
||||
- **Astro Docs:** https://docs.astro.build
|
||||
- **Node.js Docker Best Practices:** https://github.com/nodejs/docker-node
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
1. Check troubleshooting section
|
||||
2. Review Easypanel documentation
|
||||
3. Check project logs
|
||||
4. Contact DevOps team
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2026-03-02
|
||||
**Skill Version:** 1.0.0
|
||||
**Status:** ✅ Production Ready
|
||||
@@ -1,164 +0,0 @@
|
||||
# 🚀 Final Deployment Guide - Deal Plus Tech Astro
|
||||
|
||||
## ✅ What's Ready
|
||||
|
||||
### 1. Docker Image
|
||||
- ✅ Built locally: `dealplustech-astro:local`
|
||||
- ✅ Size: ~564MB
|
||||
- ✅ Ready to push to registry
|
||||
|
||||
### 2. Easypanel Integration
|
||||
- ✅ API token configured
|
||||
- ✅ Project identified: `customerwebsite`
|
||||
- ✅ Deployment script ready
|
||||
|
||||
### 3. Registry Options
|
||||
|
||||
**Option A: Easypanel Registry** (If available)
|
||||
```bash
|
||||
URL: 110.164.146.46:3001
|
||||
Status: ⚠️ Port 3001 not accessible
|
||||
```
|
||||
|
||||
**Option B: Docker Hub** (Recommended fallback)
|
||||
```bash
|
||||
URL: hub.docker.com
|
||||
Status: ✅ Available
|
||||
```
|
||||
|
||||
**Option C: Direct Server Load** (If SSH access)
|
||||
```bash
|
||||
Server: 110.164.146.46
|
||||
Status: ⚠️ Requires SSH credentials
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Recommended Deployment Path
|
||||
|
||||
### Step 1: Push to Docker Hub (5 minutes)
|
||||
|
||||
```bash
|
||||
# 1. Login to Docker Hub
|
||||
docker login
|
||||
|
||||
# 2. Tag image
|
||||
docker tag dealplustech-astro:local yourusername/dealplustech-astro:latest
|
||||
|
||||
# 3. Push
|
||||
docker push yourusername/dealplustech-astro:latest
|
||||
```
|
||||
|
||||
### Step 2: Create Service in Easypanel (2 minutes)
|
||||
|
||||
```
|
||||
1. Open: http://110.164.146.46:3000
|
||||
2. Project: customerwebsite
|
||||
3. New Service → Docker image
|
||||
4. Image: yourusername/dealplustech-astro:latest
|
||||
5. Port: 4321
|
||||
6. Deploy
|
||||
7. Copy Service ID
|
||||
```
|
||||
|
||||
### Step 3: Register Service ID
|
||||
|
||||
```bash
|
||||
cd dealplustech-astro
|
||||
./skills/easypanel-deploy/deploy.sh register svc_xxx...
|
||||
```
|
||||
|
||||
### Step 4: Verify
|
||||
|
||||
```bash
|
||||
./skills/easypanel-deploy/deploy.sh status
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Future Updates
|
||||
|
||||
Once registered:
|
||||
|
||||
```bash
|
||||
# Make changes
|
||||
git pull
|
||||
|
||||
# Update (automatically rebuilds and pushes)
|
||||
./skills/easypanel-deploy/deploy.sh update
|
||||
|
||||
# Redeploy in Easypanel dashboard
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Quick Commands
|
||||
|
||||
```bash
|
||||
# Deploy (builds + instructions)
|
||||
./skills/easypanel-deploy/deploy.sh deploy
|
||||
|
||||
# Register service
|
||||
./skills/easypanel-deploy/deploy.sh register SERVICE_ID
|
||||
|
||||
# Update (rebuild + push)
|
||||
./skills/easypanel-deploy/deploy.sh update
|
||||
|
||||
# Check status
|
||||
./skills/easypanel-deploy/deploy.sh status
|
||||
|
||||
# List projects
|
||||
./skills/easypanel-deploy/deploy.sh list
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 Files Created
|
||||
|
||||
```
|
||||
dealplustech-astro/
|
||||
├── skills/easypanel-deploy/
|
||||
│ ├── deploy.sh ✅ v3.2 Smart deployment
|
||||
│ ├── SKILL_v2.md ✅ Full documentation
|
||||
│ ├── README.md ✅ Quick start
|
||||
│ └── AUTOMATIC_DEPLOYMENT.md ✅ Automation details
|
||||
├── DEPLOYMENT_OPTIONS.md ✅ Registry options
|
||||
├── FINAL_DEPLOYMENT_GUIDE.md ✅ This file
|
||||
└── easypanel.config.json ✅ Configuration
|
||||
|
||||
~/.easypanel/
|
||||
├── credentials ✅ API token
|
||||
└── state.json ✅ Service IDs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Checklist
|
||||
|
||||
- [x] Docker image built
|
||||
- [x] Easypanel token configured
|
||||
- [x] Project identified (customerwebsite)
|
||||
- [ ] Push to Docker Hub
|
||||
- [ ] Create service in Easypanel
|
||||
- [ ] Register service ID
|
||||
- [ ] Verify deployment
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Next Action
|
||||
|
||||
**Push to Docker Hub:**
|
||||
|
||||
```bash
|
||||
docker login
|
||||
docker tag dealplustech-astro:local yourusername/dealplustech-astro:latest
|
||||
docker push yourusername/dealplustech-astro:latest
|
||||
```
|
||||
|
||||
**Then create service in Easypanel!**
|
||||
|
||||
---
|
||||
|
||||
**Status:** Ready for Docker Hub push
|
||||
**Estimated Time:** 10 minutes
|
||||
**Difficulty:** Easy
|
||||
@@ -1,167 +0,0 @@
|
||||
# 🔧 Fixes Applied - Product Tables & Responsive Fonts
|
||||
|
||||
## ✅ Issue 1: Product Tables Disappeared
|
||||
|
||||
### Problem
|
||||
The product specification tables (extracted from images) were not showing on product pages in the Astro migration.
|
||||
|
||||
### Root Cause
|
||||
- The Astro product detail page template (`[slug].astro`) was missing
|
||||
- Product tables data exists in `src/data/site-config.ts` but wasn't being rendered
|
||||
- Markdown files don't include table data (tables are in TypeScript file)
|
||||
|
||||
### Solution
|
||||
Created `src/pages/products/[slug].astro` with:
|
||||
1. **Table Rendering Section** - Displays all `productTables` from site-config
|
||||
2. **Proper Styling** - Matches original Next.js design with:
|
||||
- Table name headers
|
||||
- Alternating row colors
|
||||
- Responsive table containers
|
||||
- Proper borders and shadows
|
||||
|
||||
### Code Added
|
||||
```astro
|
||||
{productTables.length > 0 && (
|
||||
<section class="mb-12">
|
||||
<h2>ตารางข้อมูลผลิตภัณฑ์</h2>
|
||||
{productTables.map((table) => (
|
||||
<div class="bg-white rounded-2xl...">
|
||||
<h3>{table.tableName}</h3>
|
||||
<table>
|
||||
<thead>{table.headers.map(...)} </thead>
|
||||
<tbody>{table.rows.map(...)} </tbody>
|
||||
</table>
|
||||
</div>
|
||||
))}
|
||||
</section>
|
||||
)}
|
||||
```
|
||||
|
||||
### Data Source
|
||||
Tables are loaded from `src/data/site-config.ts` via `productCategories.find(p => p.id === product.data.id).productTables`
|
||||
|
||||
Products with tables:
|
||||
- ✅ ppr-welder (1 table)
|
||||
- ✅ poloplast (4 tables)
|
||||
- ✅ syler (2 tables)
|
||||
- ✅ xylent (3 tables)
|
||||
- ✅ pvc/upvc (6 tables)
|
||||
- ✅ realflex (3 tables)
|
||||
|
||||
---
|
||||
|
||||
## ✅ Issue 2: Font Too Small on Large Screens
|
||||
|
||||
### Problem
|
||||
Text was not scaling properly on larger screens (desktop, 4K monitors).
|
||||
|
||||
### Root Cause
|
||||
- Base font size was fixed at browser default (16px)
|
||||
- No responsive scaling for larger viewports
|
||||
- Tailwind classes weren't enough for very large screens
|
||||
|
||||
### Solution
|
||||
Added responsive font scaling in `src/styles/global.css`:
|
||||
|
||||
```css
|
||||
/* Base font size */
|
||||
html {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* Scale up for larger screens */
|
||||
@media (min-width: 1280px) {
|
||||
html { font-size: 18px; }
|
||||
}
|
||||
|
||||
@media (min-width: 1536px) {
|
||||
html { font-size: 20px; }
|
||||
}
|
||||
|
||||
@media (min-width: 1920px) {
|
||||
html { font-size: 22px; }
|
||||
}
|
||||
|
||||
@media (min-width: 2560px) {
|
||||
html { font-size: 24px; }
|
||||
}
|
||||
```
|
||||
|
||||
### Additional Responsive Text Classes
|
||||
```css
|
||||
.text-responsive-sm { text-sm md:text-base lg:text-lg xl:text-xl; }
|
||||
.text-responsive-base { text-base md:text-lg lg:text-xl xl:text-2xl; }
|
||||
.text-responsive-lg { text-lg md:text-xl lg:text-2xl xl:text-3xl; }
|
||||
.text-responsive-xl { text-xl md:text-2xl lg:text-3xl xl:text-4xl; }
|
||||
```
|
||||
|
||||
### Updated Components
|
||||
All major text elements now use responsive sizing:
|
||||
- **Buttons**: `text-base md:text-lg`
|
||||
- **Section titles**: `text-3xl md:text-4xl lg:text-5xl xl:text-6xl`
|
||||
- **Table headers**: `text-xl md:text-2xl lg:text-3xl`
|
||||
- **Table cells**: `text-base md:text-lg lg:text-xl`
|
||||
- **Features/FAQ**: `text-base md:text-lg lg:text-xl`
|
||||
|
||||
---
|
||||
|
||||
## 📊 Before & After Comparison
|
||||
|
||||
| Screen Size | Before | After |
|
||||
|-------------|--------|-------|
|
||||
| **Mobile (< 768px)** | 16px base | 16px base ✓ |
|
||||
| **Tablet (768-1280px)** | 16px base | 16px base ✓ |
|
||||
| **Desktop (1280-1536px)** | 16px base | **18px base** ↑ |
|
||||
| **Large (1536-1920px)** | 16px base | **20px base** ↑ |
|
||||
| **XL (1920-2560px)** | 16px base | **22px base** ↑ |
|
||||
| **4K (> 2560px)** | 16px base | **24px base** ↑ |
|
||||
|
||||
### Font Scaling Examples
|
||||
|
||||
**Product Title:**
|
||||
- Before: `text-4xl` (36px fixed)
|
||||
- After: `text-4xl md:text-5xl lg:text-6xl xl:text-7xl` (36px → 60px)
|
||||
|
||||
**Table Headers:**
|
||||
- Before: `text-lg` (18px fixed)
|
||||
- After: `text-xl md:text-2xl lg:text-3xl` (20px → 30px)
|
||||
|
||||
**Body Text:**
|
||||
- Before: `text-base` (16px fixed)
|
||||
- After: Responsive + base font scaling (16px → 24px)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Testing Checklist
|
||||
|
||||
### Product Tables
|
||||
- [ ] Visit any product page (e.g., `/pp-r-pp-rct-poloplast/`)
|
||||
- [ ] Scroll to "ตารางข้อมูลผลิตภัณฑ์" section
|
||||
- [ ] Verify tables are visible with proper styling
|
||||
- [ ] Check table headers have green background
|
||||
- [ ] Check rows alternate white/gray
|
||||
- [ ] Verify tables scroll horizontally on mobile
|
||||
|
||||
### Responsive Fonts
|
||||
- [ ] Test on mobile (375px) - text should be readable
|
||||
- [ ] Test on tablet (768px) - text slightly larger
|
||||
- [ ] Test on desktop (1920px) - text noticeably larger
|
||||
- [ ] Test on 4K (3840px) - text should be large and clear
|
||||
- [ ] Check product titles scale properly
|
||||
- [ ] Check table text scales properly
|
||||
- [ ] Check buttons scale properly
|
||||
|
||||
---
|
||||
|
||||
## 📁 Files Modified
|
||||
|
||||
| File | Changes |
|
||||
|------|---------|
|
||||
| `src/pages/products/[slug].astro` | ✅ Created - product detail page with tables |
|
||||
| `src/styles/global.css` | ✅ Updated - responsive font scaling |
|
||||
|
||||
---
|
||||
|
||||
**Status:** ✅ Both issues fixed
|
||||
**Build:** ✅ Passing
|
||||
**Next:** Test on actual device/screen sizes
|
||||
@@ -1,231 +0,0 @@
|
||||
# 🚀 Gitea Repository Deployment - BEST METHOD!
|
||||
|
||||
## ✅ Why This is Better
|
||||
|
||||
| Method | Docker Registry | Gitea Repo |
|
||||
|--------|----------------|------------|
|
||||
| Build locally | ✅ Required | ❌ Not needed |
|
||||
| Push to registry | ✅ Required | ❌ Not needed |
|
||||
| Easypanel builds | ❌ No | ✅ Yes! |
|
||||
| Auto-deploy on push | ❌ No | ✅ Yes! |
|
||||
| Version control | ❌ No | ✅ Yes! |
|
||||
| Rollbacks | ❌ Hard | ✅ Easy |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 How It Works
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
|
||||
│ You Git │ │ Easypanel │ │ Deployed │
|
||||
│ Push │────▶│ Clones & │────▶│ Service │
|
||||
│ to Gitea │ │ Builds │ │ Running │
|
||||
└─────────────┘ └──────────────┘ └─────────────┘
|
||||
```
|
||||
|
||||
**Easypanel will:**
|
||||
1. Clone your Gitea repository
|
||||
2. Run `npm install`
|
||||
3. Run `npm run build`
|
||||
4. Deploy the `dist/` folder
|
||||
5. Serve on port 4321
|
||||
|
||||
---
|
||||
|
||||
## 📋 Setup Steps
|
||||
|
||||
### Step 1: Run Deploy Script
|
||||
|
||||
```bash
|
||||
cd dealplustech-astro
|
||||
./skills/easypanel-deploy/deploy.sh deploy
|
||||
```
|
||||
|
||||
**It will show:**
|
||||
```
|
||||
Gitea URL: http://110.164.146.46:3001
|
||||
Repository: dealplustech/dealplustech-astro
|
||||
Branch: main
|
||||
Build Command: npm run build
|
||||
Publish Directory: dist
|
||||
Port: 4321
|
||||
```
|
||||
|
||||
### Step 2: Create Service in Easypanel
|
||||
|
||||
```
|
||||
1. Open: http://110.164.146.46:3000
|
||||
|
||||
2. Select Project: customerwebsite
|
||||
|
||||
3. Click: New Service → Git Repository
|
||||
|
||||
4. Configure:
|
||||
┌─────────────────────────────────────┐
|
||||
│ Repository URL: │
|
||||
│ http://110.164.146.46:3001/ │
|
||||
│ dealplustech/dealplustech-astro │
|
||||
└─────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────┐
|
||||
│ Branch: main │
|
||||
└─────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────┐
|
||||
│ Build Command: npm run build │
|
||||
└─────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────┐
|
||||
│ Publish Directory: dist │
|
||||
└─────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────┐
|
||||
│ Port: 4321 │
|
||||
└─────────────────────────────────────┘
|
||||
|
||||
5. Click: Deploy
|
||||
```
|
||||
|
||||
### Step 3: Wait for Build
|
||||
|
||||
Easypanel will:
|
||||
- ✅ Clone from Gitea (~10 seconds)
|
||||
- ✅ Run `npm install` (~30 seconds)
|
||||
- ✅ Run `npm run build` (~20 seconds)
|
||||
- ✅ Deploy `dist/` (~5 seconds)
|
||||
|
||||
**Total: ~1 minute**
|
||||
|
||||
### Step 4: Register Service ID
|
||||
|
||||
After deployment completes:
|
||||
|
||||
```bash
|
||||
# Copy Service ID from Easypanel dashboard
|
||||
./skills/easypanel-deploy/deploy.sh register svc_xxx...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Automatic Updates
|
||||
|
||||
### Enable Auto-Deploy
|
||||
|
||||
**In Easypanel:**
|
||||
1. Go to service settings
|
||||
2. Click: Git → Auto Deploy
|
||||
3. Enable: Auto Deploy on Push
|
||||
|
||||
**Then:**
|
||||
```bash
|
||||
# Make changes
|
||||
git add .
|
||||
git commit -m "Update something"
|
||||
git push
|
||||
|
||||
# Easypanel automatically rebuilds! 🎉
|
||||
```
|
||||
|
||||
### Manual Redeploy
|
||||
|
||||
```bash
|
||||
./skills/easypanel-deploy/deploy.sh redeploy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Benefits
|
||||
|
||||
### 1. No Docker Registry
|
||||
- ❌ No `docker build`
|
||||
- ❌ No `docker push`
|
||||
- ❌ No registry credentials
|
||||
|
||||
### 2. Automatic Deployments
|
||||
- ✅ Push to Gitea
|
||||
- ✅ Easypanel rebuilds
|
||||
- ✅ Zero manual steps
|
||||
|
||||
### 3. Version Control
|
||||
- ✅ Every commit = potential deployment
|
||||
- ✅ Easy rollbacks
|
||||
- ✅ Change history
|
||||
|
||||
### 4. Build Caching
|
||||
- ✅ `node_modules` cached
|
||||
- ✅ Faster builds
|
||||
- ✅ Efficient
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Gitea Repository
|
||||
|
||||
```bash
|
||||
URL: http://110.164.146.46:3001
|
||||
Owner: dealplustech
|
||||
Repo: dealplustech-astro
|
||||
Branch: main
|
||||
```
|
||||
|
||||
### Build Settings
|
||||
|
||||
```bash
|
||||
Build Command: npm run build
|
||||
Publish Directory: dist/
|
||||
Node Version: 20 (from .nvmrc or package.json)
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Add in Easypanel service settings:
|
||||
|
||||
```bash
|
||||
NODE_ENV=production
|
||||
NEXT_PUBLIC_SITE_URL=https://your-domain.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 Required Files
|
||||
|
||||
Your repository should have:
|
||||
|
||||
```
|
||||
dealplustech-astro/
|
||||
├── package.json ✅ Required (defines build)
|
||||
├── Dockerfile ⚠️ Optional (for Docker mode)
|
||||
├── astro.config.mjs ✅ Required
|
||||
├── src/ ✅ Required
|
||||
└── .gitignore ✅ Required
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Next Action
|
||||
|
||||
**Deploy now:**
|
||||
|
||||
```bash
|
||||
# 1. Run deployment script
|
||||
./skills/easypanel-deploy/deploy.sh deploy
|
||||
|
||||
# 2. Follow instructions to create service in Easypanel
|
||||
|
||||
# 3. After deployment:
|
||||
./skills/easypanel-deploy/deploy.sh register SERVICE_ID
|
||||
|
||||
# 4. Enable auto-deploy in Easypanel
|
||||
|
||||
# 5. Future updates: just git push!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**This is THE BEST way to deploy!** 🎉
|
||||
|
||||
- No Docker needed
|
||||
- No registry needed
|
||||
- Automatic deployments
|
||||
- Full version control
|
||||
@@ -1,58 +0,0 @@
|
||||
# 🚀 Deal Plus Tech - Astro Migration Complete
|
||||
|
||||
**Migration Date:** 9 March 2026
|
||||
**Status:** ✅ **PRODUCTION READY**
|
||||
|
||||
---
|
||||
|
||||
## ✅ **MIGRATION COMPLETE**
|
||||
|
||||
All core features have been successfully migrated from Next.js to Astro:
|
||||
|
||||
### **What's Working:**
|
||||
1. ✅ Astro static site - 11 pages built
|
||||
2. ✅ PDPA-compliant Privacy Policy (Thai)
|
||||
3. ✅ PDPA-compliant Terms & Conditions (Thai)
|
||||
4. ✅ Cookie Policy (Thai)
|
||||
5. ✅ Cookie consent banner (client-side)
|
||||
6. ✅ Blog with 3 posts
|
||||
7. ✅ Umami Analytics placeholder
|
||||
8. ✅ Docker configuration ready
|
||||
9. ✅ Deployment ready for Easypanel
|
||||
|
||||
### **Backup:**
|
||||
Old Next.js backup: `/Users/kunthawatgreethong/Gitea/dealplustech-backup-nextjs-20260309.tar.gz` (62MB)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **DEPLOY TO EASYPANEL NOW**
|
||||
|
||||
### **Step 1: Push to Git**
|
||||
```bash
|
||||
cd /Users/kunthawatgreethong/Gitea/dealplustech/dealplustech-astro
|
||||
git add .
|
||||
git commit -m "✅ Astro migration complete - PDPA compliant"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
### **Step 2: Deploy on Easypanel**
|
||||
|
||||
1. Go to Easypanel: `http://110.164.146.46:3000`
|
||||
2. Click your project
|
||||
3. **New Service** → **Git Repository**
|
||||
4. Connect Gitea: `https://git.moreminimore.com/kunthawat/dealplustech-astro.git`
|
||||
5. Branch: `main`
|
||||
6. Port: `3000`
|
||||
7. **Deploy**
|
||||
|
||||
### **Step 3: Verify**
|
||||
- Visit your Easypanel URL
|
||||
- Check cookie banner appears
|
||||
- Test all pages load
|
||||
- Verify privacy policy works
|
||||
|
||||
---
|
||||
|
||||
## 🎉 **SUCCESS!**
|
||||
|
||||
The Astro site is production-ready and fully PDPA-compliant!
|
||||
@@ -1,199 +0,0 @@
|
||||
# Deal Plus Tech - Astro Migration Status
|
||||
|
||||
**Generated:** 2026-03-02
|
||||
**Migration Approach:** Full rewrite (Option C - Focused)
|
||||
|
||||
---
|
||||
|
||||
## ✅ COMPLETED (4/11 tasks)
|
||||
|
||||
### 1. ✅ Project Setup
|
||||
- Created Astro project: `dealplustech-astro/`
|
||||
- Tailwind 4 configured
|
||||
- TypeScript strict mode enabled
|
||||
- Kanit font support configured
|
||||
|
||||
### 2. ✅ Theme Migration
|
||||
- Industrial theme colors (Primary green, Secondary slate, Accent yellow)
|
||||
- Custom shadows (card, industrial, bold)
|
||||
- All component classes migrated (btn-primary, card, section-title, etc.)
|
||||
- 70 lines of custom CSS
|
||||
|
||||
### 3. ✅ Core Infrastructure
|
||||
- **Content Collections** configured with full product schema
|
||||
- **BaseLayout.astro** - HTML shell with Thai SEO
|
||||
- **Header.astro** - Fully functional with mobile menu
|
||||
- **Footer.astro** - Complete with all sections
|
||||
- **utils.ts** - Helper functions (cn, formatPrice, etc.)
|
||||
- **site-config.ts** - Navigation + company info
|
||||
|
||||
### 4. ✅ Example Product
|
||||
- **ppr-elephant.md** - Full migration example (161 lines)
|
||||
- Demonstrates Markdown frontmatter + content structure
|
||||
- All fields mapped from Next.js structure
|
||||
|
||||
---
|
||||
|
||||
## 📁 CREATED FILES
|
||||
|
||||
```
|
||||
dealplustech-astro/
|
||||
├── src/
|
||||
│ ├── components/
|
||||
│ │ ├── Header.astro ✅ 223 lines (mobile menu + JS)
|
||||
│ │ └── Footer.astro ✅ 115 lines
|
||||
│ ├── layouts/
|
||||
│ │ └── BaseLayout.astro ✅ 46 lines
|
||||
│ ├── pages/
|
||||
│ │ └── products/
|
||||
│ │ ├── index.astro ✅ Product listing
|
||||
│ │ └── [slug].astro ✅ Dynamic product pages
|
||||
│ ├── content/
|
||||
│ │ ├── config.ts ✅ Product schema
|
||||
│ │ └── products/
|
||||
│ │ └── ppr-elephant.md ✅ Example product
|
||||
│ ├── data/
|
||||
│ │ ├── site-config.ts ✅ 116 lines
|
||||
│ │ └── README.md ⏳ Pending
|
||||
│ ├── lib/
|
||||
│ │ └── utils.ts ✅ 43 lines
|
||||
│ └── styles/
|
||||
│ └── global.css ✅ 114 lines (theme)
|
||||
└── astro.config.mjs ✅ Tailwind 4
|
||||
```
|
||||
|
||||
**Total: ~850 lines of code created**
|
||||
|
||||
---
|
||||
|
||||
## ⏳ REMAINING WORK (7/11 tasks)
|
||||
|
||||
### 5. ⏳ Migrate Product Data (36 products)
|
||||
**Status:** 1/36 complete (ppr-elephant)
|
||||
**Remaining:** 35 products to convert to Markdown
|
||||
|
||||
| Priority | Product ID | Status |
|
||||
|----------|------------|--------|
|
||||
| ✅ Done | ppr-elephant | Complete |
|
||||
| ⏳ High | thai-ppr | Pending |
|
||||
| ⏳ High | poloplast | Pending |
|
||||
| ⏳ High | hdpe | Pending |
|
||||
| ⏳ High | pvc | Pending |
|
||||
| ⏳ Medium | syler | Pending |
|
||||
| ⏳ Medium | xylent | Pending |
|
||||
| ⏳ Medium | realflex | Pending |
|
||||
| ⏳ Low | (27 more products) | Pending |
|
||||
|
||||
**Estimate:** 4-6 hours (10 min/product)
|
||||
|
||||
---
|
||||
|
||||
### 6. ⏳ Migrate Static Pages
|
||||
**Status:** 0/7 pages
|
||||
|
||||
| Page | Next.js Route | Status |
|
||||
|------|---------------|--------|
|
||||
| Homepage | `/` | ⏳ Pending |
|
||||
| About Us | `/about-us/` | ⏳ Pending |
|
||||
| Contact Us | `/contact-us/` | ⏳ Pending |
|
||||
| Portfolio | `/all-projects/` | ⏳ Pending |
|
||||
| Services | `/services/` | ⏳ Pending |
|
||||
| Sales Engineer | `/sales-engineer/` | ⏳ Pending |
|
||||
| Join Us | `/join-us/` | ⏳ Pending |
|
||||
|
||||
**Estimate:** 2-3 hours
|
||||
|
||||
---
|
||||
|
||||
### 7. ⏳ Migrate Blog System
|
||||
**Status:** Not started
|
||||
|
||||
**Tasks:**
|
||||
- [ ] Create blog collection schema
|
||||
- [ ] Migrate WordPress integration
|
||||
- [ ] Create blog listing page
|
||||
- [ ] Create blog post template
|
||||
|
||||
**Estimate:** 2-3 hours
|
||||
|
||||
---
|
||||
|
||||
### 8. ⏳ Migrate FloatingContact Widget
|
||||
**Status:** Not started
|
||||
|
||||
**Current:** React component (client-side floating widget)
|
||||
**Migration:** Keep as React island with `client:load`
|
||||
|
||||
**Estimate:** 1 hour
|
||||
|
||||
---
|
||||
|
||||
### 9. ⏳ Easypanel Deployment Setup
|
||||
**Status:** Not started
|
||||
|
||||
**Tasks:**
|
||||
- [ ] Create Dockerfile
|
||||
- [ ] Configure build command
|
||||
- [ ] Setup environment variables
|
||||
- [ ] Test deployment
|
||||
|
||||
**Estimate:** 1-2 hours
|
||||
|
||||
---
|
||||
|
||||
### 10. ⏳ Create Easypanel Skill
|
||||
**Status:** Not started
|
||||
|
||||
**Estimate:** 2-3 hours
|
||||
|
||||
---
|
||||
|
||||
## 📊 OVERALL PROGRESS
|
||||
|
||||
| Category | Progress | Status |
|
||||
|----------|----------|--------|
|
||||
| **Infrastructure** | 100% | ✅ Complete |
|
||||
| **Layouts** | 100% | ✅ Complete |
|
||||
| **Products** | 3% | ⏳ 1/36 done |
|
||||
| **Static Pages** | 0% | ⏳ Pending |
|
||||
| **Blog** | 0% | ⏳ Pending |
|
||||
| **Deployment** | 0% | ⏳ Pending |
|
||||
|
||||
**Overall: ~36% complete** (infrastructure done, content migration in progress)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 RECOMMENDED NEXT STEPS
|
||||
|
||||
1. **Migrate 5 key products** (PPR, HDPE, PVC, Syler, POLOPLAST) - 1 hour
|
||||
2. **Create homepage** - 1 hour
|
||||
3. **Setup deployment** - 1 hour
|
||||
4. **Test and verify** - 1 hour
|
||||
|
||||
**Then:** Migrate remaining products and blog incrementally
|
||||
|
||||
---
|
||||
|
||||
## 🎯 PRODUCTION READY WHEN
|
||||
|
||||
- [ ] 5 core products migrated
|
||||
- [ ] Homepage + About + Contact pages done
|
||||
- [ ] Deployment configured and tested
|
||||
- [ ] All links working
|
||||
- [ ] SEO metadata verified
|
||||
|
||||
**Estimated time to MVP:** 4-6 hours
|
||||
|
||||
---
|
||||
|
||||
## 📝 NOTES
|
||||
|
||||
- Product data conversion is straightforward (copy frontmatter, paste content)
|
||||
- All styling preserved and working
|
||||
- Mobile menu tested and functional
|
||||
- Thai language fully supported
|
||||
- SEO schema ready to implement
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2026-03-02 09:00 AM
|
||||
@@ -1 +0,0 @@
|
||||
web: npm run preview -- --host 0.0.0.0 --port $PORT
|
||||
@@ -1,43 +0,0 @@
|
||||
# Astro Starter Kit: Minimal
|
||||
|
||||
```sh
|
||||
npm create astro@latest -- --template minimal
|
||||
```
|
||||
|
||||
> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
|
||||
|
||||
## 🚀 Project Structure
|
||||
|
||||
Inside of your Astro project, you'll see the following folders and files:
|
||||
|
||||
```text
|
||||
/
|
||||
├── public/
|
||||
├── src/
|
||||
│ └── pages/
|
||||
│ └── index.astro
|
||||
└── package.json
|
||||
```
|
||||
|
||||
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
|
||||
|
||||
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
|
||||
|
||||
Any static assets, like images, can be placed in the `public/` directory.
|
||||
|
||||
## 🧞 Commands
|
||||
|
||||
All commands are run from the root of the project, from a terminal:
|
||||
|
||||
| Command | Action |
|
||||
| :------------------------ | :----------------------------------------------- |
|
||||
| `npm install` | Installs dependencies |
|
||||
| `npm run dev` | Starts local dev server at `localhost:4321` |
|
||||
| `npm run build` | Build your production site to `./dist/` |
|
||||
| `npm run preview` | Preview your build locally, before deploying |
|
||||
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
|
||||
| `npm run astro -- --help` | Get help using the Astro CLI |
|
||||
|
||||
## 👀 Want to learn more?
|
||||
|
||||
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
|
||||
@@ -1,58 +0,0 @@
|
||||
# 🍪 How to Test Cookie Consent Banner
|
||||
|
||||
## The Banner IS Working!
|
||||
|
||||
The cookie consent banner code is in the built HTML. If you don't see it, it's because:
|
||||
- You already accepted/rejected before
|
||||
- Consent is saved in localStorage permanently
|
||||
- Banner only shows to NEW visitors
|
||||
|
||||
## How to Test (3 Methods):
|
||||
|
||||
### Method 1: Clear LocalStorage (Easiest)
|
||||
|
||||
1. Open your website in browser
|
||||
2. Press **F12** to open DevTools
|
||||
3. Go to **Application** tab (Chrome) or **Storage** tab (Firefox)
|
||||
4. Click on **Local Storage** → Your site URL
|
||||
5. Find `consent-preferences` key
|
||||
6. **Right-click** → **Delete**
|
||||
7. **Refresh page** (F5)
|
||||
8. ✅ Banner should appear at bottom!
|
||||
|
||||
### Method 2: Incognito/Private + Clear Cache
|
||||
|
||||
1. Close ALL browser windows
|
||||
2. Open **NEW Incognito/Private** window
|
||||
3. **IMPORTANT:** Don't visit the site first in regular browser
|
||||
4. Visit your site in Incognito
|
||||
5. ✅ Banner should appear
|
||||
|
||||
### Method 3: Different Browser
|
||||
|
||||
1. If you use Chrome, try Firefox or Safari
|
||||
2. First-time visit = banner appears
|
||||
|
||||
## What the Banner Does:
|
||||
|
||||
- Shows at **bottom of page** (fixed position)
|
||||
- Has 3 buttons: **ยอมรับ** | **ปฏิเสธ** | **ปรับแต่ง**
|
||||
- Clicking saves preference to localStorage
|
||||
- Won't show again until you clear storage
|
||||
|
||||
## If Banner Still Doesn't Show:
|
||||
|
||||
1. **Check browser console** (F12 → Console tab)
|
||||
2. Look for JavaScript errors
|
||||
3. Verify page has loaded completely
|
||||
4. Check if script is blocked by ad blocker
|
||||
|
||||
## Code Location:
|
||||
|
||||
- File: `src/layouts/BaseLayout.astro`
|
||||
- Lines: 41-115
|
||||
- Built output: `dist/index.html` (search for "consent-preferences")
|
||||
|
||||
---
|
||||
|
||||
**The code is working correctly!** It's designed to not annoy users by showing repeatedly.
|
||||
@@ -1,9 +0,0 @@
|
||||
import { defineConfig } from 'astro/config';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
|
||||
export default defineConfig({
|
||||
vite: {
|
||||
plugins: [tailwindcss()]
|
||||
},
|
||||
output: 'static'
|
||||
});
|
||||
@@ -1,101 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Easypanel Deployment Script for Deal Plus Tech Astro
|
||||
# Usage: ./deploy-easypanel.sh [api-token]
|
||||
|
||||
set -e
|
||||
|
||||
EASYPANEL_URL="http://110.164.146.46:3000"
|
||||
APP_NAME="dealplustech-astro"
|
||||
PROJECT_NAME="dealplustech"
|
||||
DOCKER_IMAGE="dealplustech-astro:latest"
|
||||
PORT=4321
|
||||
API_TOKEN="${1:-$EASYPANEL_API_TOKEN}"
|
||||
|
||||
echo "============================================================"
|
||||
echo "🚀 Deploying to Easypanel"
|
||||
echo "============================================================"
|
||||
|
||||
# Check if API token is provided
|
||||
if [ -z "$API_TOKEN" ]; then
|
||||
echo "⚠️ No API token provided"
|
||||
echo ""
|
||||
echo "📋 Manual Deployment Steps:"
|
||||
echo "1. Open Easypanel: $EASYPANEL_URL"
|
||||
echo "2. Create/Select project: $PROJECT_NAME"
|
||||
echo "3. Click 'New Service' → 'Docker Image'"
|
||||
echo "4. Enter image: $DOCKER_IMAGE"
|
||||
echo "5. Set port: $PORT"
|
||||
echo "6. Click 'Deploy'"
|
||||
echo ""
|
||||
echo "💡 To enable automated deployment:"
|
||||
echo " 1. Get API token from Easypanel (Settings → API)"
|
||||
echo " 2. Run: export EASYPANEL_API_TOKEN='your-token'"
|
||||
echo " 3. Run this script again: ./deploy-easypanel.sh"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Build Docker image
|
||||
echo ""
|
||||
echo "🐳 Building Docker image..."
|
||||
cd dealplustech-astro
|
||||
docker build -t $DOCKER_IMAGE . || {
|
||||
echo "❌ Docker build failed"
|
||||
exit 1
|
||||
}
|
||||
echo "✅ Docker image built: $DOCKER_IMAGE"
|
||||
|
||||
# Deploy via API
|
||||
echo ""
|
||||
echo "🚀 Deploying to Easypanel via API..."
|
||||
|
||||
# Create deployment payload
|
||||
cat > /tmp/deploy.json << EOF
|
||||
{
|
||||
"projectName": "$PROJECT_NAME",
|
||||
"name": "$APP_NAME",
|
||||
"type": "docker",
|
||||
"docker": {
|
||||
"image": "$DOCKER_IMAGE",
|
||||
"port": $PORT
|
||||
},
|
||||
"env": {
|
||||
"NODE_ENV": "production",
|
||||
"PORT": "$PORT",
|
||||
"HOST": "0.0.0.0"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Make API call
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$EASYPANEL_URL/api/trpc/services.app.create" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $API_TOKEN" \
|
||||
-d @/tmp/deploy.json \
|
||||
--insecure)
|
||||
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
||||
BODY=$(echo "$RESPONSE" | head -n-1)
|
||||
|
||||
if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "201" ]; then
|
||||
echo "✅ Service created successfully"
|
||||
echo "$BODY" | python3 -m json.tool 2>/dev/null || echo "$BODY"
|
||||
|
||||
# Trigger deployment
|
||||
echo ""
|
||||
echo "🔄 Triggering deployment..."
|
||||
# Would need service ID from previous response
|
||||
|
||||
echo ""
|
||||
echo "============================================================"
|
||||
echo "🎉 DEPLOYMENT COMPLETE!"
|
||||
echo "============================================================"
|
||||
echo ""
|
||||
echo "📍 Service: $APP_NAME"
|
||||
echo "🔗 Dashboard: $EASYPANEL_URL"
|
||||
echo ""
|
||||
echo "💡 Check deployment status in Easypanel dashboard"
|
||||
else
|
||||
echo "❌ Deployment failed (HTTP $HTTP_CODE)"
|
||||
echo "$BODY"
|
||||
exit 1
|
||||
fi
|
||||
27
dealplustech-astro/dist/about-us/index.html
vendored
27
dealplustech-astro/dist/about-us/index.html
vendored
File diff suppressed because one or more lines are too long
14
dealplustech-astro/dist/blog/index.html
vendored
14
dealplustech-astro/dist/blog/index.html
vendored
File diff suppressed because one or more lines are too long
@@ -1,121 +0,0 @@
|
||||
<!DOCTYPE html><html lang="th"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="Astro v5.18.0"><meta name="description" content="ท่อ HDPE (High Density Polyethylene) เป็นท่อที่ได้รับความนิยมสูงในงานระบบน้ำ เนื่องจากความทนทานและความยืดหยุ่นที่เหนือกว่าท่อชนิดอื่น"><!-- Favicon --><link rel="icon" type="image/svg+xml" href="/favicon.svg"><link rel="alternate icon" href="/favicon.ico" sizes="any"><link rel="apple-touch-icon" href="/favicon.svg"><!-- Google Fonts: Kanit for Thai --><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Kanit:wght@300;400;500;600;700&display=swap" rel="stylesheet"><!-- SEO --><meta property="og:title" content="ข้อดีของท่อ HDPE ในงานระบบน้ำ ทำไมถึงเป็นตัวเลือกยอดนิยม"><meta property="og:description" content="ท่อ HDPE (High Density Polyethylene) เป็นท่อที่ได้รับความนิยมสูงในงานระบบน้ำ เนื่องจากความทนทานและความยืดหยุ่นที่เหนือกว่าท่อชนิดอื่น"><meta property="og:image" content="/og-image.jpg"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><title>ข้อดีของท่อ HDPE ในงานระบบน้ำ ทำไมถึงเป็นตัวเลือกยอดนิยม | ดีล พลัส เทค</title><style>html{font-family:Kanit,system-ui,sans-serif;font-size:18px}@media(min-width:1280px){html{font-size:20px}}@media(min-width:1536px){html{font-size:22px}}@media(min-width:1920px){html{font-size:24px}}
|
||||
</style></head> <body class="flex flex-col min-h-screen"> <main class="pt-32 pb-16"> <article class="container mx-auto px-4 max-w-4xl"> <!-- Header --> <header class="mb-8"> <div class="flex items-center gap-4 mb-4"> <span class="industrial-badge">ท่อ HDPE</span> <time class="text-secondary-500"> 10 มกราคม 2567 </time> <span class="text-secondary-500">•</span> <span class="text-secondary-500">Deal Plus Tech</span> </div> <h1 class="text-4xl md:text-5xl font-bold text-secondary-900 mb-4"> ข้อดีของท่อ HDPE ในงานระบบน้ำ ทำไมถึงเป็นตัวเลือกยอดนิยม </h1> </header> <!-- Featured Image --> <div class="relative aspect-video bg-secondary-100 rounded-xl overflow-hidden mb-8"> <img src="/images/2021/03/hdpe-pipe_000C.jpg" alt="ข้อดีของท่อ HDPE ในงานระบบน้ำ ทำไมถึงเป็นตัวเลือกยอดนิยม" class="object-cover w-full h-full" loading="lazy"> </div> <!-- Content --> <div class="prose prose-lg max-w-none prose-headings:font-bold prose-a:text-primary-600 hover:prose-a:text-primary-700 prose-img:rounded-xl"> <h2 id="ท่อ-hdpe-คืออะไร">ท่อ HDPE คืออะไร?</h2>
|
||||
<p>ท่อ HDPE (High Density Polyethylene) หรือท่อเอชดีพีอี เป็นท่อที่ผลิตจากโพลิเอทิลีนความหนาแน่นสูง เป็นวัสดุพลาสติกที่มีความแข็งแรงและทนทานเป็นอย่างมาก</p>
|
||||
<h2 id="ข้อดีของท่อ-hdpe">ข้อดีของท่อ HDPE</h2>
|
||||
<h3 id="1-ความยืดหยุ่นสูง">1. ความยืดหยุ่นสูง</h3>
|
||||
<p>ท่อ HDPE สามารถโค้งงอได้ถึง 45 องศา ทำให้เหมาะสำหรับพื้นที่ติดตั้งจำกัด และสามารถรองรับการเคลื่อนไหวของดินได้ดี</p>
|
||||
<h3 id="2-ทนทานต่อสารเคมี">2. ทนทานต่อสารเคมี</h3>
|
||||
<p>ท่อ HDPE ทนทานต่อการกัดกร่อนของสารเคมี กรด และด่าง ทำให้เหมาะสำหรับงานอุตสาหกรรม</p>
|
||||
<h3 id="3-อายุการใช้งานยาวนาน">3. อายุการใช้งานยาวนาน</h3>
|
||||
<p>ท่อ HDPE มีอายุการใช้งานมากกว่า 50 ปี เมื่อติดตั้งและใช้งานอย่างถูกต้อง</p>
|
||||
<h3 id="4-น้ำหนักเบา">4. น้ำหนักเบา</h3>
|
||||
<p>ท่อ HDPE มีน้ำหนักเบากว่าท่อโลหะ ทำให้ง่ายต่อการขนส่งและติดตั้ง</p>
|
||||
<h3 id="5-การเชื่อมต่อที่แน่นหนา">5. การเชื่อมต่อที่แน่นหนา</h3>
|
||||
<p>การเชื่อมท่อ HDPE ด้วยวิธี Butt Fusion ทำให้ท่อเชื่อมต่อกันเป็นเนื้อเดียว ไม่มีรอยต่อ ป้องกันการรั่วซึม</p>
|
||||
<h3 id="6-ปลอดภัยต่อสุขภาพ">6. ปลอดภัยต่อสุขภาพ</h3>
|
||||
<p>ท่อ HDPE ไม่เป็นสนิม ไม่ปล่อยสารพิษ ปลอดภัยสำหรับน้ำดื่ม</p>
|
||||
<h2 id="การใช้งานท่อ-hdpe">การใช้งานท่อ HDPE</h2>
|
||||
<h3 id="งานประปา">งานประปา</h3>
|
||||
<ul>
|
||||
<li>ท่อส่งน้ำประปา</li>
|
||||
<li>ระบบประปาในบ้านเรือน</li>
|
||||
<li>ระบบประปาในอาคาร</li>
|
||||
</ul>
|
||||
<h3 id="งานเกษตร">งานเกษตร</h3>
|
||||
<ul>
|
||||
<li>ระบบน้ำหยด</li>
|
||||
<li>ระบบสปริงเกลอร์</li>
|
||||
<li>ระบบน้ำเพื่อการเกษตร</li>
|
||||
</ul>
|
||||
<h3 id="งานอุตสาหกรรม">งานอุตสาหกรรม</h3>
|
||||
<ul>
|
||||
<li>ท่อส่งสารเคมี</li>
|
||||
<li>ระบบบำบัดน้ำเสีย</li>
|
||||
<li>งานโรงงานอุตสาหกรรม</li>
|
||||
</ul>
|
||||
<h3 id="งานโครงสร้างพื้นฐาน">งานโครงสร้างพื้นฐาน</h3>
|
||||
<ul>
|
||||
<li>งานท่อใต้ดิน</li>
|
||||
<li>ท่อร้อยสายไฟ</li>
|
||||
<li>งานสาธารณูปโภค</li>
|
||||
</ul>
|
||||
<h2 id="ขนาดท่อ-hdpe-ที่นิยมใช้">ขนาดท่อ HDPE ที่นิยมใช้</h2>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<table><thead><tr><th>ขนาด (มม.)</th><th>การใช้งาน</th></tr></thead><tbody><tr><td>16-32</td><td>งานประปาภายในบ้าน</td></tr><tr><td>40-63</td><td>งานประปาอาคารขนาดเล็ก</td></tr><tr><td>75-110</td><td>งานประปาอาคารขนาดใหญ่</td></tr><tr><td>125-315</td><td>งานท่อส่งน้ำหลัก</td></tr><tr><td>355-1200</td><td>งานโครงสร้างพื้นฐาน</td></tr></tbody></table>
|
||||
<h2 id="เกรดของท่อ-hdpe">เกรดของท่อ HDPE</h2>
|
||||
<h3 id="pe80">PE80</h3>
|
||||
<ul>
|
||||
<li>เหมาะสำหรับงานทั่วไป</li>
|
||||
<li>ทนแรงดันสูงสุด 8 MPa</li>
|
||||
</ul>
|
||||
<h3 id="pe100">PE100</h3>
|
||||
<ul>
|
||||
<li>เหมาะสำหรับงานที่ต้องการความแข็งแรงสูง</li>
|
||||
<li>ทนแรงดันสูงสุด 10 MPa</li>
|
||||
<li>เป็นเกรดที่นิยมใช้ในปัจจุบัน</li>
|
||||
</ul>
|
||||
<h2 id="การติดตั้งท่อ-hdpe">การติดตั้งท่อ HDPE</h2>
|
||||
<h3 id="วิธี-butt-fusion">วิธี Butt Fusion</h3>
|
||||
<ol>
|
||||
<li>ตัดท่อให้ตรง</li>
|
||||
<li>ทำความสะอาดผิวท่อ</li>
|
||||
<li>ใช้เครื่องเชื่อมท่อ HDPE</li>
|
||||
<li>ให้ความร้อนจนผิวท่อละลาย</li>
|
||||
<li>กดท่อเข้าด้วยกัน</li>
|
||||
<li>รอให้เย็นตัวลง</li>
|
||||
</ol>
|
||||
<h3 id="วิธี-electrofusion">วิธี Electrofusion</h3>
|
||||
<ol>
|
||||
<li>ใช้ข้อต่อแบบ Electrofusion</li>
|
||||
<li>เสียบปลั๊กไฟเข้ากับข้อต่อ</li>
|
||||
<li>รอจนกระบวนการเชื่อมเสร็จสิ้น</li>
|
||||
</ol>
|
||||
<h2 id="สรุป">สรุป</h2>
|
||||
<p>ท่อ HDPE เป็นตัวเลือกที่ยอดเยี่ยมสำหรับงานระบบน้ำ เนื่องจากมีความทนทาน ความยืดหยุ่น และอายุการใช้งานที่ยาวนาน ไม่ว่าจะเป็นงานประปา งานเกษตร หรืองานอุตสาหกรรม ท่อ HDPE สามารถตอบโจทย์ได้ทุกการใช้งาน</p>
|
||||
<hr>
|
||||
<p><strong>สนใจสินค้าท่อ HDPE?</strong>
|
||||
ติดต่อเราได้ที่:</p>
|
||||
<ul>
|
||||
<li>โทร: 090-555-1415</li>
|
||||
<li>LINE: jppselection</li>
|
||||
</ul>
|
||||
<p><a href="/%E0%B8%97%E0%B9%88%E0%B8%ADhdpe">ดูสินค้าท่อ HDPE ทั้งหมด</a></p> </div> <!-- Back to Blog --> <div class="mt-12 pt-8 border-t border-secondary-200"> <a href="/blog/" class="inline-flex items-center text-primary-600 font-medium hover:text-primary-700 transition-colors"> <svg class="w-5 h-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path> </svg>
|
||||
กลับสู่หน้าบทความ
|
||||
</a> </div> </article> </main> <!-- Cookie Consent Banner --> <script type="module">const t=JSON.parse(localStorage.getItem("consent-preferences")||"null");if(t)t.analytics;else{const e=document.createElement("div");e.id="cookie-banner",e.className="fixed bottom-0 left-0 right-0 bg-secondary-900 text-white p-6 z-50 shadow-lg",e.innerHTML=`
|
||||
<div class="container mx-auto max-w-4xl">
|
||||
<p class="text-lg mb-4">เราใช้คุกกี้เพื่อปรับปรุงประสบการณ์การใช้งานเว็บไซต์ โดยคลิกยอมรับเพื่อใช้งานคุกกี้ทุกประเภท หรือคลิกปรับแต่งเพื่อเลือกคุกกี้ที่ต้องการ</p>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<button id="accept-all" class="px-6 py-2 bg-primary-600 text-white font-semibold rounded-md hover:bg-primary-700">ยอมรับ</button>
|
||||
<button id="reject-all" class="px-6 py-2 bg-secondary-700 text-white font-semibold rounded-md hover:bg-secondary-600">ปฏิเสธ</button>
|
||||
<button id="customize" class="px-6 py-2 border border-white text-white font-semibold rounded-md hover:bg-white hover:text-secondary-900">ปรับแต่ง</button>
|
||||
</div>
|
||||
</div>
|
||||
`,document.body.appendChild(e),document.getElementById("accept-all")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!0,marketing:!0,timestamp:new Date().toISOString()})),e.remove()}),document.getElementById("reject-all")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!1,marketing:!1,timestamp:new Date().toISOString()})),e.remove()}),document.getElementById("customize")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!1,marketing:!1,timestamp:new Date().toISOString()})),e.remove()})}</script> </body> </html>
|
||||
@@ -1,73 +0,0 @@
|
||||
<!DOCTYPE html><html lang="th"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="Astro v5.18.0"><meta name="description" content="ท่อ PPR (Polypropylene Random Copolymer) เป็นท่อพลาสติกที่ได้รับความนิยมสูงในการใช้งานระบบประปา บทความนี้จะอธิบายทุกสิ่งที่คุณต้องรู้เกี่ยวกับท่อ PPR"><!-- Favicon --><link rel="icon" type="image/svg+xml" href="/favicon.svg"><link rel="alternate icon" href="/favicon.ico" sizes="any"><link rel="apple-touch-icon" href="/favicon.svg"><!-- Google Fonts: Kanit for Thai --><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Kanit:wght@300;400;500;600;700&display=swap" rel="stylesheet"><!-- SEO --><meta property="og:title" content="ท่อ PPR คืออะไร? คู่มือฉบับสมบูรณ์สำหรับการเลือกใช้งาน"><meta property="og:description" content="ท่อ PPR (Polypropylene Random Copolymer) เป็นท่อพลาสติกที่ได้รับความนิยมสูงในการใช้งานระบบประปา บทความนี้จะอธิบายทุกสิ่งที่คุณต้องรู้เกี่ยวกับท่อ PPR"><meta property="og:image" content="/og-image.jpg"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><title>ท่อ PPR คืออะไร? คู่มือฉบับสมบูรณ์สำหรับการเลือกใช้งาน | ดีล พลัส เทค</title><style>html{font-family:Kanit,system-ui,sans-serif;font-size:18px}@media(min-width:1280px){html{font-size:20px}}@media(min-width:1536px){html{font-size:22px}}@media(min-width:1920px){html{font-size:24px}}
|
||||
</style></head> <body class="flex flex-col min-h-screen"> <main class="pt-32 pb-16"> <article class="container mx-auto px-4 max-w-4xl"> <!-- Header --> <header class="mb-8"> <div class="flex items-center gap-4 mb-4"> <span class="industrial-badge">ท่อ PPR</span> <time class="text-secondary-500"> 15 มกราคม 2567 </time> <span class="text-secondary-500">•</span> <span class="text-secondary-500">Deal Plus Tech</span> </div> <h1 class="text-4xl md:text-5xl font-bold text-secondary-900 mb-4"> ท่อ PPR คืออะไร? คู่มือฉบับสมบูรณ์สำหรับการเลือกใช้งาน </h1> </header> <!-- Featured Image --> <div class="relative aspect-video bg-secondary-100 rounded-xl overflow-hidden mb-8"> <img src="/images/2021/03/ppr-pipe_000C.jpg" alt="ท่อ PPR คืออะไร? คู่มือฉบับสมบูรณ์สำหรับการเลือกใช้งาน" class="object-cover w-full h-full" loading="lazy"> </div> <!-- Content --> <div class="prose prose-lg max-w-none prose-headings:font-bold prose-a:text-primary-600 hover:prose-a:text-primary-700 prose-img:rounded-xl"> <h2 id="ท่อ-ppr-คืออะไร">ท่อ PPR คืออะไร?</h2>
|
||||
<p>ท่อ PPR (Polypropylene Random Copolymer) หรือท่อพีพีอาร์ เป็นท่อพลาสติกที่ผลิตจากเม็ดพลาสติก PP-R 80 (Polypropylene Random Copolymer 80) ซึ่งเป็นวัสดุพลาสติกคุณภาพสูงที่มีความแข็งแรงและทนทานเป็นอย่างดี</p>
|
||||
<h2 id="ข้อดีของท่อ-ppr">ข้อดีของท่อ PPR</h2>
|
||||
<h3 id="1-ทนแรงดันและอุณหภูมิสูง">1. ทนแรงดันและอุณหภูมิสูง</h3>
|
||||
<p>ท่อ PPR สามารถทนแรงดันได้สูงถึง 20 บาร์ และทนต่ออุณหภูมิได้สูงถึง 95°C ทำให้เหมาะสำหรับใช้งานทั้งระบบน้ำเย็นและน้ำร้อน</p>
|
||||
<h3 id="2-สะอาดและปลอดภัย">2. สะอาดและปลอดภัย</h3>
|
||||
<p>ท่อ PPR ไม่เป็นสนิม ปราศจากโลหะหนักและสิ่งปนเปื้อน ทำให้น้ำที่ไหลผ่านสะอาดและปลอดภัยต่อการบริโภค</p>
|
||||
<h3 id="3-อายุการใช้งานยาวนาน">3. อายุการใช้งานยาวนาน</h3>
|
||||
<p>ด้วยคุณสมบัติที่ทนทาน ท่อ PPR มีอายุการใช้งานยาวนานกว่า 50 ปี</p>
|
||||
<h3 id="4-ติดตั้งง่าย">4. ติดตั้งง่าย</h3>
|
||||
<p>การเชื่อมต่อท่อ PPR ใช้วิธีเชื่อมด้วยความร้อน ทำให้ท่อและข้อต่อเป็นเนื้อเดียวกัน ไม่มีปัญหารั่วซึม</p>
|
||||
<h3 id="5-ประหยัดพลังงาน">5. ประหยัดพลังงาน</h3>
|
||||
<p>ท่อ PPR เป็นฉนวนกันความร้อนที่ดี ช่วยรักษาอุณหภูมิของน้ำได้ดีกว่าท่อโลหะ</p>
|
||||
<h2 id="การเลือกท่อ-ppr-ที่เหมาะสม">การเลือกท่อ PPR ที่เหมาะสม</h2>
|
||||
<h3 id="ขนาดท่อ">ขนาดท่อ</h3>
|
||||
<p>เลือกขนาดท่อให้เหมาะสมกับปริมาณน้ำที่ต้องการใช้งาน:</p>
|
||||
<ul>
|
||||
<li>ท่อขนาด 20-25 มม. เหมาะสำหรับบ้านเรือนทั่วไป</li>
|
||||
<li>ท่อขนาด 32-63 มม. เหมาะสำหรับอาคารขนาดใหญ่</li>
|
||||
</ul>
|
||||
<h3 id="เกรดของท่อ">เกรดของท่อ</h3>
|
||||
<ul>
|
||||
<li><strong>PN10</strong> - สำหรับน้ำเย็น ทนแรงดัน 10 บาร์</li>
|
||||
<li><strong>PN16</strong> - สำหรับน้ำอุ่น ทนแรงดัน 16 บาร์</li>
|
||||
<li><strong>PN20</strong> - สำหรับน้ำร้อน ทนแรงดัน 20 บาร์</li>
|
||||
</ul>
|
||||
<h2 id="การติดตั้งท่อ-ppr">การติดตั้งท่อ PPR</h2>
|
||||
<h3 id="ขั้นตอนการเชื่อมท่อ">ขั้นตอนการเชื่อมท่อ</h3>
|
||||
<ol>
|
||||
<li>ตัดท่อให้ตรงและเรียบ</li>
|
||||
<li>ทำความสะอาดผิวท่อและข้อต่อ</li>
|
||||
<li>ใช้เครื่องเชื่อมท่ออุณหภูมิ 260°C</li>
|
||||
<li>สอดท่อและข้อต่อเข้าด้วยกัน</li>
|
||||
<li>รอให้เย็นตัวลงประมาณ 2-3 นาที</li>
|
||||
</ol>
|
||||
<h3 id="ข้อควรระวัง">ข้อควรระวัง</h3>
|
||||
<ul>
|
||||
<li>หลีกเลี่ยงการติดตั้งในพื้นที่ที่มีแสงแดดโดยตรง</li>
|
||||
<li>ควรทิ้งระยะห่างสำหรับการขยายตัวของท่อ</li>
|
||||
<li>ตรวจสอบความร้อนของเครื่องเชื่อมก่อนใช้งาน</li>
|
||||
</ul>
|
||||
<h2 id="ท่อ-ppr-ตราช้าง">ท่อ PPR ตราช้าง</h2>
|
||||
<p>ท่อ PPR ตราช้าง เป็นท่อ PPR คุณภาพสูงที่ผลิตจากเม็ดพลาสติก PP-R 80 วัตถุดิบคุณภาพสูงมาตรฐานยุโรปจาก lyondellbasell</p>
|
||||
<p><strong>คุณสมบัติเด่น:</strong></p>
|
||||
<ul>
|
||||
<li>ทนแรงดันได้สูงสุด 20 บาร์</li>
|
||||
<li>ทนต่ออุณหภูมิได้สูงถึง 95°C</li>
|
||||
<li>ผลิตตามมาตรฐาน DIN8077 และ DIN8078 ของประเทศเยอรมัน</li>
|
||||
<li>รับประกันคุณภาพ</li>
|
||||
</ul>
|
||||
<h2 id="สรุป">สรุป</h2>
|
||||
<p>ท่อ PPR เป็นตัวเลือกที่ดีสำหรับระบบประปาในปัจจุบัน เนื่องจากมีความทนทานสูง ติดตั้งง่าย และมีอายุการใช้งานยาวนาน หากคุณกำลังมองหาท่อสำหรับงานระบบน้ำ ท่อ PPR เป็นตัวเลือกที่คุ้มค่าและเหมาะสม</p>
|
||||
<hr>
|
||||
<p><strong>สนใจสินค้าท่อ PPR?</strong>
|
||||
ติดต่อเราได้ที่:</p>
|
||||
<ul>
|
||||
<li>โทร: 090-555-1415</li>
|
||||
<li>LINE: jppselection</li>
|
||||
<li>อีเมล: <a href="mailto:dealplustech@gmail.com">dealplustech@gmail.com</a></li>
|
||||
</ul>
|
||||
<p><a href="/%E0%B8%97%E0%B9%88%E0%B8%AD%E0%B8%9E%E0%B8%B5%E0%B8%9E%E0%B8%B5%E0%B8%AD%E0%B8%B2%E0%B8%A3%E0%B9%8C%E0%B8%95%E0%B8%A3%E0%B8%B2%E0%B8%8A%E0%B9%89%E0%B8%B2%E0%B8%87">ดูสินค้าท่อ PPR ทั้งหมด</a></p> </div> <!-- Back to Blog --> <div class="mt-12 pt-8 border-t border-secondary-200"> <a href="/blog/" class="inline-flex items-center text-primary-600 font-medium hover:text-primary-700 transition-colors"> <svg class="w-5 h-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path> </svg>
|
||||
กลับสู่หน้าบทความ
|
||||
</a> </div> </article> </main> <!-- Cookie Consent Banner --> <script type="module">const t=JSON.parse(localStorage.getItem("consent-preferences")||"null");if(t)t.analytics;else{const e=document.createElement("div");e.id="cookie-banner",e.className="fixed bottom-0 left-0 right-0 bg-secondary-900 text-white p-6 z-50 shadow-lg",e.innerHTML=`
|
||||
<div class="container mx-auto max-w-4xl">
|
||||
<p class="text-lg mb-4">เราใช้คุกกี้เพื่อปรับปรุงประสบการณ์การใช้งานเว็บไซต์ โดยคลิกยอมรับเพื่อใช้งานคุกกี้ทุกประเภท หรือคลิกปรับแต่งเพื่อเลือกคุกกี้ที่ต้องการ</p>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<button id="accept-all" class="px-6 py-2 bg-primary-600 text-white font-semibold rounded-md hover:bg-primary-700">ยอมรับ</button>
|
||||
<button id="reject-all" class="px-6 py-2 bg-secondary-700 text-white font-semibold rounded-md hover:bg-secondary-600">ปฏิเสธ</button>
|
||||
<button id="customize" class="px-6 py-2 border border-white text-white font-semibold rounded-md hover:bg-white hover:text-secondary-900">ปรับแต่ง</button>
|
||||
</div>
|
||||
</div>
|
||||
`,document.body.appendChild(e),document.getElementById("accept-all")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!0,marketing:!0,timestamp:new Date().toISOString()})),e.remove()}),document.getElementById("reject-all")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!1,marketing:!1,timestamp:new Date().toISOString()})),e.remove()}),document.getElementById("customize")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!1,marketing:!1,timestamp:new Date().toISOString()})),e.remove()})}</script> </body> </html>
|
||||
@@ -1,165 +0,0 @@
|
||||
<!DOCTYPE html><html lang="th"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="Astro v5.18.0"><meta name="description" content="ปั๊มน้ำเป็นอุปกรณ์สำคัญในระบบน้ำทุกบ้าน การบำรุงรักษาที่ถูกต้องจะช่วยยืดอายุการใช้งานและประหยัดค่าไฟฟ้า"><!-- Favicon --><link rel="icon" type="image/svg+xml" href="/favicon.svg"><link rel="alternate icon" href="/favicon.ico" sizes="any"><link rel="apple-touch-icon" href="/favicon.svg"><!-- Google Fonts: Kanit for Thai --><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Kanit:wght@300;400;500;600;700&display=swap" rel="stylesheet"><!-- SEO --><meta property="og:title" content="การบำรุงรักษาปั๊มน้ำให้มีอายุการใช้งานยาวนาน"><meta property="og:description" content="ปั๊มน้ำเป็นอุปกรณ์สำคัญในระบบน้ำทุกบ้าน การบำรุงรักษาที่ถูกต้องจะช่วยยืดอายุการใช้งานและประหยัดค่าไฟฟ้า"><meta property="og:image" content="/og-image.jpg"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><title>การบำรุงรักษาปั๊มน้ำให้มีอายุการใช้งานยาวนาน | ดีล พลัส เทค</title><style>html{font-family:Kanit,system-ui,sans-serif;font-size:18px}@media(min-width:1280px){html{font-size:20px}}@media(min-width:1536px){html{font-size:22px}}@media(min-width:1920px){html{font-size:24px}}
|
||||
</style></head> <body class="flex flex-col min-h-screen"> <main class="pt-32 pb-16"> <article class="container mx-auto px-4 max-w-4xl"> <!-- Header --> <header class="mb-8"> <div class="flex items-center gap-4 mb-4"> <span class="industrial-badge">ปั๊มน้ำ</span> <time class="text-secondary-500"> 5 มกราคม 2567 </time> <span class="text-secondary-500">•</span> <span class="text-secondary-500">Deal Plus Tech</span> </div> <h1 class="text-4xl md:text-5xl font-bold text-secondary-900 mb-4"> การบำรุงรักษาปั๊มน้ำให้มีอายุการใช้งานยาวนาน </h1> </header> <!-- Featured Image --> <div class="relative aspect-video bg-secondary-100 rounded-xl overflow-hidden mb-8"> <img src="/images/2021/02/Water-Pump1.jpg" alt="การบำรุงรักษาปั๊มน้ำให้มีอายุการใช้งานยาวนาน" class="object-cover w-full h-full" loading="lazy"> </div> <!-- Content --> <div class="prose prose-lg max-w-none prose-headings:font-bold prose-a:text-primary-600 hover:prose-a:text-primary-700 prose-img:rounded-xl"> <h2 id="ความสำคัญของการบำรุงรักษาปั๊มน้ำ">ความสำคัญของการบำรุงรักษาปั๊มน้ำ</h2>
|
||||
<p>ปั๊มน้ำเป็นหัวใจของระบบน้ำในบ้าน การบำรุงรักษาอย่างสม่ำเสมอจะช่วย:</p>
|
||||
<ul>
|
||||
<li>ยืดอายุการใช้งานของปั๊มน้ำ</li>
|
||||
<li>ลดปัญหาการเสีย</li>
|
||||
<li>ประหยัดค่าไฟฟ้า</li>
|
||||
<li>ป้องกันอุบัติเหตุจากการรั่วซึม</li>
|
||||
</ul>
|
||||
<h2 id="การบำรุงรักษาปั๊มน้ำแบบทำเอง">การบำรุงรักษาปั๊มน้ำแบบทำเอง</h2>
|
||||
<h3 id="1-ตรวจสอบสายไฟและสวิตช์">1. ตรวจสอบสายไฟและสวิตช์</h3>
|
||||
<ul>
|
||||
<li>ตรวจสอบสายไฟว่ามีรอยชำรุดหรือไม่</li>
|
||||
<li>ตรวจสอบสวิตช์ว่าทำงานปกติหรือไม่</li>
|
||||
<li>หากพบความผิดปกติควรเรียกช่าง</li>
|
||||
</ul>
|
||||
<h3 id="2-ทำความสะอาดตัวกรอง">2. ทำความสะอาดตัวกรอง</h3>
|
||||
<ul>
|
||||
<li>ปิดวาล์วน้ำเข้าก่อนทำความสะอาด</li>
|
||||
<li>ถอดตัวกรองออกมาล้าง</li>
|
||||
<li>ตรวจสอบว่ามีสิ่งปนเปื้อนหรือไม่</li>
|
||||
<li>ติดตั้งกลับเข้าที่เดิม</li>
|
||||
</ul>
|
||||
<h3 id="3-ตรวจสอบแรงดันน้ำ">3. ตรวจสอบแรงดันน้ำ</h3>
|
||||
<ul>
|
||||
<li>สังเกตแรงดันน้ำว่าลดลงหรือไม่</li>
|
||||
<li>ตรวจสอบว่ามีเสียงผิดปกติหรือไม่</li>
|
||||
<li>หากแรงดันลดลงอาจมีการรั่วซึม</li>
|
||||
</ul>
|
||||
<h3 id="4-ตรวจสอบถังแรงดัน-pressure-tank">4. ตรวจสอบถังแรงดัน (Pressure Tank)</h3>
|
||||
<ul>
|
||||
<li>ตรวจสอบว่าถังมีอากาศเพียงพอหรือไม่</li>
|
||||
<li>หากปั๊มเปิด-ปิดบ่อยผิดปกติ อาจต้องเติมอากาศ</li>
|
||||
<li>ควรตรวจสอบทุก 6 เดือน</li>
|
||||
</ul>
|
||||
<h2 id="ปัญหาที่พบบ่อยและวิธีแก้ไข">ปัญหาที่พบบ่อยและวิธีแก้ไข</h2>
|
||||
<h3 id="ปั๊มไม่ทำงาน">ปั๊มไม่ทำงาน</h3>
|
||||
<p><strong>สาเหตุ:</strong></p>
|
||||
<ul>
|
||||
<li>ไฟดับหรือสายไฟขาด</li>
|
||||
<li>สวิตช์เสีย</li>
|
||||
<li>มอเตอร์เสีย</li>
|
||||
</ul>
|
||||
<p><strong>วิธีแก้:</strong></p>
|
||||
<ul>
|
||||
<li>ตรวจสอบไฟและสายไฟ</li>
|
||||
<li>เปลี่ยนสวิตช์</li>
|
||||
<li>เรียกช่างซ่อมมอเตอร์</li>
|
||||
</ul>
|
||||
<h3 id="แรงดันน้ำต่ำ">แรงดันน้ำต่ำ</h3>
|
||||
<p><strong>สาเหตุ:</strong></p>
|
||||
<ul>
|
||||
<li>ตัวกรองอุดตัน</li>
|
||||
<li>ท่อรั่ว</li>
|
||||
<li>ใบพัดสึกหรอ</li>
|
||||
</ul>
|
||||
<p><strong>วิธีแก้:</strong></p>
|
||||
<ul>
|
||||
<li>ทำความสะอาดตัวกรอง</li>
|
||||
<li>ตรวจสอบและซ่อมท่อ</li>
|
||||
<li>เปลี่ยนใบพัด</li>
|
||||
</ul>
|
||||
<h3 id="ปั๊มเปิด-ปิดบ่อย">ปั๊มเปิด-ปิดบ่อย</h3>
|
||||
<p><strong>สาเหตุ:</strong></p>
|
||||
<ul>
|
||||
<li>ถังแรงดันอากาศรั่ว</li>
|
||||
<li>แผ่นไดอะแฟรมแตก</li>
|
||||
<li>วาล์วตรวจสอบแรงดันเสีย</li>
|
||||
</ul>
|
||||
<p><strong>วิธีแก้:</strong></p>
|
||||
<ul>
|
||||
<li>เติมอากาศในถัง</li>
|
||||
<li>เปลี่ยนแผ่นไดอะแฟรม</li>
|
||||
<li>เปลี่ยนวาล์ว</li>
|
||||
</ul>
|
||||
<h3 id="ปั๊มมีเสียงดังผิดปกติ">ปั๊มมีเสียงดังผิดปกติ</h3>
|
||||
<p><strong>สาเหตุ:</strong></p>
|
||||
<ul>
|
||||
<li>ลูกปืนเสีย</li>
|
||||
<li>ใบพัดชำรุด</li>
|
||||
<li>การติดตั้งไม่แน่นหนา</li>
|
||||
</ul>
|
||||
<p><strong>วิธีแก้:</strong></p>
|
||||
<ul>
|
||||
<li>เปลี่ยนลูกปืน</li>
|
||||
<li>เปลี่ยนใบพัด</li>
|
||||
<li>ตรวจสอบการยึดแน่น</li>
|
||||
</ul>
|
||||
<h2 id="ตารางการบำรุงรักษา">ตารางการบำรุงรักษา</h2>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<table><thead><tr><th>รายการ</th><th>ความถี่</th><th>หมายเหตุ</th></tr></thead><tbody><tr><td>ตรวจสอบสายไฟ</td><td>ทุกเดือน</td><td>มองหารอยชำรุด</td></tr><tr><td>ทำความสะอาดตัวกรอง</td><td>ทุก 3 เดือน</td><td>หรือเมื่อแรงดันลด</td></tr><tr><td>ตรวจสอบถังแรงดัน</td><td>ทุก 6 เดือน</td><td>เติมอากาศหากจำเป็น</td></tr><tr><td>ตรวจสอบสวิตช์</td><td>ทุกปี</td><td>เปลี่ยนหากเสีย</td></tr><tr><td>ตรวจสอบใบพัด</td><td>ทุก 2 ปี</td><td>โดยช่างผู้เชี่ยวชาญ</td></tr></tbody></table>
|
||||
<h2 id="เคล็ดลับการใช้งานปั๊มน้ำ">เคล็ดลับการใช้งานปั๊มน้ำ</h2>
|
||||
<h3 id="ประหยัดไฟฟ้า">ประหยัดไฟฟ้า</h3>
|
||||
<ul>
|
||||
<li>เลือกขนาดปั๊มที่เหมาะสมกับการใช้งาน</li>
|
||||
<li>ติดตั้งถังแรงดันขนาดเหมาะสม</li>
|
||||
<li>หลีกเลี่ยงการเปิด-ปิดปั๊มบ่อย</li>
|
||||
</ul>
|
||||
<h3 id="ป้องกันปัญหา">ป้องกันปัญหา</h3>
|
||||
<ul>
|
||||
<li>อย่าให้ปั๊มแห้ง (ทำงานโดยไม่มีน้ำ)</li>
|
||||
<li>ตรวจสอบรอยรั่วอย่างสม่ำเสมอ</li>
|
||||
<li>ใช้ตัวกรองเพื่อป้องกันสิ่งสกปรก</li>
|
||||
</ul>
|
||||
<h3 id="เมื่อต้องเปลี่ยนปั๊ม">เมื่อต้องเปลี่ยนปั๊ม</h3>
|
||||
<ul>
|
||||
<li>เลือกปั๊มที่มีคุณภาพ</li>
|
||||
<li>พิจารณาขนาดและกำลังที่เหมาะสม</li>
|
||||
<li>ติดตั้งโดยช่างผู้เชี่ยวชาญ</li>
|
||||
</ul>
|
||||
<h2 id="สรุป">สรุป</h2>
|
||||
<p>การบำรุงรักษาปั๊มน้ำอย่างสม่ำเสมอจะช่วยยืดอายุการใช้งาน ลดปัญหาการเสีย และประหยัดค่าใช้จ่ายในระยะยาว ควรตรวจสอบและบำรุงรักษาตามตารางที่กำหนด และหากพบปัญหาที่ไม่สามารถแก้ไขได้เอง ควรติดต่อช่างผู้เชี่ยวชาญ</p>
|
||||
<hr>
|
||||
<p><strong>ต้องการซื้อปั๊มน้ำหรืออุปกรณ์เสริม?</strong>
|
||||
ติดต่อเราได้ที่:</p>
|
||||
<ul>
|
||||
<li>โทร: 090-555-1415</li>
|
||||
<li>LINE: jppselection</li>
|
||||
</ul>
|
||||
<p><a href="/%E0%B8%9B%E0%B8%B1%E0%B9%8A%E0%B8%A1%E0%B8%99%E0%B9%89%E0%B8%B3-pump">ดูสินค้าปั๊มน้ำทั้งหมด</a></p> </div> <!-- Back to Blog --> <div class="mt-12 pt-8 border-t border-secondary-200"> <a href="/blog/" class="inline-flex items-center text-primary-600 font-medium hover:text-primary-700 transition-colors"> <svg class="w-5 h-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path> </svg>
|
||||
กลับสู่หน้าบทความ
|
||||
</a> </div> </article> </main> <!-- Cookie Consent Banner --> <script type="module">const t=JSON.parse(localStorage.getItem("consent-preferences")||"null");if(t)t.analytics;else{const e=document.createElement("div");e.id="cookie-banner",e.className="fixed bottom-0 left-0 right-0 bg-secondary-900 text-white p-6 z-50 shadow-lg",e.innerHTML=`
|
||||
<div class="container mx-auto max-w-4xl">
|
||||
<p class="text-lg mb-4">เราใช้คุกกี้เพื่อปรับปรุงประสบการณ์การใช้งานเว็บไซต์ โดยคลิกยอมรับเพื่อใช้งานคุกกี้ทุกประเภท หรือคลิกปรับแต่งเพื่อเลือกคุกกี้ที่ต้องการ</p>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<button id="accept-all" class="px-6 py-2 bg-primary-600 text-white font-semibold rounded-md hover:bg-primary-700">ยอมรับ</button>
|
||||
<button id="reject-all" class="px-6 py-2 bg-secondary-700 text-white font-semibold rounded-md hover:bg-secondary-600">ปฏิเสธ</button>
|
||||
<button id="customize" class="px-6 py-2 border border-white text-white font-semibold rounded-md hover:bg-white hover:text-secondary-900">ปรับแต่ง</button>
|
||||
</div>
|
||||
</div>
|
||||
`,document.body.appendChild(e),document.getElementById("accept-all")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!0,marketing:!0,timestamp:new Date().toISOString()})),e.remove()}),document.getElementById("reject-all")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!1,marketing:!1,timestamp:new Date().toISOString()})),e.remove()}),document.getElementById("customize")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!1,marketing:!1,timestamp:new Date().toISOString()})),e.remove()})}</script> </body> </html>
|
||||
35
dealplustech-astro/dist/cookie-policy/index.html
vendored
35
dealplustech-astro/dist/cookie-policy/index.html
vendored
@@ -1,35 +0,0 @@
|
||||
<!DOCTYPE html><html lang="th"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="Astro v5.18.0"><meta name="description" content="นโยบายการใช้งานคุกกี้ของเว็บไซต์บริษัท ดีล พลัส เทค จำกัด"><!-- Favicon --><link rel="icon" type="image/svg+xml" href="/favicon.svg"><link rel="alternate icon" href="/favicon.ico" sizes="any"><link rel="apple-touch-icon" href="/favicon.svg"><!-- Google Fonts: Kanit for Thai --><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Kanit:wght@300;400;500;600;700&display=swap" rel="stylesheet"><!-- SEO --><meta property="og:title" content="นโยบายคุกกี้"><meta property="og:description" content="นโยบายการใช้งานคุกกี้ของเว็บไซต์บริษัท ดีล พลัส เทค จำกัด"><meta property="og:image" content="/og-image.jpg"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><title>นโยบายคุกกี้ | ดีล พลัส เทค</title><style>html{font-family:Kanit,system-ui,sans-serif;font-size:18px}@media(min-width:1280px){html{font-size:20px}}@media(min-width:1536px){html{font-size:22px}}@media(min-width:1920px){html{font-size:24px}}
|
||||
</style></head> <body class="flex flex-col min-h-screen"> <main class="min-h-screen bg-secondary-50"> <div class="container mx-auto px-4 py-12"> <div class="max-w-4xl mx-auto bg-white rounded-lg shadow-lg p-8 md:p-12"> <h1 class="text-4xl font-bold text-secondary-900 mb-4">นโยบายคุกกี้</h1> <p class="text-secondary-600 mb-8">Cookie Policy - ปรับปรุงล่าสุด: 9 มีนาคม 2026</p> <div class="prose prose-lg max-w-none text-secondary-700"> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">1. คุกกี้คืออะไร?</h2> <p class="mb-4">
|
||||
คุกกี้ (Cookie) คือไฟล์ข้อความขนาดเล็กที่เว็บไซต์บันทึกลงบนอุปกรณ์ของท่าน
|
||||
(คอมพิวเตอร์, แท็บเล็ต, หรือมือถือ) เมื่อท่านเยี่ยมชมเว็บไซต์
|
||||
คุกกี้ช่วยให้เว็บไซต์จดจำการกระทำและความชอบของท่าน ทำให้ประสบการณ์การใช้งานดีขึ้น
|
||||
</p> </section> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">2. ประเภทคุกกี้ที่เราใช้</h2> <p class="mb-4">เราใช้คุกกี้ 3 ประเภท:</p> <div class="space-y-4"> <div class="bg-secondary-50 p-4 rounded-lg"> <h3 class="text-lg font-semibold mb-2">🔒 คุกกี้ที่จำเป็น (Essential Cookies)</h3> <p class="text-sm">
|
||||
คุกกี้เหล่านี้จำเป็นสำหรับการทำงานของเว็บไซต์ ไม่สามารถปิดใช้งานได้
|
||||
ใช้สำหรับ: การจัดการเซสชัน, ความปลอดภัย, การทำงานพื้นฐานของเว็บไซต์
|
||||
</p> <p class="text-sm mt-2"><strong>ความยินยอม:</strong> ไม่จำเป็น (เปิดเสมอ)</p> </div> <div class="bg-secondary-50 p-4 rounded-lg"> <h3 class="text-lg font-semibold mb-2">📊 คุกกี้วิเคราะห์ (Analytics Cookies)</h3> <p class="text-sm">
|
||||
คุกกี้เหล่านี้帮助我们เก็บข้อมูลการใช้งานเว็บไซต์แบบไม่ระบุตัวตน
|
||||
ใช้สำหรับ: การวิเคราะห์ผู้เยี่ยมชม, หน้าเว็บที่นิยม, อัตราการตีกลับ
|
||||
</p> <p class="text-sm mt-2"><strong>ความยินยอม:</strong> ต้องเปิดใช้งาน (Opt-in)</p> </div> <div class="bg-secondary-50 p-4 rounded-lg"> <h3 class="text-lg font-semibold mb-2">📢 คุกกี้การตลาด (Marketing Cookies)</h3> <p class="text-sm">
|
||||
คุกกี้เหล่านี้ใช้เพื่อติดตามผู้ใช้งานบนเว็บไซต์ต่าง ๆ
|
||||
ใช้สำหรับ: การโฆษณาที่กำหนดเป้าหมาย, การวัดประสิทธิภาพโฆษณา
|
||||
</p> <p class="text-sm mt-2"><strong>ความยินยอม:</strong> ต้องเปิดใช้งาน (Opt-in)</p> </div> </div> </section> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">3. คุกกี้ที่เราใช้</h2> <div class="overflow-x-auto"> <table class="min-w-full border"> <thead class="bg-secondary-100"> <tr> <th class="px-4 py-2 border text-left">ชื่อคุกกี้</th> <th class="px-4 py-2 border text-left">ประเภท</th> <th class="px-4 py-2 border text-left">ระยะเวลา</th> <th class="px-4 py-2 border text-left">วัตถุประสงค์</th> </tr> </thead> <tbody> <tr> <td class="px-4 py-2 border">session_id</td> <td class="px-4 py-2 border">จำเป็น</td> <td class="px-4 py-2 border">จนกว่าจะปิดเบราว์เซอร์</td> <td class="px-4 py-2 border">จัดการเซสชัน</td> </tr> <tr> <td class="px-4 py-2 border">consent-preferences</td> <td class="px-4 py-2 border">จำเป็น</td> <td class="px-4 py-2 border">1 ปี</td> <td class="px-4 py-2 border">บันทึกการตั้งค่าคุกกี้</td> </tr> <tr> <td class="px-4 py-2 border">umami analytics</td> <td class="px-4 py-2 border">วิเคราะห์</td> <td class="px-4 py-2 border">ไม่ใช้คุกกี้</td> <td class="px-4 py-2 border">วิเคราะห์การใช้งาน (Privacy-first)</td> </tr> </tbody> </table> </div> </section> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">4. การจัดการคุกกี้</h2> <p class="mb-4">ท่านสามารถจัดการการตั้งค่าคุกกี้ได้โดย:</p> <ul class="list-disc pl-6 space-y-2"> <li><strong>แบนเนอร์คุกกี้:</strong> คลิกที่ปุ่ม "ปรับแต่ง" ในแบนเนอร์คุกกี้เพื่อเลือกคุกกี้ที่ต้องการ</li> <li><strong>การตั้งค่าเบราว์เซอร์:</strong> เบราว์เซอร์ส่วนใหญ่ยอมให้ท่านบล็อกหรือลบคุกกี้ได้</li> <li><strong>ลิงก์ในฟุตเตอร์:</strong> คลิก "การตั้งค่าคุกกี้" ที่ด้านล่างของหน้าเว็บ</li> </ul> <p class="mt-4"> <a href="#" id="openPreferences" class="text-primary-600 hover:underline font-semibold">
|
||||
→ เปิดการตั้งค่าคุกกี้ตอนนี้
|
||||
</a> </p> </section> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">5. การเพิกถอนความยินยอม</h2> <p class="mb-4">
|
||||
ท่านสามารถเพิกถอนความยินยอมสำหรับคุกกี้วิเคราะห์และคุกกี้การตลาดเมื่อใดก็ได้
|
||||
โดยไปที่การตั้งค่าคุกกี้และปิดการใช้งานคุกกี้เหล่านั้น
|
||||
การเพิกถอนความยินยอมจะไม่มีผลต่อความถูกต้องของการประมวลผลก่อนการเพิกถอน
|
||||
</p> </section> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">6. การอัปเดตนโยบาย</h2> <p class="mb-4">
|
||||
เราอาจอัปเดตนโยบายคุกกี้นี้เป็นครั้งคราว การเปลี่ยนแปลงใด ๆ จะถูกเผยแพร่บนหน้านี้
|
||||
กรุณาตรวจสอบหน้าทนี้เป็นระยะเพื่อดูการเปลี่ยนแปลง
|
||||
</p> </section> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">7. การติดต่อ</h2> <p class="mb-4">หากมีคำถามเกี่ยวกับนโยบายคุกกี้นี้ กรุณาติดต่อ:</p> <div class="bg-secondary-50 p-4 rounded-lg"> <p><strong>บริษัท ดีล พลัส เทค จำกัด</strong></p> <p>อีเมล: info@dealplustech.co.th</p> <p>โทรศัพท์: 090-555-1415</p> </div> </section> <section class="mt-12 pt-8 border-t border-secondary-200"> <p class="text-sm text-secondary-600">
|
||||
อ่านเพิ่มเติม: <a href="/privacy-policy/" class="text-primary-600 hover:underline">นโยบายความเป็นส่วนตัว</a> |
|
||||
<a href="/terms-and-conditions/" class="text-primary-600 hover:underline">ข้อกำหนดและเงื่อนไข</a> </p> </section> </div> </div> </div> </main> <!-- Cookie Consent Banner --> <script type="module">const t=JSON.parse(localStorage.getItem("consent-preferences")||"null");if(t)t.analytics;else{const e=document.createElement("div");e.id="cookie-banner",e.className="fixed bottom-0 left-0 right-0 bg-secondary-900 text-white p-6 z-50 shadow-lg",e.innerHTML=`
|
||||
<div class="container mx-auto max-w-4xl">
|
||||
<p class="text-lg mb-4">เราใช้คุกกี้เพื่อปรับปรุงประสบการณ์การใช้งานเว็บไซต์ โดยคลิกยอมรับเพื่อใช้งานคุกกี้ทุกประเภท หรือคลิกปรับแต่งเพื่อเลือกคุกกี้ที่ต้องการ</p>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<button id="accept-all" class="px-6 py-2 bg-primary-600 text-white font-semibold rounded-md hover:bg-primary-700">ยอมรับ</button>
|
||||
<button id="reject-all" class="px-6 py-2 bg-secondary-700 text-white font-semibold rounded-md hover:bg-secondary-600">ปฏิเสธ</button>
|
||||
<button id="customize" class="px-6 py-2 border border-white text-white font-semibold rounded-md hover:bg-white hover:text-secondary-900">ปรับแต่ง</button>
|
||||
</div>
|
||||
</div>
|
||||
`,document.body.appendChild(e),document.getElementById("accept-all")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!0,marketing:!0,timestamp:new Date().toISOString()})),e.remove()}),document.getElementById("reject-all")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!1,marketing:!1,timestamp:new Date().toISOString()})),e.remove()}),document.getElementById("customize")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!1,marketing:!1,timestamp:new Date().toISOString()})),e.remove()})}</script> </body> </html> <script type="module">document.getElementById("openPreferences")?.addEventListener("click",e=>{e.preventDefault(),window.dispatchEvent(new CustomEvent("open-cookie-preferences"))});</script>
|
||||
BIN
dealplustech-astro/dist/favicon.ico
vendored
BIN
dealplustech-astro/dist/favicon.ico
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 655 B |
9
dealplustech-astro/dist/favicon.svg
vendored
9
dealplustech-astro/dist/favicon.svg
vendored
@@ -1,9 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
|
||||
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
|
||||
<style>
|
||||
path { fill: #000; }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
path { fill: #FFF; }
|
||||
}
|
||||
</style>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 749 B |
45
dealplustech-astro/dist/index.html
vendored
45
dealplustech-astro/dist/index.html
vendored
File diff suppressed because one or more lines are too long
@@ -1,32 +0,0 @@
|
||||
<!DOCTYPE html><html lang="th"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="Astro v5.18.0"><meta name="description" content="นโยบายความเป็นส่วนตัวตามกฎหมายคุ้มครองข้อมูลส่วนบุคคล (PDPA) ของบริษัท ดีล พลัส เทค จำกัด"><!-- Favicon --><link rel="icon" type="image/svg+xml" href="/favicon.svg"><link rel="alternate icon" href="/favicon.ico" sizes="any"><link rel="apple-touch-icon" href="/favicon.svg"><!-- Google Fonts: Kanit for Thai --><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Kanit:wght@300;400;500;600;700&display=swap" rel="stylesheet"><!-- SEO --><meta property="og:title" content="นโยบายความเป็นส่วนตัว"><meta property="og:description" content="นโยบายความเป็นส่วนตัวตามกฎหมายคุ้มครองข้อมูลส่วนบุคคล (PDPA) ของบริษัท ดีล พลัส เทค จำกัด"><meta property="og:image" content="/og-image.jpg"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><title>นโยบายความเป็นส่วนตัว | ดีล พลัส เทค</title><style>html{font-family:Kanit,system-ui,sans-serif;font-size:18px}@media(min-width:1280px){html{font-size:20px}}@media(min-width:1536px){html{font-size:22px}}@media(min-width:1920px){html{font-size:24px}}
|
||||
</style></head> <body class="flex flex-col min-h-screen"> <main class="min-h-screen bg-secondary-50"> <div class="container mx-auto px-4 py-12"> <div class="max-w-4xl mx-auto bg-white rounded-lg shadow-lg p-8 md:p-12"> <h1 class="text-4xl font-bold text-secondary-900 mb-4">นโยบายความเป็นส่วนตัว</h1> <p class="text-secondary-600 mb-8">Privacy Policy - ปรับปรุงล่าสุด: 9 มีนาคม 2026</p> <nav class="mb-8 p-4 bg-secondary-50 rounded-lg"> <h2 class="text-lg font-semibold mb-3">สารบัญ</h2> <ul class="space-y-1 text-primary-600"> <li><a href="#section1" class="hover:underline">1. ข้อมูลผู้ควบคุมข้อมูลส่วนบุคคล</a></li> <li><a href="#section2" class="hover:underline">2. ประเภทข้อมูลที่เก็บรวบรวม</a></li> <li><a href="#section3" class="hover:underline">3. วัตถุประสงค์การเก็บรวบรวม</a></li> <li><a href="#section4" class="hover:underline">4. ฐานทางกฎหมายสำหรับการประมวลผล</a></li> <li><a href="#section5" class="hover:underline">5. ระยะเวลาเก็บรักษาข้อมูล</a></li> <li><a href="#section6" class="hover:underline">6. การเปิดเผยข้อมูล</a></li> <li><a href="#section9" class="hover:underline">7. คุกกี้และเทคโนโลยีการติดตาม</a></li> <li><a href="#section10" class="hover:underline">8. สิทธิของเจ้าของข้อมูล</a></li> <li><a href="#section11" class="hover:underline">9. มาตรการรักษาความปลอดภัย</a></li> <li><a href="#section13" class="hover:underline">10. สิทธิร้องเรียน</a></li> </ul> </nav> <div class="prose prose-lg max-w-none"> <section id="section1" class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">1. ข้อมูลผู้ควบคุมข้อมูลส่วนบุคคล</h2> <p class="text-secondary-700 mb-4"> <strong>บริษัท ดีล พลัส เทค จำกัด</strong> เป็นผู้ควบคุมข้อมูลส่วนบุคคล (Data Controller)
|
||||
ซึ่งมีหน้าที่ในการตัดสินใจเกี่ยวกับการเก็บรวบรวม ใช้ หรือเปิดเผยข้อมูลส่วนบุคคล
|
||||
</p> <div class="bg-secondary-50 p-4 rounded-lg"> <p class="text-secondary-700"><strong>ที่อยู่:</strong> 9/70 ซอยนครลุง 17 แขวงบางไผ่ เขตบางแค กทม. 10160</p> <p class="text-secondary-700"><strong>เบอร์โทรศัพท์:</strong> 090-555-1415</p> <p class="text-secondary-700"><strong>อีเมล:</strong> info@dealplustech.co.th</p> </div> </section> <section id="section2" class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">2. ประเภทข้อมูลที่เก็บรวบรวม</h2> <p class="text-secondary-700 mb-4">เราเก็บรวบรวมข้อมูลส่วนบุคคลดังนี้:</p> <ul class="list-disc pl-6 space-y-2 text-secondary-700"> <li><strong>ข้อมูลส่วนบุคคลทั่วไป:</strong> ชื่อ, นามสกุล, ที่อยู่อีเมล, เบอร์โทรศัพท์</li> <li><strong>ข้อมูลการใช้งาน:</strong> IP Address, Browser Type, Device Information, Cookie Data</li> <li><strong>ข้อมูลการติดต่อ:</strong> ข้อความหรือคำถามที่ท่านส่งถึงเรา</li> </ul> </section> <section id="section3" class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">3. วัตถุประสงค์การเก็บรวบรวม</h2> <p class="text-secondary-700 mb-4">เราเก็บรวบรวมข้อมูลเพื่อวัตถุประสงค์ดังนี้:</p> <ul class="list-disc pl-6 space-y-2 text-secondary-700"> <li>เพื่อให้บริการและตอบคำถามหรือคำขอของท่าน</li> <li>เพื่อปรับปรุงประสบการณ์การใช้งานเว็บไซต์</li> <li>เพื่อส่งข้อมูลข่าวสารและการตลาด (เมื่อได้รับความยินยอม)</li> <li>เพื่อวิเคราะห์และปรับปรุงบริการของเรา</li> <li>เพื่อปฏิบัติตามกฎหมายและข้อบังคับที่เกี่ยวข้อง</li> </ul> </section> <section id="section4" class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">4. ฐานทางกฎหมายสำหรับการประมวลผล</h2> <p class="text-secondary-700 mb-4">เราประมวลผลข้อมูลส่วนบุคคลภายใต้ฐานทางกฎหมายดังนี้:</p> <ul class="list-disc pl-6 space-y-2 text-secondary-700"> <li><strong>ความยินยอม (Consent):</strong> สำหรับการส่งข้อมูลการตลาดและการใช้คุกกี้บางประเภท</li> <li><strong>การปฏิบัติตามสัญญา (Contract):</strong> เพื่อให้บริการที่ท่านร้องขอ</li> <li><strong>ผลประโยชน์โดยชอบด้วยกฎหมาย (Legitimate Interest):</strong> เพื่อปรับปรุงบริการและวิเคราะห์การใช้งาน</li> <li><strong>การปฏิบัติตามกฎหมาย (Legal Obligation):</strong> เมื่อจำเป็นต้องปฏิบัติตามกฎหมาย</li> </ul> </section> <section id="section5" class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">5. ระยะเวลาเก็บรักษาข้อมูล</h2> <p class="text-secondary-700 mb-4">
|
||||
เราเก็บรักษาข้อมูลส่วนบุคคลเป็นเวลา <strong>10 ปี</strong> ตามข้อกำหนดของกฎหมาย PDPA
|
||||
หรือตราบเท่าที่จำเป็นสำหรับวัตถุประสงค์ที่ระบุไว้ข้างต้น
|
||||
หลังจากสิ้นสุดระยะเวลาเก็บรักษา เราจะทำลายหรือทำให้ข้อมูลไม่สามารถระบุตัวตนได้
|
||||
</p> </section> <section id="section6" class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">6. การเปิดเผยข้อมูล</h2> <p class="text-secondary-700 mb-4">
|
||||
เราจะไม่เปิดเผยข้อมูลส่วนบุคคลของท่านให้กับบุคคลภายนอก เว้นแต่:
|
||||
</p> <ul class="list-disc pl-6 space-y-2 text-secondary-700"> <li>ท่านให้ความยินยอมอย่างชัดเจน</li> <li>จำเป็นต้องปฏิบัติตามกฎหมายหรือคำสั่งศาล</li> <li>จำเป็นสำหรับการให้บริการที่ท่านร้องขอ (เช่น ผู้ให้บริการจัดส่ง)</li> <li>เพื่อปกป้องสิทธิและความปลอดภัยของเราและผู้อื่น</li> </ul> </section> <section id="section9" class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">7. คุกกี้และเทคโนโลยีการติดตาม</h2> <p class="text-secondary-700 mb-4">
|
||||
เราใช้คุกกี้และเทคโนโลยีการติดตามเพื่อปรับปรุงประสบการณ์การใช้งานเว็บไซต์ ท่านสามารถจัดการการตั้งค่าคุกกี้ได้ที่
|
||||
<a href="/cookie-policy/" class="text-primary-600 hover:underline">นโยบายคุกกี้</a> </p> </section> <section id="section10" class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">8. สิทธิของเจ้าของข้อมูล</h2> <p class="text-secondary-700 mb-4">
|
||||
ภายใต้กฎหมาย PDPA ท่านมีสิทธิดังต่อไปนี้:
|
||||
</p> <ul class="list-disc pl-6 space-y-2 text-secondary-700"> <li><strong>สิทธิขอเข้าถึง:</strong> ขอรับสำเนาข้อมูลส่วนบุคคลที่ท่านให้ไว้</li> <li><strong>สิทธิขอแก้ไข:</strong> ขอให้แก้ไขข้อมูลที่ไม่ถูกต้อง</li> <li><strong>สิทธิขอ ลบ:</strong> ขอให้ ลบข้อมูลส่วนบุคคล (Right to Erasure)</li> <li><strong>สิทธิขอระงับ:</strong> ขอให้ระงับการประมวลผลข้อมูล</li> <li><strong>สิทธิขอพกพา:</strong> ขอรับข้อมูลในรูปแบบที่อ่านได้ทั่วไป</li> <li><strong>สิทธิคัดค้าน:</strong> คัดค้านการประมวลผลข้อมูล</li> <li><strong>สิทธิเพิกถอนความยินยอม:</strong> เพิกถอนความยินยอมที่ได้ให้ไว้ก่อนหน้า</li> <li><strong>สิทธิร้องเรียน:</strong> ร้องเรียนต่อคณะกรรมการคุ้มครองข้อมูลส่วนบุคคล</li> </ul> <p class="text-secondary-700 mt-4">
|
||||
หากท่านต้องการใช้สิทธิเหล่านี้ กรุณาติดต่อเราที่ info@dealplustech.co.th
|
||||
</p> </section> <section id="section11" class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">9. มาตรการรักษาความปลอดภัย</h2> <p class="text-secondary-700 mb-4">
|
||||
เราใช้มาตรการรักษาความปลอดภัยที่เหมาะสมเพื่อปกป้องข้อมูลส่วนบุคคลของท่านจากการเข้าถึง
|
||||
การใช้ การแก้ไข หรือการเปิดเผยโดยไม่ได้รับอนุญาต มาตรการเหล่านี้รวมถึง:
|
||||
</p> <ul class="list-disc pl-6 space-y-2 text-secondary-700"> <li>การเข้ารหัสข้อมูล (Encryption)</li> <li>การควบคุมการเข้าถึง (Access Control)</li> <li>การสำรองข้อมูลเป็นประจำ</li> <li>การฝึกอบรมพนักงานเรื่องการคุ้มครองข้อมูล</li> </ul> </section> <section id="section13" class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">10. สิทธิร้องเรียน</h2> <p class="text-secondary-700 mb-4">
|
||||
หากท่านเชื่อว่ามีการละเมิดกฎหมาย PDPA ท่านมีสิทธิร้องเรียนต่อ:
|
||||
</p> <div class="bg-secondary-50 p-4 rounded-lg"> <p class="text-secondary-700"> <strong>คณะกรรมการคุ้มครองข้อมูลส่วนบุคคล (PDPC)</strong> </p> <p class="text-secondary-700">เว็บไซต์: www.pdpc.or.th</p> <p class="text-secondary-700">อีเมล: info@pdpc.or.th</p> </div> </section> <section class="mt-12 pt-8 border-t border-secondary-200"> <h2 class="text-xl font-bold text-secondary-900 mb-4">การติดต่อ</h2> <p class="text-secondary-700">
|
||||
หากมีคำถามเกี่ยวกับนโยบายความเป็นส่วนตัวนี้ กรุณาติดต่อ:
|
||||
</p> <div class="mt-4"> <p class="text-secondary-700"><strong>บริษัท ดีล พลัส เทค จำกัด</strong></p> <p class="text-secondary-700">อีเมล: info@dealplustech.co.th</p> <p class="text-secondary-700">โทรศัพท์: 090-555-1415</p> </div> </section> </div> </div> </div> </main> <!-- Cookie Consent Banner --> <script type="module">const t=JSON.parse(localStorage.getItem("consent-preferences")||"null");if(t)t.analytics;else{const e=document.createElement("div");e.id="cookie-banner",e.className="fixed bottom-0 left-0 right-0 bg-secondary-900 text-white p-6 z-50 shadow-lg",e.innerHTML=`
|
||||
<div class="container mx-auto max-w-4xl">
|
||||
<p class="text-lg mb-4">เราใช้คุกกี้เพื่อปรับปรุงประสบการณ์การใช้งานเว็บไซต์ โดยคลิกยอมรับเพื่อใช้งานคุกกี้ทุกประเภท หรือคลิกปรับแต่งเพื่อเลือกคุกกี้ที่ต้องการ</p>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<button id="accept-all" class="px-6 py-2 bg-primary-600 text-white font-semibold rounded-md hover:bg-primary-700">ยอมรับ</button>
|
||||
<button id="reject-all" class="px-6 py-2 bg-secondary-700 text-white font-semibold rounded-md hover:bg-secondary-600">ปฏิเสธ</button>
|
||||
<button id="customize" class="px-6 py-2 border border-white text-white font-semibold rounded-md hover:bg-white hover:text-secondary-900">ปรับแต่ง</button>
|
||||
</div>
|
||||
</div>
|
||||
`,document.body.appendChild(e),document.getElementById("accept-all")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!0,marketing:!0,timestamp:new Date().toISOString()})),e.remove()}),document.getElementById("reject-all")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!1,marketing:!1,timestamp:new Date().toISOString()})),e.remove()}),document.getElementById("customize")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!1,marketing:!1,timestamp:new Date().toISOString()})),e.remove()})}</script> </body> </html>
|
||||
11
dealplustech-astro/dist/products/index.html
vendored
11
dealplustech-astro/dist/products/index.html
vendored
File diff suppressed because one or more lines are too long
52
dealplustech-astro/dist/services/index.html
vendored
52
dealplustech-astro/dist/services/index.html
vendored
@@ -1,52 +0,0 @@
|
||||
<!DOCTYPE html><html lang="th"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="Astro v5.18.0"><meta name="description" content="บริการครบวงจร จำหน่ายวัสดุท่อ ให้คำปรึกษา ออกแบบระบบ และติดตั้ง"><!-- Favicon --><link rel="icon" type="image/svg+xml" href="/favicon.svg"><link rel="alternate icon" href="/favicon.ico" sizes="any"><link rel="apple-touch-icon" href="/favicon.svg"><!-- Google Fonts: Kanit for Thai --><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Kanit:wght@300;400;500;600;700&display=swap" rel="stylesheet"><!-- SEO --><meta property="og:title" content="บริการของเรา"><meta property="og:description" content="บริการครบวงจร จำหน่ายวัสดุท่อ ให้คำปรึกษา ออกแบบระบบ และติดตั้ง"><meta property="og:image" content="/og-image.jpg"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><title>บริการของเรา | ดีล พลัส เทค</title><style>html{font-family:Kanit,system-ui,sans-serif;font-size:18px}@media(min-width:1280px){html{font-size:20px}}@media(min-width:1536px){html{font-size:22px}}@media(min-width:1920px){html{font-size:24px}}
|
||||
</style></head> <body class="flex flex-col min-h-screen"> <main> <!-- Hero Section --> <section class="relative h-[50vh] min-h-[400px] bg-secondary-900"> <div class="absolute inset-0 bg-gradient-to-r from-secondary-900 via-secondary-900/90 to-secondary-900/60 z-10"></div> <img src="/images/2021/03/hdpe-pipe_000C.jpg" alt="บริการของเรา" class="absolute inset-0 w-full h-full object-cover opacity-40" loading="eager"> <div class="relative z-20 container mx-auto px-4 h-full flex items-center"> <div class="max-w-2xl"> <span class="inline-block px-4 py-2 bg-primary-600 text-white font-semibold mb-4 rounded">
|
||||
บริการครบวงจร
|
||||
</span> <h1 class="text-4xl md:text-5xl lg:text-6xl font-bold text-white mb-6">
|
||||
บริการ<span class="text-primary-400">ของเรา</span> </h1> <p class="text-xl text-secondary-200">
|
||||
ตั้งแต่การให้คำปรึกษา ออกแบบ จัดส่ง จนถึงติดตั้ง เราพร้อมดูแลโครงการของคุณครบวงจร
|
||||
</p> </div> </div> </section> <!-- Services Grid --> <section class="py-20 bg-white"> <div class="container mx-auto px-4"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"> <!-- Service 1 --> <div class="group p-8 bg-secondary-50 rounded-2xl hover:bg-primary-600 transition-all duration-300 hover:shadow-xl"> <div class="w-16 h-16 bg-primary-600 text-white rounded-xl flex items-center justify-center mb-6 group-hover:bg-white group-hover:text-primary-600 transition-colors"> <svg class="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path> </svg> </div> <h3 class="text-xl font-bold text-secondary-900 mb-3 group-hover:text-white transition-colors">
|
||||
จำหน่ายวัสดุท่อ
|
||||
</h3> <p class="text-secondary-600 group-hover:text-primary-100 transition-colors">
|
||||
จำหน่ายท่อพีพีอาร์ ท่อ HDPE ท่อ PVC วาล์ว และอุปกรณ์ต่อท่อครบวงจร สินค้าคุณภาพ ราคาแข่งขันได้
|
||||
</p> </div> <!-- Service 2 --> <div class="group p-8 bg-secondary-50 rounded-2xl hover:bg-primary-600 transition-all duration-300 hover:shadow-xl"> <div class="w-16 h-16 bg-primary-600 text-white rounded-xl flex items-center justify-center mb-6 group-hover:bg-white group-hover:text-primary-600 transition-colors"> <svg class="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path> </svg> </div> <h3 class="text-xl font-bold text-secondary-900 mb-3 group-hover:text-white transition-colors">
|
||||
ให้คำปรึกษา
|
||||
</h3> <p class="text-secondary-600 group-hover:text-primary-100 transition-colors">
|
||||
ทีมงานมืออาชีพพร้อมให้คำปรึกษาเกี่ยวกับการเลือกวัสดุท่อที่เหมาะสมกับโครงการของคุณ
|
||||
</p> </div> <!-- Service 3 --> <div class="group p-8 bg-secondary-50 rounded-2xl hover:bg-primary-600 transition-all duration-300 hover:shadow-xl"> <div class="w-16 h-16 bg-primary-600 text-white rounded-xl flex items-center justify-center mb-6 group-hover:bg-white group-hover:text-primary-600 transition-colors"> <svg class="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2"></path> </svg> </div> <h3 class="text-xl font-bold text-secondary-900 mb-3 group-hover:text-white transition-colors">
|
||||
ออกแบบระบบ
|
||||
</h3> <p class="text-secondary-600 group-hover:text-primary-100 transition-colors">
|
||||
บริการออกแบบระบบท่อน้ำ ระบบดับเพลิง และระบบปรับอากาศ โดยวิศวกรผู้เชี่ยวชาญ
|
||||
</p> </div> <!-- Service 4 --> <div class="group p-8 bg-secondary-50 rounded-2xl hover:bg-primary-600 transition-all duration-300 hover:shadow-xl"> <div class="w-16 h-16 bg-primary-600 text-white rounded-xl flex items-center justify-center mb-6 group-hover:bg-white group-hover:text-primary-600 transition-colors"> <svg class="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path> </svg> </div> <h3 class="text-xl font-bold text-secondary-900 mb-3 group-hover:text-white transition-colors">
|
||||
ติดตั้งระบบ
|
||||
</h3> <p class="text-secondary-600 group-hover:text-primary-100 transition-colors">
|
||||
ทีมช่างผู้เชี่ยวชาญติดตั้งระบบท่อครบวงจร พร้อมรับประกันงาน
|
||||
</p> </div> <!-- Service 5 --> <div class="group p-8 bg-secondary-50 rounded-2xl hover:bg-primary-600 transition-all duration-300 hover:shadow-xl"> <div class="w-16 h-16 bg-primary-600 text-white rounded-xl flex items-center justify-center mb-6 group-hover:bg-white group-hover:text-primary-600 transition-colors"> <svg class="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4"></path> </svg> </div> <h3 class="text-xl font-bold text-secondary-900 mb-3 group-hover:text-white transition-colors">
|
||||
จัดส่งสินค้า
|
||||
</h3> <p class="text-secondary-600 group-hover:text-primary-100 transition-colors">
|
||||
บริการจัดส่งสินค้าทั่วประเทศ รวดเร็ว ปลอดภัย มีประกันความเสียหาย
|
||||
</p> </div> <!-- Service 6 --> <div class="group p-8 bg-secondary-50 rounded-2xl hover:bg-primary-600 transition-all duration-300 hover:shadow-xl"> <div class="w-16 h-16 bg-primary-600 text-white rounded-xl flex items-center justify-center mb-6 group-hover:bg-white group-hover:text-primary-600 transition-colors"> <svg class="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 5.636l-3.536 3.536m0 5.656l3.536 3.536M9.172 9.172L5.636 5.636m3.536 9.192l-3.536 3.536M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-5 0a4 4 0 11-8 0 4 4 0 018 0z"></path> </svg> </div> <h3 class="text-xl font-bold text-secondary-900 mb-3 group-hover:text-white transition-colors">
|
||||
บริการหลังการขาย
|
||||
</h3> <p class="text-secondary-600 group-hover:text-primary-100 transition-colors">
|
||||
ทีมงานพร้อมให้การดูแลและบริการซ่อมบำรุงหลังการขายตลอดอายุการใช้งาน
|
||||
</p> </div> </div> </div> </section> <!-- Process Section --> <section class="py-20 bg-secondary-900"> <div class="container mx-auto px-4"> <div class="text-center mb-16"> <h2 class="text-3xl md:text-4xl font-bold text-white mb-4">
|
||||
ขั้นตอน<span class="text-primary-400">การทำงาน</span> </h2> <p class="text-secondary-300 text-lg max-w-2xl mx-auto">
|
||||
เราให้ความสำคัญกับทุกขั้นตอน เพื่อให้ลูกค้าได้รับบริการที่ดีที่สุด
|
||||
</p> </div> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8"> <!-- Step 1 --> <div class="relative"> <div class="text-center"> <span class="text-6xl font-bold text-primary-600/30">01</span> <h3 class="text-xl font-bold text-white mt-4 mb-2">ปรึกษา</h3> <p class="text-secondary-400">ติดต่อเราเพื่อปรึกษาเกี่ยวกับความต้องการของโครงการ</p> </div> </div> <!-- Step 2 --> <div class="relative"> <div class="text-center"> <span class="text-6xl font-bold text-primary-600/30">02</span> <h3 class="text-xl font-bold text-white mt-4 mb-2">ออกแบบ</h3> <p class="text-secondary-400">ทีมวิศวกรออกแบบระบบให้เหมาะสมกับการใช้งาน</p> </div> </div> <!-- Step 3 --> <div class="relative"> <div class="text-center"> <span class="text-6xl font-bold text-primary-600/30">03</span> <h3 class="text-xl font-bold text-white mt-4 mb-2">เสนอราคา</h3> <p class="text-secondary-400">เสนอราคาสินค้าและบริการอย่างโปร่งใส</p> </div> </div> <!-- Step 4 --> <div class="relative"> <div class="text-center"> <span class="text-6xl font-bold text-primary-600/30">04</span> <h3 class="text-xl font-bold text-white mt-4 mb-2">ติดตั้ง</h3> <p class="text-secondary-400">ทีมช่างติดตั้งโดยมืออาชีพตรงตามกำหนด</p> </div> </div> </div> </div> </section> <!-- Why Choose Us --> <section class="py-20 bg-secondary-50"> <div class="container mx-auto px-4"> <div class="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center"> <div> <h2 class="text-3xl md:text-4xl font-bold text-secondary-900 mb-6">
|
||||
ทำไมต้องเลือก<span class="text-primary-600">ดีลพลัสเทค</span> </h2> <div class="space-y-6"> <div class="flex gap-4"> <div class="w-12 h-12 bg-primary-600 rounded-lg flex items-center justify-center flex-shrink-0"> <svg class="w-6 h-6 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path> </svg> </div> <div> <h3 class="font-bold text-secondary-900 mb-1">ประสบการณ์กว่า 10 ปี</h3> <p class="text-secondary-600">เชี่ยวชาญด้านระบบท่อและอุปกรณ์ครบวงจร</p> </div> </div> <div class="flex gap-4"> <div class="w-12 h-12 bg-primary-600 rounded-lg flex items-center justify-center flex-shrink-0"> <svg class="w-6 h-6 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path> </svg> </div> <div> <h3 class="font-bold text-secondary-900 mb-1">สินค้าคุณภาพ</h3> <p class="text-secondary-600">สินค้าผ่านมาตรฐาน มอก. / FM / UL พร้อมรับประกัน</p> </div> </div> <div class="flex gap-4"> <div class="w-12 h-12 bg-primary-600 rounded-lg flex items-center justify-center flex-shrink-0"> <svg class="w-6 h-6 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path> </svg> </div> <div> <h3 class="font-bold text-secondary-900 mb-1">ทีมงานมืออาชีพ</h3> <p class="text-secondary-600">วิศวกรและช่างผู้เชี่ยวชาญพร้อมให้คำปรึกษา</p> </div> </div> <div class="flex gap-4"> <div class="w-12 h-12 bg-primary-600 rounded-lg flex items-center justify-center flex-shrink-0"> <svg class="w-6 h-6 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path> </svg> </div> <div> <h3 class="font-bold text-secondary-900 mb-1">บริการรวดเร็ว</h3> <p class="text-secondary-600">จัดส่งสินค้าทั่วประเทศ ตรงตามกำหนด</p> </div> </div> </div> </div> <div class="relative aspect-video bg-secondary-200 rounded-2xl overflow-hidden"> <img src="/images/2021/03/hdpe-welding_000C-1.jpg" alt="ทีมงานมืออาชีพ" class="object-cover w-full h-full" loading="lazy"> </div> </div> </div> </section> <!-- CTA --> <section class="py-20 bg-primary-600"> <div class="container mx-auto px-4 text-center"> <h2 class="text-3xl md:text-4xl font-bold text-white mb-4">
|
||||
พร้อมเริ่มโครงการของคุณ?
|
||||
</h2> <p class="text-primary-100 text-lg mb-8 max-w-">
|
||||
ต2xl mx-autoิดต่อเราวันนี้เพื่อรับคำปรึกษาและใบเสนอราคาฟรี
|
||||
</p> <div class="flex flex-wrap justify-center gap-4"> <a href="/contact-us/" class="btn-secondary bg-white text-primary-600 hover:bg-primary-50">
|
||||
ติดต่อเรา
|
||||
</a> <a href="tel:090-555-1415" class="btn-outline border-white text-white hover:bg-white hover:text-primary-600">
|
||||
โทร: 090-555-1415
|
||||
</a> </div> </div> </section> </main> <div class="fixed bottom-6 right-6 z-40 flex flex-col gap-3"> <!-- LINE --> <a href="https://line.me/ti/p/@dealplustech" target="_blank" rel="noopener noreferrer" class="w-14 h-14 bg-[#00B900] rounded-full flex items-center justify-center shadow-lg hover:scale-110 transition-transform" aria-label="ติดต่อผ่าน LINE"> <svg class="w-7 h-7 text-white" viewBox="0 0 24 24" fill="currentColor"> <path d="M19.365 9.863c.349 0 .63.285.63.631 0 .345-.281.63-.63.63H17.61v1.125h1.755c.349 0 .63.283.63.63 0 .344-.281.629-.63.629h-2.386c-.345 0-.627-.285-.627-.629V8.108c0-.345.282-.63.63-.63h2.386c.346 0 .627.285.627.63 0 .349-.281.63-.63.63H17.61v1.125h1.755zm-3.855 3.016c0 .27-.174.51-.432.596-.064.021-.133.031-.199.031-.211 0-.391-.09-.51-.25l-2.443-3.317v2.94c0 .344-.279.629-.631.629-.346 0-.626-.285-.626-.629V8.108c0-.27.173-.51.43-.595.06-.023.136-.033.194-.033.195 0 .375.104.495.254l2.462 3.33V8.108c0-.345.282-.63.63-.63.345 0 .63.285.63.63v4.771zm-5.741 0c0 .344-.282.629-.631.629-.345 0-.627-.285-.627-.629V8.108c0-.345.282-.63.63-.63.346 0 .628.285.628.63v4.771zm-2.466.629H4.917c-.345 0-.63-.285-.63-.629V8.108c0-.345.285-.63.63-.63.348 0 .63.285.63.63v4.141h1.756c.348 0 .629.283.629.63 0 .344-.282.629-.629.629M24 10.314C24 4.943 18.615.572 12 .572S0 4.943 0 10.314c0 4.811 4.27 8.842 10.035 9.608.391.082.923.258 1.058.59.12.301.079.766.038 1.08l-.164 1.02c-.045.301-.24 1.186 1.049.645 1.291-.539 6.916-4.078 9.436-6.975C23.176 14.393 24 12.458 24 10.314"></path> </svg> </a> <!-- Phone --> <a href="tel:090-555-1415" class="w-14 h-14 bg-primary-600 rounded-full flex items-center justify-center shadow-lg hover:scale-110 transition-transform" aria-label="โทรหาเรา"> <svg class="w-7 h-7 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"></path> </svg> </a> </div> <!-- Cookie Consent Banner --> <script type="module">const t=JSON.parse(localStorage.getItem("consent-preferences")||"null");if(t)t.analytics;else{const e=document.createElement("div");e.id="cookie-banner",e.className="fixed bottom-0 left-0 right-0 bg-secondary-900 text-white p-6 z-50 shadow-lg",e.innerHTML=`
|
||||
<div class="container mx-auto max-w-4xl">
|
||||
<p class="text-lg mb-4">เราใช้คุกกี้เพื่อปรับปรุงประสบการณ์การใช้งานเว็บไซต์ โดยคลิกยอมรับเพื่อใช้งานคุกกี้ทุกประเภท หรือคลิกปรับแต่งเพื่อเลือกคุกกี้ที่ต้องการ</p>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<button id="accept-all" class="px-6 py-2 bg-primary-600 text-white font-semibold rounded-md hover:bg-primary-700">ยอมรับ</button>
|
||||
<button id="reject-all" class="px-6 py-2 bg-secondary-700 text-white font-semibold rounded-md hover:bg-secondary-600">ปฏิเสธ</button>
|
||||
<button id="customize" class="px-6 py-2 border border-white text-white font-semibold rounded-md hover:bg-white hover:text-secondary-900">ปรับแต่ง</button>
|
||||
</div>
|
||||
</div>
|
||||
`,document.body.appendChild(e),document.getElementById("accept-all")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!0,marketing:!0,timestamp:new Date().toISOString()})),e.remove()}),document.getElementById("reject-all")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!1,marketing:!1,timestamp:new Date().toISOString()})),e.remove()}),document.getElementById("customize")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!1,marketing:!1,timestamp:new Date().toISOString()})),e.remove()})}</script> </body> </html>
|
||||
@@ -1,42 +0,0 @@
|
||||
<!DOCTYPE html><html lang="th"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="Astro v5.18.0"><meta name="description" content="ข้อกำหนดและเงื่อนไขการใช้งานเว็บไซต์ของบริษัท ดีล พลัส เทค จำกัด"><!-- Favicon --><link rel="icon" type="image/svg+xml" href="/favicon.svg"><link rel="alternate icon" href="/favicon.ico" sizes="any"><link rel="apple-touch-icon" href="/favicon.svg"><!-- Google Fonts: Kanit for Thai --><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Kanit:wght@300;400;500;600;700&display=swap" rel="stylesheet"><!-- SEO --><meta property="og:title" content="ข้อกำหนดและเงื่อนไข"><meta property="og:description" content="ข้อกำหนดและเงื่อนไขการใช้งานเว็บไซต์ของบริษัท ดีล พลัส เทค จำกัด"><meta property="og:image" content="/og-image.jpg"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><title>ข้อกำหนดและเงื่อนไข | ดีล พลัส เทค</title><style>html{font-family:Kanit,system-ui,sans-serif;font-size:18px}@media(min-width:1280px){html{font-size:20px}}@media(min-width:1536px){html{font-size:22px}}@media(min-width:1920px){html{font-size:24px}}
|
||||
</style></head> <body class="flex flex-col min-h-screen"> <main class="min-h-screen bg-secondary-50"> <div class="container mx-auto px-4 py-12"> <div class="max-w-4xl mx-auto bg-white rounded-lg shadow-lg p-8 md:p-12"> <h1 class="text-4xl font-bold text-secondary-900 mb-4">ข้อกำหนดและเงื่อนไข</h1> <p class="text-secondary-600 mb-8">Terms and Conditions - มีผลบังคับใช้ตั้งแต่วันที่ 9 มีนาคม 2026</p> <div class="prose prose-lg max-w-none text-secondary-700"> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">1. การยอมรับข้อกำหนด</h2> <p class="mb-4">
|
||||
ยินดีต้อนรับสู่เว็บไซต์ของ <strong>บริษัท ดีล พลัส เทค จำกัด</strong> ("เรา", "ของเรา" หรือ "เว็บไซต์")
|
||||
โดยการเข้าใช้งานเว็บไซต์นี้ ท่านยอมรับว่าท่านได้อ่าน เข้าใจ และตกลงที่จะผูกพันกับข้อกำหนดและเงื่อนไขเหล่านี้
|
||||
หากท่านไม่ยอมรับข้อกำหนดใด ๆ กรุณาหยุดการใช้งานเว็บไซต์นี้
|
||||
</p> </section> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">2. คำอธิบายบริการ</h2> <p class="mb-4">
|
||||
เว็บไซต์นี้ให้บริการข้อมูลเกี่ยวกับสินค้าและบริการของเรา รวมถึง:
|
||||
</p> <ul class="list-disc pl-6 space-y-2"> <li>ข้อมูลผลิตภัณฑ์ท่อและอุปกรณ์ระบบ HVAC</li> <li>ข้อมูลทางเทคนิคและสเปคสินค้า</li> <li>บริการให้คำปรึกษา</li> <li>ช่องทางการติดต่อและขอใบเสนอราคา</li> </ul> </section> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">3. สิทธิ์ในทรัพย์สินทางปัญญา</h2> <p class="mb-4">
|
||||
เนื้อหาทั้งหมดบนเว็บไซต์นี้ รวมถึงแต่ไม่จำกัดเพียง ข้อความ รูปภาพ กราฟิก โลโก้ ไอคอน
|
||||
และซอฟต์แวร์ เป็นทรัพย์สินทางปัญญาของบริษัท ดีล พลัส เทค จำกัด และได้รับความคุ้มครองตามกฎหมายลิขสิทธิ์
|
||||
ห้ามมิให้ทำซ้ำ ดัดแปลง เผยแพร่ หรือใช้เพื่อการค้าโดยไม่ได้รับอนุญาตเป็นลายลักษณ์อักษร
|
||||
</p> </section> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">4. ข้อผูกมัดของผู้ใช้</h2> <p class="mb-4">ท่านตกลงที่จะ:</p> <ul class="list-disc pl-6 space-y-2"> <li>ใช้เว็บไซต์นี้เพื่อวัตถุประสงค์ที่ถูกต้องตามกฎหมายเท่านั้น</li> <li>ไม่ให้ข้อมูลที่เป็นเท็จหรือไม่ถูกต้อง</li> <li>ไม่พยายามเข้าถึงระบบหรือข้อมูลโดยไม่ได้รับอนุญาต</li> <li>ไม่ใช้เว็บไซต์ในทางที่ผิดหรือเป็นอันตรายต่อผู้อื่น</li> <li>เคารพสิทธิ์ในทรัพย์สินทางปัญญาของเรา</li> </ul> </section> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">5. การจำกัดความรับผิด</h2> <p class="mb-4">
|
||||
เราพยายามให้ข้อมูลที่ถูกต้องและทันสมัยบนเว็บไซต์ อย่างไรก็ตาม เราไม่รับประกันว่า:
|
||||
</p> <ul class="list-disc pl-6 space-y-2"> <li>ข้อมูลบนเว็บไซต์จะถูกต้อง ครบถ้วน หรือเป็นปัจจุบันเสมอ</li> <li>เว็บไซต์จะทำงานได้โดยไม่มีการขัดข้องหรือปราศจากข้อผิดพลาด</li> <li>เว็บไซต์จะปลอดภัยจากการโจมตีทางไซเบอร์หรือไวรัส</li> </ul> <p class="mt-4">
|
||||
เราจะไม่รับผิดชอบต่อความเสียหายใด ๆ ที่เกิดขึ้นจากการใช้หรือไม่สามารถใช้เว็บไซต์นี้
|
||||
ไม่ว่ากรณีใด ๆ ทั้งสิ้น
|
||||
</p> </section> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">6. เงื่อนไขการ终止</h2> <p class="mb-4">
|
||||
เราขอสงวนสิทธิ์ในการระงับหรือยกเลิกการเข้าถึงเว็บไซต์ของท่าน โดยไม่ต้องแจ้งให้ทราบล่วงหน้า
|
||||
หาก我们发现ว่าท่านละเมิดข้อกำหนดและเงื่อนไขเหล่านี้
|
||||
</p> </section> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">7. กฎหมายที่ใช้บังคับ</h2> <p class="mb-4">
|
||||
ข้อกำหนดและเงื่อนไขนี้ อยู่ภายใต้บังคับของกฎหมายแห่งราชอาณาจักรไทย
|
||||
และให้ตีความตามกฎหมายดังกล่าว
|
||||
</p> </section> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">8. การระงับข้อพิพาท</h2> <p class="mb-4">
|
||||
หากเกิดข้อพิพาทใด ๆ จากข้อกำหนดและเงื่อนไขนี้ คู่สัญญาตกลงที่จะเจรจาไกล่เกลี่ยข้อพิพาท
|
||||
หากไม่สามารถตกลงกันได้ ให้อยู่ในอำนาจพิจารณาคดีของศาลไทย
|
||||
</p> </section> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">9. การแก้ไขข้อกำหนด</h2> <p class="mb-4">
|
||||
เราขอสงวนสิทธิ์ในการแก้ไขข้อกำหนดและเงื่อนไขนี้เมื่อใดก็ได้
|
||||
โดยจะแจ้งให้ท่านทราบผ่านการเผยแพร่บนเว็บไซต์ การแก้ไขจะมีผลบังคับใช้ทันทีหลังการเผยแพร่
|
||||
กรุณาตรวจสอบหน้าทนี้เป็นระยะ
|
||||
</p> </section> <section class="mb-8"> <h2 class="text-2xl font-bold text-secondary-900 mb-4">10. ข้อมูลการติดต่อ</h2> <p class="mb-4">หากมีคำถามเกี่ยวกับข้อกำหนดและเงื่อนไขนี้ กรุณาติดต่อ:</p> <div class="bg-secondary-50 p-4 rounded-lg"> <p><strong>บริษัท ดีล พลัส เทค จำกัด</strong></p> <p>ที่อยู่: 9/70 ซอยนครลุง 17 แขวงบางไผ่ เขตบางแค กทม. 10160</p> <p>โทรศัพท์: 090-555-1415</p> <p>อีเมล: info@dealplustech.co.th</p> </div> </section> <section class="mt-12 pt-8 border-t border-secondary-200"> <p class="text-sm text-secondary-600">
|
||||
ข้อกำหนดและเงื่อนไขนี้เป็นส่วนหนึ่งของข้อตกลงการใช้งานเว็บไซต์ของเรา
|
||||
และต้องอ่านร่วมกับ <a href="/privacy-policy/" class="text-primary-600 hover:underline">นโยบายความเป็นส่วนตัว</a>
|
||||
และ <a href="/cookie-policy/" class="text-primary-600 hover:underline">นโยบายคุกกี้</a> </p> </section> </div> </div> </div> </main> <!-- Cookie Consent Banner --> <script type="module">const t=JSON.parse(localStorage.getItem("consent-preferences")||"null");if(t)t.analytics;else{const e=document.createElement("div");e.id="cookie-banner",e.className="fixed bottom-0 left-0 right-0 bg-secondary-900 text-white p-6 z-50 shadow-lg",e.innerHTML=`
|
||||
<div class="container mx-auto max-w-4xl">
|
||||
<p class="text-lg mb-4">เราใช้คุกกี้เพื่อปรับปรุงประสบการณ์การใช้งานเว็บไซต์ โดยคลิกยอมรับเพื่อใช้งานคุกกี้ทุกประเภท หรือคลิกปรับแต่งเพื่อเลือกคุกกี้ที่ต้องการ</p>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<button id="accept-all" class="px-6 py-2 bg-primary-600 text-white font-semibold rounded-md hover:bg-primary-700">ยอมรับ</button>
|
||||
<button id="reject-all" class="px-6 py-2 bg-secondary-700 text-white font-semibold rounded-md hover:bg-secondary-600">ปฏิเสธ</button>
|
||||
<button id="customize" class="px-6 py-2 border border-white text-white font-semibold rounded-md hover:bg-white hover:text-secondary-900">ปรับแต่ง</button>
|
||||
</div>
|
||||
</div>
|
||||
`,document.body.appendChild(e),document.getElementById("accept-all")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!0,marketing:!0,timestamp:new Date().toISOString()})),e.remove()}),document.getElementById("reject-all")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!1,marketing:!1,timestamp:new Date().toISOString()})),e.remove()}),document.getElementById("customize")?.addEventListener("click",()=>{localStorage.setItem("consent-preferences",JSON.stringify({essential:!0,analytics:!1,marketing:!1,timestamp:new Date().toISOString()})),e.remove()})}</script> </body> </html>
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"easypanel": {
|
||||
"url": "",
|
||||
"project": "customerwebsite",
|
||||
"app": {
|
||||
"name": "dealplustech-astro",
|
||||
"port": 4321,
|
||||
"image": "dealplustech-astro:latest"
|
||||
},
|
||||
"env": {
|
||||
"NODE_ENV": "production",
|
||||
"PORT": "4321",
|
||||
"HOST": "0.0.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
# Nixpacks Configuration for Astro
|
||||
# https://nixpacks.com/docs/configuration/file
|
||||
|
||||
[phases.setup]
|
||||
nixPkgs = ["nodejs-20_x"]
|
||||
|
||||
[phases.install]
|
||||
cmds = ["npm ci"]
|
||||
|
||||
[phases.build]
|
||||
cmds = ["npm run build"]
|
||||
|
||||
[start]
|
||||
cmd = "npm run preview -- --host 0.0.0.0 --port $PORT"
|
||||
1
dealplustech-astro/node_modules/.astro/data-store.json
generated
vendored
1
dealplustech-astro/node_modules/.astro/data-store.json
generated
vendored
File diff suppressed because one or more lines are too long
1
dealplustech-astro/node_modules/.bin/acorn
generated
vendored
1
dealplustech-astro/node_modules/.bin/acorn
generated
vendored
@@ -1 +0,0 @@
|
||||
../acorn/bin/acorn
|
||||
1
dealplustech-astro/node_modules/.bin/astro
generated
vendored
1
dealplustech-astro/node_modules/.bin/astro
generated
vendored
@@ -1 +0,0 @@
|
||||
../astro/astro.js
|
||||
1
dealplustech-astro/node_modules/.bin/astro-consent
generated
vendored
1
dealplustech-astro/node_modules/.bin/astro-consent
generated
vendored
@@ -1 +0,0 @@
|
||||
../astro-consent/dist/cli.cjs
|
||||
1
dealplustech-astro/node_modules/.bin/cssesc
generated
vendored
1
dealplustech-astro/node_modules/.bin/cssesc
generated
vendored
@@ -1 +0,0 @@
|
||||
../cssesc/bin/cssesc
|
||||
1
dealplustech-astro/node_modules/.bin/esbuild
generated
vendored
1
dealplustech-astro/node_modules/.bin/esbuild
generated
vendored
@@ -1 +0,0 @@
|
||||
../esbuild/bin/esbuild
|
||||
1
dealplustech-astro/node_modules/.bin/is-docker
generated
vendored
1
dealplustech-astro/node_modules/.bin/is-docker
generated
vendored
@@ -1 +0,0 @@
|
||||
../is-docker/cli.js
|
||||
1
dealplustech-astro/node_modules/.bin/is-inside-container
generated
vendored
1
dealplustech-astro/node_modules/.bin/is-inside-container
generated
vendored
@@ -1 +0,0 @@
|
||||
../is-inside-container/cli.js
|
||||
1
dealplustech-astro/node_modules/.bin/jiti
generated
vendored
1
dealplustech-astro/node_modules/.bin/jiti
generated
vendored
@@ -1 +0,0 @@
|
||||
../jiti/lib/jiti-cli.mjs
|
||||
1
dealplustech-astro/node_modules/.bin/js-yaml
generated
vendored
1
dealplustech-astro/node_modules/.bin/js-yaml
generated
vendored
@@ -1 +0,0 @@
|
||||
../js-yaml/bin/js-yaml.js
|
||||
1
dealplustech-astro/node_modules/.bin/nanoid
generated
vendored
1
dealplustech-astro/node_modules/.bin/nanoid
generated
vendored
@@ -1 +0,0 @@
|
||||
../nanoid/bin/nanoid.cjs
|
||||
1
dealplustech-astro/node_modules/.bin/parser
generated
vendored
1
dealplustech-astro/node_modules/.bin/parser
generated
vendored
@@ -1 +0,0 @@
|
||||
../@babel/parser/bin/babel-parser.js
|
||||
1
dealplustech-astro/node_modules/.bin/rollup
generated
vendored
1
dealplustech-astro/node_modules/.bin/rollup
generated
vendored
@@ -1 +0,0 @@
|
||||
../rollup/dist/bin/rollup
|
||||
1
dealplustech-astro/node_modules/.bin/semver
generated
vendored
1
dealplustech-astro/node_modules/.bin/semver
generated
vendored
@@ -1 +0,0 @@
|
||||
../semver/bin/semver.js
|
||||
1
dealplustech-astro/node_modules/.bin/svgo
generated
vendored
1
dealplustech-astro/node_modules/.bin/svgo
generated
vendored
@@ -1 +0,0 @@
|
||||
../svgo/bin/svgo.js
|
||||
1
dealplustech-astro/node_modules/.bin/tsc
generated
vendored
1
dealplustech-astro/node_modules/.bin/tsc
generated
vendored
@@ -1 +0,0 @@
|
||||
../typescript/bin/tsc
|
||||
1
dealplustech-astro/node_modules/.bin/tsconfck
generated
vendored
1
dealplustech-astro/node_modules/.bin/tsconfck
generated
vendored
@@ -1 +0,0 @@
|
||||
../tsconfck/bin/tsconfck.js
|
||||
1
dealplustech-astro/node_modules/.bin/tsserver
generated
vendored
1
dealplustech-astro/node_modules/.bin/tsserver
generated
vendored
@@ -1 +0,0 @@
|
||||
../typescript/bin/tsserver
|
||||
1
dealplustech-astro/node_modules/.bin/vite
generated
vendored
1
dealplustech-astro/node_modules/.bin/vite
generated
vendored
@@ -1 +0,0 @@
|
||||
../vite/bin/vite.js
|
||||
7067
dealplustech-astro/node_modules/.package-lock.json
generated
vendored
7067
dealplustech-astro/node_modules/.package-lock.json
generated
vendored
File diff suppressed because it is too large
Load Diff
31
dealplustech-astro/node_modules/.vite/deps/_metadata.json
generated
vendored
31
dealplustech-astro/node_modules/.vite/deps/_metadata.json
generated
vendored
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"hash": "ec7c8616",
|
||||
"configHash": "06117f6a",
|
||||
"lockfileHash": "fa2c2659",
|
||||
"browserHash": "12cbe3a0",
|
||||
"optimized": {
|
||||
"astro > cssesc": {
|
||||
"src": "../../cssesc/cssesc.js",
|
||||
"file": "astro___cssesc.js",
|
||||
"fileHash": "3b44b1ed",
|
||||
"needsInterop": true
|
||||
},
|
||||
"astro > aria-query": {
|
||||
"src": "../../aria-query/lib/index.js",
|
||||
"file": "astro___aria-query.js",
|
||||
"fileHash": "4b6e1232",
|
||||
"needsInterop": true
|
||||
},
|
||||
"astro > axobject-query": {
|
||||
"src": "../../axobject-query/lib/index.js",
|
||||
"file": "astro___axobject-query.js",
|
||||
"fileHash": "32d0da0b",
|
||||
"needsInterop": true
|
||||
}
|
||||
},
|
||||
"chunks": {
|
||||
"chunk-BUSYA2B4": {
|
||||
"file": "chunk-BUSYA2B4.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
6776
dealplustech-astro/node_modules/.vite/deps/astro___aria-query.js
generated
vendored
6776
dealplustech-astro/node_modules/.vite/deps/astro___aria-query.js
generated
vendored
File diff suppressed because it is too large
Load Diff
7
dealplustech-astro/node_modules/.vite/deps/astro___aria-query.js.map
generated
vendored
7
dealplustech-astro/node_modules/.vite/deps/astro___aria-query.js.map
generated
vendored
File diff suppressed because one or more lines are too long
3754
dealplustech-astro/node_modules/.vite/deps/astro___axobject-query.js
generated
vendored
3754
dealplustech-astro/node_modules/.vite/deps/astro___axobject-query.js
generated
vendored
File diff suppressed because one or more lines are too long
7
dealplustech-astro/node_modules/.vite/deps/astro___axobject-query.js.map
generated
vendored
7
dealplustech-astro/node_modules/.vite/deps/astro___axobject-query.js.map
generated
vendored
File diff suppressed because one or more lines are too long
99
dealplustech-astro/node_modules/.vite/deps/astro___cssesc.js
generated
vendored
99
dealplustech-astro/node_modules/.vite/deps/astro___cssesc.js
generated
vendored
@@ -1,99 +0,0 @@
|
||||
import {
|
||||
__commonJS
|
||||
} from "./chunk-BUSYA2B4.js";
|
||||
|
||||
// node_modules/cssesc/cssesc.js
|
||||
var require_cssesc = __commonJS({
|
||||
"node_modules/cssesc/cssesc.js"(exports, module) {
|
||||
var object = {};
|
||||
var hasOwnProperty = object.hasOwnProperty;
|
||||
var merge = function merge2(options, defaults) {
|
||||
if (!options) {
|
||||
return defaults;
|
||||
}
|
||||
var result = {};
|
||||
for (var key in defaults) {
|
||||
result[key] = hasOwnProperty.call(options, key) ? options[key] : defaults[key];
|
||||
}
|
||||
return result;
|
||||
};
|
||||
var regexAnySingleEscape = /[ -,\.\/:-@\[-\^`\{-~]/;
|
||||
var regexSingleEscape = /[ -,\.\/:-@\[\]\^`\{-~]/;
|
||||
var regexExcessiveSpaces = /(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g;
|
||||
var cssesc = function cssesc2(string, options) {
|
||||
options = merge(options, cssesc2.options);
|
||||
if (options.quotes != "single" && options.quotes != "double") {
|
||||
options.quotes = "single";
|
||||
}
|
||||
var quote = options.quotes == "double" ? '"' : "'";
|
||||
var isIdentifier = options.isIdentifier;
|
||||
var firstChar = string.charAt(0);
|
||||
var output = "";
|
||||
var counter = 0;
|
||||
var length = string.length;
|
||||
while (counter < length) {
|
||||
var character = string.charAt(counter++);
|
||||
var codePoint = character.charCodeAt();
|
||||
var value = void 0;
|
||||
if (codePoint < 32 || codePoint > 126) {
|
||||
if (codePoint >= 55296 && codePoint <= 56319 && counter < length) {
|
||||
var extra = string.charCodeAt(counter++);
|
||||
if ((extra & 64512) == 56320) {
|
||||
codePoint = ((codePoint & 1023) << 10) + (extra & 1023) + 65536;
|
||||
} else {
|
||||
counter--;
|
||||
}
|
||||
}
|
||||
value = "\\" + codePoint.toString(16).toUpperCase() + " ";
|
||||
} else {
|
||||
if (options.escapeEverything) {
|
||||
if (regexAnySingleEscape.test(character)) {
|
||||
value = "\\" + character;
|
||||
} else {
|
||||
value = "\\" + codePoint.toString(16).toUpperCase() + " ";
|
||||
}
|
||||
} else if (/[\t\n\f\r\x0B]/.test(character)) {
|
||||
value = "\\" + codePoint.toString(16).toUpperCase() + " ";
|
||||
} else if (character == "\\" || !isIdentifier && (character == '"' && quote == character || character == "'" && quote == character) || isIdentifier && regexSingleEscape.test(character)) {
|
||||
value = "\\" + character;
|
||||
} else {
|
||||
value = character;
|
||||
}
|
||||
}
|
||||
output += value;
|
||||
}
|
||||
if (isIdentifier) {
|
||||
if (/^-[-\d]/.test(output)) {
|
||||
output = "\\-" + output.slice(1);
|
||||
} else if (/\d/.test(firstChar)) {
|
||||
output = "\\3" + firstChar + " " + output.slice(1);
|
||||
}
|
||||
}
|
||||
output = output.replace(regexExcessiveSpaces, function($0, $1, $2) {
|
||||
if ($1 && $1.length % 2) {
|
||||
return $0;
|
||||
}
|
||||
return ($1 || "") + $2;
|
||||
});
|
||||
if (!isIdentifier && options.wrap) {
|
||||
return quote + output + quote;
|
||||
}
|
||||
return output;
|
||||
};
|
||||
cssesc.options = {
|
||||
"escapeEverything": false,
|
||||
"isIdentifier": false,
|
||||
"quotes": "single",
|
||||
"wrap": false
|
||||
};
|
||||
cssesc.version = "3.0.0";
|
||||
module.exports = cssesc;
|
||||
}
|
||||
});
|
||||
export default require_cssesc();
|
||||
/*! Bundled license information:
|
||||
|
||||
cssesc/cssesc.js:
|
||||
(*! https://mths.be/cssesc v3.0.0 by @mathias *)
|
||||
*/
|
||||
//# sourceMappingURL=astro___cssesc.js.map
|
||||
7
dealplustech-astro/node_modules/.vite/deps/astro___cssesc.js.map
generated
vendored
7
dealplustech-astro/node_modules/.vite/deps/astro___cssesc.js.map
generated
vendored
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../cssesc/cssesc.js"],
|
||||
"sourcesContent": ["/*! https://mths.be/cssesc v3.0.0 by @mathias */\n'use strict';\n\nvar object = {};\nvar hasOwnProperty = object.hasOwnProperty;\nvar merge = function merge(options, defaults) {\n\tif (!options) {\n\t\treturn defaults;\n\t}\n\tvar result = {};\n\tfor (var key in defaults) {\n\t\t// `if (defaults.hasOwnProperty(key) { … }` is not needed here, since\n\t\t// only recognized option names are used.\n\t\tresult[key] = hasOwnProperty.call(options, key) ? options[key] : defaults[key];\n\t}\n\treturn result;\n};\n\nvar regexAnySingleEscape = /[ -,\\.\\/:-@\\[-\\^`\\{-~]/;\nvar regexSingleEscape = /[ -,\\.\\/:-@\\[\\]\\^`\\{-~]/;\nvar regexAlwaysEscape = /['\"\\\\]/;\nvar regexExcessiveSpaces = /(^|\\\\+)?(\\\\[A-F0-9]{1,6})\\x20(?![a-fA-F0-9\\x20])/g;\n\n// https://mathiasbynens.be/notes/css-escapes#css\nvar cssesc = function cssesc(string, options) {\n\toptions = merge(options, cssesc.options);\n\tif (options.quotes != 'single' && options.quotes != 'double') {\n\t\toptions.quotes = 'single';\n\t}\n\tvar quote = options.quotes == 'double' ? '\"' : '\\'';\n\tvar isIdentifier = options.isIdentifier;\n\n\tvar firstChar = string.charAt(0);\n\tvar output = '';\n\tvar counter = 0;\n\tvar length = string.length;\n\twhile (counter < length) {\n\t\tvar character = string.charAt(counter++);\n\t\tvar codePoint = character.charCodeAt();\n\t\tvar value = void 0;\n\t\t// If it’s not a printable ASCII character…\n\t\tif (codePoint < 0x20 || codePoint > 0x7E) {\n\t\t\tif (codePoint >= 0xD800 && codePoint <= 0xDBFF && counter < length) {\n\t\t\t\t// It’s a high surrogate, and there is a next character.\n\t\t\t\tvar extra = string.charCodeAt(counter++);\n\t\t\t\tif ((extra & 0xFC00) == 0xDC00) {\n\t\t\t\t\t// next character is low surrogate\n\t\t\t\t\tcodePoint = ((codePoint & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000;\n\t\t\t\t} else {\n\t\t\t\t\t// It’s an unmatched surrogate; only append this code unit, in case\n\t\t\t\t\t// the next code unit is the high surrogate of a surrogate pair.\n\t\t\t\t\tcounter--;\n\t\t\t\t}\n\t\t\t}\n\t\t\tvalue = '\\\\' + codePoint.toString(16).toUpperCase() + ' ';\n\t\t} else {\n\t\t\tif (options.escapeEverything) {\n\t\t\t\tif (regexAnySingleEscape.test(character)) {\n\t\t\t\t\tvalue = '\\\\' + character;\n\t\t\t\t} else {\n\t\t\t\t\tvalue = '\\\\' + codePoint.toString(16).toUpperCase() + ' ';\n\t\t\t\t}\n\t\t\t} else if (/[\\t\\n\\f\\r\\x0B]/.test(character)) {\n\t\t\t\tvalue = '\\\\' + codePoint.toString(16).toUpperCase() + ' ';\n\t\t\t} else if (character == '\\\\' || !isIdentifier && (character == '\"' && quote == character || character == '\\'' && quote == character) || isIdentifier && regexSingleEscape.test(character)) {\n\t\t\t\tvalue = '\\\\' + character;\n\t\t\t} else {\n\t\t\t\tvalue = character;\n\t\t\t}\n\t\t}\n\t\toutput += value;\n\t}\n\n\tif (isIdentifier) {\n\t\tif (/^-[-\\d]/.test(output)) {\n\t\t\toutput = '\\\\-' + output.slice(1);\n\t\t} else if (/\\d/.test(firstChar)) {\n\t\t\toutput = '\\\\3' + firstChar + ' ' + output.slice(1);\n\t\t}\n\t}\n\n\t// Remove spaces after `\\HEX` escapes that are not followed by a hex digit,\n\t// since they’re redundant. Note that this is only possible if the escape\n\t// sequence isn’t preceded by an odd number of backslashes.\n\toutput = output.replace(regexExcessiveSpaces, function ($0, $1, $2) {\n\t\tif ($1 && $1.length % 2) {\n\t\t\t// It’s not safe to remove the space, so don’t.\n\t\t\treturn $0;\n\t\t}\n\t\t// Strip the space.\n\t\treturn ($1 || '') + $2;\n\t});\n\n\tif (!isIdentifier && options.wrap) {\n\t\treturn quote + output + quote;\n\t}\n\treturn output;\n};\n\n// Expose default options (so they can be overridden globally).\ncssesc.options = {\n\t'escapeEverything': false,\n\t'isIdentifier': false,\n\t'quotes': 'single',\n\t'wrap': false\n};\n\ncssesc.version = '3.0.0';\n\nmodule.exports = cssesc;\n"],
|
||||
"mappings": ";;;;;AAAA;AAAA;AAGA,QAAI,SAAS,CAAC;AACd,QAAI,iBAAiB,OAAO;AAC5B,QAAI,QAAQ,SAASA,OAAM,SAAS,UAAU;AAC7C,UAAI,CAAC,SAAS;AACb,eAAO;AAAA,MACR;AACA,UAAI,SAAS,CAAC;AACd,eAAS,OAAO,UAAU;AAGzB,eAAO,GAAG,IAAI,eAAe,KAAK,SAAS,GAAG,IAAI,QAAQ,GAAG,IAAI,SAAS,GAAG;AAAA,MAC9E;AACA,aAAO;AAAA,IACR;AAEA,QAAI,uBAAuB;AAC3B,QAAI,oBAAoB;AAExB,QAAI,uBAAuB;AAG3B,QAAI,SAAS,SAASC,QAAO,QAAQ,SAAS;AAC7C,gBAAU,MAAM,SAASA,QAAO,OAAO;AACvC,UAAI,QAAQ,UAAU,YAAY,QAAQ,UAAU,UAAU;AAC7D,gBAAQ,SAAS;AAAA,MAClB;AACA,UAAI,QAAQ,QAAQ,UAAU,WAAW,MAAM;AAC/C,UAAI,eAAe,QAAQ;AAE3B,UAAI,YAAY,OAAO,OAAO,CAAC;AAC/B,UAAI,SAAS;AACb,UAAI,UAAU;AACd,UAAI,SAAS,OAAO;AACpB,aAAO,UAAU,QAAQ;AACxB,YAAI,YAAY,OAAO,OAAO,SAAS;AACvC,YAAI,YAAY,UAAU,WAAW;AACrC,YAAI,QAAQ;AAEZ,YAAI,YAAY,MAAQ,YAAY,KAAM;AACzC,cAAI,aAAa,SAAU,aAAa,SAAU,UAAU,QAAQ;AAEnE,gBAAI,QAAQ,OAAO,WAAW,SAAS;AACvC,iBAAK,QAAQ,UAAW,OAAQ;AAE/B,4BAAc,YAAY,SAAU,OAAO,QAAQ,QAAS;AAAA,YAC7D,OAAO;AAGN;AAAA,YACD;AAAA,UACD;AACA,kBAAQ,OAAO,UAAU,SAAS,EAAE,EAAE,YAAY,IAAI;AAAA,QACvD,OAAO;AACN,cAAI,QAAQ,kBAAkB;AAC7B,gBAAI,qBAAqB,KAAK,SAAS,GAAG;AACzC,sBAAQ,OAAO;AAAA,YAChB,OAAO;AACN,sBAAQ,OAAO,UAAU,SAAS,EAAE,EAAE,YAAY,IAAI;AAAA,YACvD;AAAA,UACD,WAAW,iBAAiB,KAAK,SAAS,GAAG;AAC5C,oBAAQ,OAAO,UAAU,SAAS,EAAE,EAAE,YAAY,IAAI;AAAA,UACvD,WAAW,aAAa,QAAQ,CAAC,iBAAiB,aAAa,OAAO,SAAS,aAAa,aAAa,OAAQ,SAAS,cAAc,gBAAgB,kBAAkB,KAAK,SAAS,GAAG;AAC1L,oBAAQ,OAAO;AAAA,UAChB,OAAO;AACN,oBAAQ;AAAA,UACT;AAAA,QACD;AACA,kBAAU;AAAA,MACX;AAEA,UAAI,cAAc;AACjB,YAAI,UAAU,KAAK,MAAM,GAAG;AAC3B,mBAAS,QAAQ,OAAO,MAAM,CAAC;AAAA,QAChC,WAAW,KAAK,KAAK,SAAS,GAAG;AAChC,mBAAS,QAAQ,YAAY,MAAM,OAAO,MAAM,CAAC;AAAA,QAClD;AAAA,MACD;AAKA,eAAS,OAAO,QAAQ,sBAAsB,SAAU,IAAI,IAAI,IAAI;AACnE,YAAI,MAAM,GAAG,SAAS,GAAG;AAExB,iBAAO;AAAA,QACR;AAEA,gBAAQ,MAAM,MAAM;AAAA,MACrB,CAAC;AAED,UAAI,CAAC,gBAAgB,QAAQ,MAAM;AAClC,eAAO,QAAQ,SAAS;AAAA,MACzB;AACA,aAAO;AAAA,IACR;AAGA,WAAO,UAAU;AAAA,MAChB,oBAAoB;AAAA,MACpB,gBAAgB;AAAA,MAChB,UAAU;AAAA,MACV,QAAQ;AAAA,IACT;AAEA,WAAO,UAAU;AAEjB,WAAO,UAAU;AAAA;AAAA;",
|
||||
"names": ["merge", "cssesc"]
|
||||
}
|
||||
8
dealplustech-astro/node_modules/.vite/deps/chunk-BUSYA2B4.js
generated
vendored
8
dealplustech-astro/node_modules/.vite/deps/chunk-BUSYA2B4.js
generated
vendored
@@ -1,8 +0,0 @@
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __commonJS = (cb, mod) => function __require() {
|
||||
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
||||
};
|
||||
|
||||
export {
|
||||
__commonJS
|
||||
};
|
||||
7
dealplustech-astro/node_modules/.vite/deps/chunk-BUSYA2B4.js.map
generated
vendored
7
dealplustech-astro/node_modules/.vite/deps/chunk-BUSYA2B4.js.map
generated
vendored
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": [],
|
||||
"sourcesContent": [],
|
||||
"mappings": "",
|
||||
"names": []
|
||||
}
|
||||
3
dealplustech-astro/node_modules/.vite/deps/package.json
generated
vendored
3
dealplustech-astro/node_modules/.vite/deps/package.json
generated
vendored
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
53
dealplustech-astro/node_modules/@astrojs/compiler/LICENSE
generated
vendored
53
dealplustech-astro/node_modules/@astrojs/compiler/LICENSE
generated
vendored
@@ -1,53 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 [Astro contributors](https://github.com/withastro/compiler/graphs/contributors)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
"""
|
||||
This license applies to parts of the `internal/` subdirectory originating from
|
||||
the https://cs.opensource.google/go/x/net/+/master:html/ repository:
|
||||
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
72
dealplustech-astro/node_modules/@astrojs/compiler/README.md
generated
vendored
72
dealplustech-astro/node_modules/@astrojs/compiler/README.md
generated
vendored
@@ -1,72 +0,0 @@
|
||||
# Astro Compiler
|
||||
|
||||
Astro’s [Go](https://golang.org/) + WASM compiler.
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
npm install @astrojs/compiler
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
#### Transform `.astro` to valid TypeScript
|
||||
|
||||
The Astro compiler can convert `.astro` syntax to a TypeScript Module whose default export generates HTML.
|
||||
|
||||
**Some notes**...
|
||||
|
||||
- TypeScript is valid `.astro` syntax! The output code may need an additional post-processing step to generate valid JavaScript.
|
||||
- `.astro` files rely on a server implementation exposed as `astro/runtime/server/index.js` in the Node ecosystem. Other runtimes currently need to bring their own rendering implementation and reference it via `internalURL`. This is a pain point we're looking into fixing.
|
||||
|
||||
```js
|
||||
import { transform, type TransformResult } from "@astrojs/compiler";
|
||||
|
||||
const result = await transform(source, {
|
||||
filename: "/Users/astro/Code/project/src/pages/index.astro",
|
||||
sourcemap: "both",
|
||||
internalURL: "astro/runtime/server/index.js",
|
||||
});
|
||||
```
|
||||
|
||||
#### Parse `.astro` and return an AST
|
||||
|
||||
The Astro compiler can emit an AST using the `parse` method.
|
||||
|
||||
**Some notes**...
|
||||
|
||||
- Position data is currently incomplete and in some cases incorrect. We're working on it!
|
||||
- A `TextNode` can represent both HTML `text` and JavaScript/TypeScript source code.
|
||||
- The `@astrojs/compiler/utils` entrypoint exposes `walk` and `walkAsync` functions that can be used to traverse the AST. It also exposes the `is` helper which can be used as guards to derive the proper types for each `node`.
|
||||
|
||||
```js
|
||||
import { parse } from "@astrojs/compiler";
|
||||
import { walk, walkAsync, is } from "@astrojs/compiler/utils";
|
||||
|
||||
const result = await parse(source, {
|
||||
position: false, // defaults to `true`
|
||||
});
|
||||
|
||||
walk(result.ast, (node) => {
|
||||
// `tag` nodes are `element` | `custom-element` | `component`
|
||||
if (is.tag(node)) {
|
||||
console.log(node.name);
|
||||
}
|
||||
});
|
||||
|
||||
await walkAsync(result.ast, async (node) => {
|
||||
if (is.tag(node)) {
|
||||
node.value = await expensiveCalculation(node)
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Develop
|
||||
|
||||
### VSCode / CodeSpaces
|
||||
|
||||
A `devcontainer` configuration is available for use with VSCode's [Remote Development extension pack](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) and GitHub CodeSpaces.
|
||||
|
||||
## Contributing
|
||||
|
||||
[CONTRIBUTING.md](/CONTRIBUTING.md)
|
||||
BIN
dealplustech-astro/node_modules/@astrojs/compiler/dist/astro.wasm
generated
vendored
BIN
dealplustech-astro/node_modules/@astrojs/compiler/dist/astro.wasm
generated
vendored
Binary file not shown.
2
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/index.cjs
generated
vendored
2
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/index.cjs
generated
vendored
File diff suppressed because one or more lines are too long
11
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/index.d.ts
generated
vendored
11
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/index.d.ts
generated
vendored
@@ -1,11 +0,0 @@
|
||||
import { transform as transform$1, parse as parse$1, convertToTSX as convertToTSX$1, teardown as teardown$1, initialize as initialize$1 } from '../shared/types.js';
|
||||
import '../shared/ast.js';
|
||||
import '../shared/diagnostics.js';
|
||||
|
||||
declare const transform: typeof transform$1;
|
||||
declare const parse: typeof parse$1;
|
||||
declare const convertToTSX: typeof convertToTSX$1;
|
||||
declare const teardown: typeof teardown$1;
|
||||
declare const initialize: typeof initialize$1;
|
||||
|
||||
export { convertToTSX, initialize, parse, teardown, transform };
|
||||
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/index.js
generated
vendored
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/index.js
generated
vendored
@@ -1 +0,0 @@
|
||||
import{a as f}from"../chunk-QR6QDSEV.js";var u=(t,e)=>p().transform(t,e),S=(t,e)=>p().parse(t,e),v=(t,e)=>p().convertToTSX(t,e),a,i,h=()=>{a=void 0,i=void 0,globalThis["@astrojs/compiler"]=void 0},T=async t=>{let e=t.wasmURL;if(!e)throw new Error('Must provide the "wasmURL" option');e+="",a||(a=m(e).catch(n=>{throw a=void 0,n})),i=i||await a},p=()=>{if(!a)throw new Error('You need to call "initialize" before calling this');if(!i)throw new Error('You need to wait for the promise returned from "initialize" to be resolved before calling this');return i},y=async(t,e)=>{let n;return WebAssembly.instantiateStreaming?n=await WebAssembly.instantiateStreaming(fetch(t),e):n=await(async()=>{let s=await fetch(t).then(o=>o.arrayBuffer());return WebAssembly.instantiate(s,e)})(),n},m=async t=>{let e=new f,n=await y(t,e.importObject);e.run(n.instance);let c=globalThis["@astrojs/compiler"];return{transform:(s,o)=>new Promise(r=>r(c.transform(s,o||{}))),convertToTSX:(s,o)=>new Promise(r=>r(c.convertToTSX(s,o||{}))).then(r=>({...r,map:JSON.parse(r.map)})),parse:(s,o)=>new Promise(r=>r(c.parse(s,o||{}))).then(r=>({...r,ast:JSON.parse(r.ast)}))}};export{v as convertToTSX,T as initialize,S as parse,h as teardown,u as transform};
|
||||
3
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/utils.cjs
generated
vendored
3
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/utils.cjs
generated
vendored
@@ -1,3 +0,0 @@
|
||||
"use strict";var c=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var N=Object.prototype.hasOwnProperty;var u=(o,e)=>{for(var t in e)c(o,t,{get:e[t],enumerable:!0})},f=(o,e,t,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of p(e))!N.call(o,r)&&r!==t&&c(o,r,{get:()=>e[r],enumerable:!(a=d(e,r))||a.enumerable});return o};var y=o=>f(c({},"__esModule",{value:!0}),o);var v={};u(v,{is:()=>s,serialize:()=>k,walk:()=>h,walkAsync:()=>x});module.exports=y(v);function n(o){return e=>e.type===o}var s={parent(o){return Array.isArray(o.children)},literal(o){return typeof o.value=="string"},tag(o){return o.type==="element"||o.type==="custom-element"||o.type==="component"||o.type==="fragment"},whitespace(o){return o.type==="text"&&o.value.trim().length===0},root:n("root"),element:n("element"),customElement:n("custom-element"),component:n("component"),fragment:n("fragment"),expression:n("expression"),text:n("text"),doctype:n("doctype"),comment:n("comment"),frontmatter:n("frontmatter")},l=class{constructor(e){this.callback=e}async visit(e,t,a){if(await this.callback(e,t,a),s.parent(e)){let r=[];for(let i=0;i<e.children.length;i++){let m=e.children[i];r.push(this.callback(m,e,i))}await Promise.all(r)}}};function h(o,e){new l(e).visit(o)}function x(o,e){return new l(e).visit(o)}function g(o){let e="";for(let t of o.attributes)switch(e+=" ",t.kind){case"empty":{e+=`${t.name}`;break}case"expression":{e+=`${t.name}={${t.value}}`;break}case"quoted":{e+=`${t.name}=${t.raw}`;break}case"template-literal":{e+=`${t.name}=\`${t.value}\``;break}case"shorthand":{e+=`{${t.name}}`;break}case"spread":{e+=`{...${t.value}}`;break}}return e}function k(o,e={selfClose:!0}){let t="";function a(r){if(s.root(r))for(let i of r.children)a(i);else if(s.frontmatter(r))t+=`---${r.value}---
|
||||
|
||||
`;else if(s.comment(r))t+=`<!--${r.value}-->`;else if(s.expression(r)){t+="{";for(let i of r.children)a(i);t+="}"}else if(s.literal(r))t+=r.value;else if(s.tag(r))if(t+=`<${r.name}`,t+=g(r),r.children.length===0&&e.selfClose)t+=" />";else{t+=">";for(let i of r.children)a(i);t+=`</${r.name}>`}}return a(o),t}0&&(module.exports={is,serialize,walk,walkAsync});
|
||||
29
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/utils.d.ts
generated
vendored
29
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/utils.d.ts
generated
vendored
@@ -1,29 +0,0 @@
|
||||
import { Node, ParentNode, LiteralNode, TagLikeNode, TextNode, RootNode, ElementNode, CustomElementNode, ComponentNode, FragmentNode, ExpressionNode, DoctypeNode, CommentNode, FrontmatterNode } from '../shared/ast.js';
|
||||
|
||||
type Visitor = (node: Node, parent?: ParentNode, index?: number) => void | Promise<void>;
|
||||
declare const is: {
|
||||
parent(node: Node): node is ParentNode;
|
||||
literal(node: Node): node is LiteralNode;
|
||||
tag(node: Node): node is TagLikeNode;
|
||||
whitespace(node: Node): node is TextNode;
|
||||
root: (node: Node) => node is RootNode;
|
||||
element: (node: Node) => node is ElementNode;
|
||||
customElement: (node: Node) => node is CustomElementNode;
|
||||
component: (node: Node) => node is ComponentNode;
|
||||
fragment: (node: Node) => node is FragmentNode;
|
||||
expression: (node: Node) => node is ExpressionNode;
|
||||
text: (node: Node) => node is TextNode;
|
||||
doctype: (node: Node) => node is DoctypeNode;
|
||||
comment: (node: Node) => node is CommentNode;
|
||||
frontmatter: (node: Node) => node is FrontmatterNode;
|
||||
};
|
||||
declare function walk(node: ParentNode, callback: Visitor): void;
|
||||
declare function walkAsync(node: ParentNode, callback: Visitor): Promise<void>;
|
||||
interface SerializeOptions {
|
||||
selfClose: boolean;
|
||||
}
|
||||
/** @deprecated Please use `SerializeOptions` */
|
||||
type SerializeOtions = SerializeOptions;
|
||||
declare function serialize(root: Node, opts?: SerializeOptions): string;
|
||||
|
||||
export { SerializeOptions, SerializeOtions, Visitor, is, serialize, walk, walkAsync };
|
||||
3
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/utils.js
generated
vendored
3
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/utils.js
generated
vendored
@@ -1,3 +0,0 @@
|
||||
function n(o){return t=>t.type===o}var a={parent(o){return Array.isArray(o.children)},literal(o){return typeof o.value=="string"},tag(o){return o.type==="element"||o.type==="custom-element"||o.type==="component"||o.type==="fragment"},whitespace(o){return o.type==="text"&&o.value.trim().length===0},root:n("root"),element:n("element"),customElement:n("custom-element"),component:n("component"),fragment:n("fragment"),expression:n("expression"),text:n("text"),doctype:n("doctype"),comment:n("comment"),frontmatter:n("frontmatter")},l=class{constructor(t){this.callback=t}async visit(t,e,s){if(await this.callback(t,e,s),a.parent(t)){let r=[];for(let i=0;i<t.children.length;i++){let c=t.children[i];r.push(this.callback(c,t,i))}await Promise.all(r)}}};function N(o,t){new l(t).visit(o)}function u(o,t){return new l(t).visit(o)}function m(o){let t="";for(let e of o.attributes)switch(t+=" ",e.kind){case"empty":{t+=`${e.name}`;break}case"expression":{t+=`${e.name}={${e.value}}`;break}case"quoted":{t+=`${e.name}=${e.raw}`;break}case"template-literal":{t+=`${e.name}=\`${e.value}\``;break}case"shorthand":{t+=`{${e.name}}`;break}case"spread":{t+=`{...${e.value}}`;break}}return t}function f(o,t={selfClose:!0}){let e="";function s(r){if(a.root(r))for(let i of r.children)s(i);else if(a.frontmatter(r))e+=`---${r.value}---
|
||||
|
||||
`;else if(a.comment(r))e+=`<!--${r.value}-->`;else if(a.expression(r)){e+="{";for(let i of r.children)s(i);e+="}"}else if(a.literal(r))e+=r.value;else if(a.tag(r))if(e+=`<${r.name}`,e+=m(r),r.children.length===0&&t.selfClose)e+=" />";else{e+=">";for(let i of r.children)s(i);e+=`</${r.name}>`}}return s(o),e}export{a as is,f as serialize,N as walk,u as walkAsync};
|
||||
2
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/wasm_exec.cjs
generated
vendored
2
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/wasm_exec.cjs
generated
vendored
File diff suppressed because one or more lines are too long
37
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/wasm_exec.d.ts
generated
vendored
37
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/wasm_exec.d.ts
generated
vendored
@@ -1,37 +0,0 @@
|
||||
declare class Go {
|
||||
importObject: {
|
||||
gojs: {
|
||||
'runtime.wasmExit': (sp: any) => void;
|
||||
'runtime.wasmWrite': (sp: any) => void;
|
||||
'runtime.resetMemoryDataView': (sp: any) => void;
|
||||
'runtime.nanotime1': (sp: any) => void;
|
||||
'runtime.walltime': (sp: any) => void;
|
||||
'runtime.scheduleTimeoutEvent': (sp: any) => void;
|
||||
'runtime.clearTimeoutEvent': (sp: any) => void;
|
||||
'runtime.getRandomData': (sp: any) => void;
|
||||
'syscall/js.finalizeRef': (sp: any) => void;
|
||||
'syscall/js.stringVal': (sp: any) => void;
|
||||
'syscall/js.valueGet': (sp: any) => void;
|
||||
'syscall/js.valueSet': (sp: any) => void;
|
||||
'syscall/js.valueDelete': (sp: any) => void;
|
||||
'syscall/js.valueIndex': (sp: any) => void;
|
||||
'syscall/js.valueSetIndex': (sp: any) => void;
|
||||
'syscall/js.valueCall': (sp: any) => void;
|
||||
'syscall/js.valueInvoke': (sp: any) => void;
|
||||
'syscall/js.valueNew': (sp: any) => void;
|
||||
'syscall/js.valueLength': (sp: any) => void;
|
||||
'syscall/js.valuePrepareString': (sp: any) => void;
|
||||
'syscall/js.valueLoadString': (sp: any) => void;
|
||||
'syscall/js.valueInstanceOf': (sp: any) => void;
|
||||
'syscall/js.copyBytesToGo': (sp: any) => void;
|
||||
'syscall/js.copyBytesToJS': (sp: any) => void;
|
||||
debug: (value: any) => void;
|
||||
};
|
||||
};
|
||||
constructor();
|
||||
run(instance: any): Promise<void>;
|
||||
private _resume;
|
||||
private _makeFuncWrapper;
|
||||
}
|
||||
|
||||
export { Go as default };
|
||||
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/wasm_exec.js
generated
vendored
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/browser/wasm_exec.js
generated
vendored
@@ -1 +0,0 @@
|
||||
import{a}from"../chunk-QR6QDSEV.js";export{a as default};
|
||||
2
dealplustech-astro/node_modules/@astrojs/compiler/dist/chunk-QR6QDSEV.js
generated
vendored
2
dealplustech-astro/node_modules/@astrojs/compiler/dist/chunk-QR6QDSEV.js
generated
vendored
File diff suppressed because one or more lines are too long
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/chunk-W5DTLHV4.js
generated
vendored
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/chunk-W5DTLHV4.js
generated
vendored
File diff suppressed because one or more lines are too long
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/index.cjs
generated
vendored
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/index.cjs
generated
vendored
File diff suppressed because one or more lines are too long
12
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/index.d.ts
generated
vendored
12
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/index.d.ts
generated
vendored
@@ -1,12 +0,0 @@
|
||||
import { transform as transform$1, parse as parse$1, convertToTSX as convertToTSX$1, teardown as teardown$1 } from '../shared/types.js';
|
||||
export { HoistedScript, ParseOptions, ParseResult, PreprocessorResult, TransformOptions, TransformResult } from '../shared/types.js';
|
||||
import '../shared/ast.js';
|
||||
import '../shared/diagnostics.js';
|
||||
|
||||
declare const transform: typeof transform$1;
|
||||
declare const parse: typeof parse$1;
|
||||
declare const convertToTSX: typeof convertToTSX$1;
|
||||
declare const compile: (template: string) => Promise<string>;
|
||||
declare const teardown: typeof teardown$1;
|
||||
|
||||
export { compile, convertToTSX, parse, teardown, transform };
|
||||
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/index.js
generated
vendored
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/index.js
generated
vendored
@@ -1 +0,0 @@
|
||||
import{a as c}from"../chunk-W5DTLHV4.js";import{promises as m}from"fs";import{fileURLToPath as f}from"url";var w=async(t,s)=>i().then(r=>r.transform(t,s)),l=async(t,s)=>i().then(r=>r.parse(t,s)),b=async(t,s)=>i().then(r=>r.convertToTSX(t,s)),P=async t=>{let{default:s}=await import(`data:text/javascript;charset=utf-8;base64,${Buffer.from(t).toString("base64")}`);return s},n,g=()=>{n=void 0,globalThis["@astrojs/compiler"]=void 0},i=()=>(n||(n=d().catch(t=>{throw n=void 0,t})),n),y=async(t,s)=>{let r;return r=await(async()=>{let o=await m.readFile(t).then(e=>e.buffer);return WebAssembly.instantiate(new Uint8Array(o),s)})(),r},d=async()=>{let t=new c,s=await y(f(new URL("../astro.wasm",import.meta.url)),t.importObject);t.run(s.instance);let r=globalThis["@astrojs/compiler"];return{transform:(a,o)=>new Promise(e=>{try{e(r.transform(a,o||{}))}catch(p){throw n=void 0,p}}),parse:(a,o)=>new Promise(e=>e(r.parse(a,o||{}))).catch(e=>{throw n=void 0,e}).then(e=>({...e,ast:JSON.parse(e.ast)})),convertToTSX:(a,o)=>new Promise(e=>e(r.convertToTSX(a,o||{}))).catch(e=>{throw n=void 0,e}).then(e=>({...e,map:JSON.parse(e.map)}))}};export{P as compile,b as convertToTSX,l as parse,g as teardown,w as transform};
|
||||
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/sync.cjs
generated
vendored
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/sync.cjs
generated
vendored
File diff suppressed because one or more lines are too long
16
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/sync.d.ts
generated
vendored
16
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/sync.d.ts
generated
vendored
@@ -1,16 +0,0 @@
|
||||
import { TransformOptions, TransformResult, ParseOptions, ParseResult, ConvertToTSXOptions, TSXResult, transform as transform$1, parse as parse$1, convertToTSX as convertToTSX$1 } from '../shared/types.js';
|
||||
import '../shared/ast.js';
|
||||
import '../shared/diagnostics.js';
|
||||
|
||||
type UnwrappedPromise<T> = T extends (...params: any) => Promise<infer Return> ? (...params: Parameters<T>) => Return : T;
|
||||
interface Service {
|
||||
transform: UnwrappedPromise<typeof transform$1>;
|
||||
parse: UnwrappedPromise<typeof parse$1>;
|
||||
convertToTSX: UnwrappedPromise<typeof convertToTSX$1>;
|
||||
}
|
||||
declare const transform: (input: string, options: TransformOptions | undefined) => TransformResult;
|
||||
declare const parse: (input: string, options: ParseOptions | undefined) => ParseResult;
|
||||
declare const convertToTSX: (input: string, options: ConvertToTSXOptions | undefined) => TSXResult;
|
||||
declare function startRunningService(): Service;
|
||||
|
||||
export { convertToTSX, parse, startRunningService, transform };
|
||||
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/sync.js
generated
vendored
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/sync.js
generated
vendored
@@ -1 +0,0 @@
|
||||
import{a as c}from"../chunk-W5DTLHV4.js";import{readFileSync as p}from"fs";import{fileURLToPath as m}from"url";function i(){return s||(s=f()),s}var s,l=(e,t)=>i().transform(e,t),w=(e,t)=>i().parse(e,t),h=(e,t)=>i().convertToTSX(e,t);function f(){let e=new c,t=v(m(new URL("../astro.wasm",import.meta.url)),e.importObject);e.run(t);let o=globalThis["@astrojs/compiler"];return{transform:(n,a)=>{try{return o.transform(n,a||{})}catch(r){throw s=void 0,r}},parse:(n,a)=>{try{let r=o.parse(n,a||{});return{...r,ast:JSON.parse(r.ast)}}catch(r){throw s=void 0,r}},convertToTSX:(n,a)=>{try{let r=o.convertToTSX(n,a||{});return{...r,map:JSON.parse(r.map)}}catch(r){throw s=void 0,r}}}}function v(e,t){let o=p(e);return new WebAssembly.Instance(new WebAssembly.Module(o),t)}export{h as convertToTSX,w as parse,f as startRunningService,l as transform};
|
||||
3
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/utils.cjs
generated
vendored
3
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/utils.cjs
generated
vendored
@@ -1,3 +0,0 @@
|
||||
"use strict";var m=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var N=Object.prototype.hasOwnProperty;var u=(o,e)=>{for(var t in e)m(o,t,{get:e[t],enumerable:!0})},f=(o,e,t,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of p(e))!N.call(o,r)&&r!==t&&m(o,r,{get:()=>e[r],enumerable:!(a=d(e,r))||a.enumerable});return o};var y=o=>f(m({},"__esModule",{value:!0}),o);var v={};u(v,{is:()=>s,serialize:()=>k,walk:()=>h,walkAsync:()=>x});module.exports=y(v);function n(o){return e=>e.type===o}var s={parent(o){return Array.isArray(o.children)},literal(o){return typeof o.value=="string"},tag(o){return o.type==="element"||o.type==="custom-element"||o.type==="component"||o.type==="fragment"},whitespace(o){return o.type==="text"&&o.value.trim().length===0},root:n("root"),element:n("element"),customElement:n("custom-element"),component:n("component"),fragment:n("fragment"),expression:n("expression"),text:n("text"),doctype:n("doctype"),comment:n("comment"),frontmatter:n("frontmatter")},l=class{constructor(e){this.callback=e}async visit(e,t,a){if(await this.callback(e,t,a),s.parent(e)){let r=[];for(let i=0;i<e.children.length;i++){let c=e.children[i];r.push(this.callback(c,e,i))}await Promise.all(r)}}};function h(o,e){new l(e).visit(o)}function x(o,e){return new l(e).visit(o)}function g(o){let e="";for(let t of o.attributes)switch(e+=" ",t.kind){case"empty":{e+=`${t.name}`;break}case"expression":{e+=`${t.name}={${t.value}}`;break}case"quoted":{e+=`${t.name}=${t.raw}`;break}case"template-literal":{e+=`${t.name}=\`${t.value}\``;break}case"shorthand":{e+=`{${t.name}}`;break}case"spread":{e+=`{...${t.name}}`;break}}return e}function k(o,e={selfClose:!0}){let t="";function a(r){if(s.root(r))for(let i of r.children)a(i);else if(s.frontmatter(r))t+=`---${r.value}---
|
||||
|
||||
`;else if(s.comment(r))t+=`<!--${r.value}-->`;else if(s.expression(r)){t+="{";for(let i of r.children)a(i);t+="}"}else if(s.literal(r))t+=r.value;else if(s.tag(r))if(t+=`<${r.name}`,t+=g(r),r.children.length===0&&e.selfClose)t+=" />";else{t+=">";for(let i of r.children)a(i);t+=`</${r.name}>`}}return a(o),t}0&&(module.exports={is,serialize,walk,walkAsync});
|
||||
29
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/utils.d.ts
generated
vendored
29
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/utils.d.ts
generated
vendored
@@ -1,29 +0,0 @@
|
||||
import { Node, ParentNode, LiteralNode, TagLikeNode, TextNode, RootNode, ElementNode, CustomElementNode, ComponentNode, FragmentNode, ExpressionNode, DoctypeNode, CommentNode, FrontmatterNode } from '../shared/ast.js';
|
||||
|
||||
type Visitor = (node: Node, parent?: ParentNode, index?: number) => void | Promise<void>;
|
||||
declare const is: {
|
||||
parent(node: Node): node is ParentNode;
|
||||
literal(node: Node): node is LiteralNode;
|
||||
tag(node: Node): node is TagLikeNode;
|
||||
whitespace(node: Node): node is TextNode;
|
||||
root: (node: Node) => node is RootNode;
|
||||
element: (node: Node) => node is ElementNode;
|
||||
customElement: (node: Node) => node is CustomElementNode;
|
||||
component: (node: Node) => node is ComponentNode;
|
||||
fragment: (node: Node) => node is FragmentNode;
|
||||
expression: (node: Node) => node is ExpressionNode;
|
||||
text: (node: Node) => node is TextNode;
|
||||
doctype: (node: Node) => node is DoctypeNode;
|
||||
comment: (node: Node) => node is CommentNode;
|
||||
frontmatter: (node: Node) => node is FrontmatterNode;
|
||||
};
|
||||
declare function walk(node: ParentNode, callback: Visitor): void;
|
||||
declare function walkAsync(node: ParentNode, callback: Visitor): Promise<void>;
|
||||
interface SerializeOptions {
|
||||
selfClose: boolean;
|
||||
}
|
||||
/** @deprecated Please use `SerializeOptions` */
|
||||
type SerializeOtions = SerializeOptions;
|
||||
declare function serialize(root: Node, opts?: SerializeOptions): string;
|
||||
|
||||
export { SerializeOptions, SerializeOtions, Visitor, is, serialize, walk, walkAsync };
|
||||
3
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/utils.js
generated
vendored
3
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/utils.js
generated
vendored
@@ -1,3 +0,0 @@
|
||||
function n(o){return t=>t.type===o}var a={parent(o){return Array.isArray(o.children)},literal(o){return typeof o.value=="string"},tag(o){return o.type==="element"||o.type==="custom-element"||o.type==="component"||o.type==="fragment"},whitespace(o){return o.type==="text"&&o.value.trim().length===0},root:n("root"),element:n("element"),customElement:n("custom-element"),component:n("component"),fragment:n("fragment"),expression:n("expression"),text:n("text"),doctype:n("doctype"),comment:n("comment"),frontmatter:n("frontmatter")},l=class{constructor(t){this.callback=t}async visit(t,e,s){if(await this.callback(t,e,s),a.parent(t)){let r=[];for(let i=0;i<t.children.length;i++){let m=t.children[i];r.push(this.callback(m,t,i))}await Promise.all(r)}}};function N(o,t){new l(t).visit(o)}function u(o,t){return new l(t).visit(o)}function c(o){let t="";for(let e of o.attributes)switch(t+=" ",e.kind){case"empty":{t+=`${e.name}`;break}case"expression":{t+=`${e.name}={${e.value}}`;break}case"quoted":{t+=`${e.name}=${e.raw}`;break}case"template-literal":{t+=`${e.name}=\`${e.value}\``;break}case"shorthand":{t+=`{${e.name}}`;break}case"spread":{t+=`{...${e.name}}`;break}}return t}function f(o,t={selfClose:!0}){let e="";function s(r){if(a.root(r))for(let i of r.children)s(i);else if(a.frontmatter(r))e+=`---${r.value}---
|
||||
|
||||
`;else if(a.comment(r))e+=`<!--${r.value}-->`;else if(a.expression(r)){e+="{";for(let i of r.children)s(i);e+="}"}else if(a.literal(r))e+=r.value;else if(a.tag(r))if(e+=`<${r.name}`,e+=c(r),r.children.length===0&&t.selfClose)e+=" />";else{e+=">";for(let i of r.children)s(i);e+=`</${r.name}>`}}return s(o),e}export{a as is,f as serialize,N as walk,u as walkAsync};
|
||||
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/wasm_exec.cjs
generated
vendored
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/wasm_exec.cjs
generated
vendored
File diff suppressed because one or more lines are too long
37
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/wasm_exec.d.ts
generated
vendored
37
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/wasm_exec.d.ts
generated
vendored
@@ -1,37 +0,0 @@
|
||||
declare class Go {
|
||||
importObject: {
|
||||
gojs: {
|
||||
'runtime.wasmExit': (sp: any) => void;
|
||||
'runtime.wasmWrite': (sp: any) => void;
|
||||
'runtime.resetMemoryDataView': (sp: any) => void;
|
||||
'runtime.nanotime1': (sp: any) => void;
|
||||
'runtime.walltime': (sp: any) => void;
|
||||
'runtime.scheduleTimeoutEvent': (sp: any) => void;
|
||||
'runtime.clearTimeoutEvent': (sp: any) => void;
|
||||
'runtime.getRandomData': (sp: any) => void;
|
||||
'syscall/js.finalizeRef': (sp: any) => void;
|
||||
'syscall/js.stringVal': (sp: any) => void;
|
||||
'syscall/js.valueGet': (sp: any) => void;
|
||||
'syscall/js.valueSet': (sp: any) => void;
|
||||
'syscall/js.valueDelete': (sp: any) => void;
|
||||
'syscall/js.valueIndex': (sp: any) => void;
|
||||
'syscall/js.valueSetIndex': (sp: any) => void;
|
||||
'syscall/js.valueCall': (sp: any) => void;
|
||||
'syscall/js.valueInvoke': (sp: any) => void;
|
||||
'syscall/js.valueNew': (sp: any) => void;
|
||||
'syscall/js.valueLength': (sp: any) => void;
|
||||
'syscall/js.valuePrepareString': (sp: any) => void;
|
||||
'syscall/js.valueLoadString': (sp: any) => void;
|
||||
'syscall/js.valueInstanceOf': (sp: any) => void;
|
||||
'syscall/js.copyBytesToGo': (sp: any) => void;
|
||||
'syscall/js.copyBytesToJS': (sp: any) => void;
|
||||
debug: (value: any) => void;
|
||||
};
|
||||
};
|
||||
constructor();
|
||||
run(instance: any): Promise<void>;
|
||||
private _resume;
|
||||
private _makeFuncWrapper;
|
||||
}
|
||||
|
||||
export { Go as default };
|
||||
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/wasm_exec.js
generated
vendored
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/node/wasm_exec.js
generated
vendored
@@ -1 +0,0 @@
|
||||
import{a}from"../chunk-W5DTLHV4.js";export{a as default};
|
||||
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/shared/ast.cjs
generated
vendored
1
dealplustech-astro/node_modules/@astrojs/compiler/dist/shared/ast.cjs
generated
vendored
@@ -1 +0,0 @@
|
||||
"use strict";var r=Object.defineProperty;var a=Object.getOwnPropertyDescriptor;var i=Object.getOwnPropertyNames;var N=Object.prototype.hasOwnProperty;var p=(t,e,d,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of i(e))!N.call(t,o)&&o!==d&&r(t,o,{get:()=>e[o],enumerable:!(n=a(e,o))||n.enumerable});return t};var s=t=>p(r({},"__esModule",{value:!0}),t);var m={};module.exports=s(m);
|
||||
74
dealplustech-astro/node_modules/@astrojs/compiler/dist/shared/ast.d.ts
generated
vendored
74
dealplustech-astro/node_modules/@astrojs/compiler/dist/shared/ast.d.ts
generated
vendored
@@ -1,74 +0,0 @@
|
||||
type ParentNode = RootNode | ElementNode | ComponentNode | CustomElementNode | FragmentNode | ExpressionNode;
|
||||
type LiteralNode = TextNode | DoctypeNode | CommentNode | FrontmatterNode;
|
||||
type Node = RootNode | ElementNode | ComponentNode | CustomElementNode | FragmentNode | ExpressionNode | TextNode | FrontmatterNode | DoctypeNode | CommentNode;
|
||||
interface Position {
|
||||
start: Point;
|
||||
end?: Point;
|
||||
}
|
||||
interface Point {
|
||||
/** 1-based line number */
|
||||
line: number;
|
||||
/** 1-based column number, per-line */
|
||||
column: number;
|
||||
/** 0-based byte offset */
|
||||
offset: number;
|
||||
}
|
||||
interface BaseNode {
|
||||
type: string;
|
||||
position?: Position;
|
||||
}
|
||||
interface ParentLikeNode extends BaseNode {
|
||||
type: 'element' | 'component' | 'custom-element' | 'fragment' | 'expression' | 'root';
|
||||
children: Node[];
|
||||
}
|
||||
interface ValueNode extends BaseNode {
|
||||
value: string;
|
||||
}
|
||||
interface RootNode extends ParentLikeNode {
|
||||
type: 'root';
|
||||
}
|
||||
interface AttributeNode extends BaseNode {
|
||||
type: 'attribute';
|
||||
kind: 'quoted' | 'empty' | 'expression' | 'spread' | 'shorthand' | 'template-literal';
|
||||
name: string;
|
||||
value: string;
|
||||
raw?: string;
|
||||
}
|
||||
interface TextNode extends ValueNode {
|
||||
type: 'text';
|
||||
}
|
||||
interface ElementNode extends ParentLikeNode {
|
||||
type: 'element';
|
||||
name: string;
|
||||
attributes: AttributeNode[];
|
||||
}
|
||||
interface FragmentNode extends ParentLikeNode {
|
||||
type: 'fragment';
|
||||
name: string;
|
||||
attributes: AttributeNode[];
|
||||
}
|
||||
interface ComponentNode extends ParentLikeNode {
|
||||
type: 'component';
|
||||
name: string;
|
||||
attributes: AttributeNode[];
|
||||
}
|
||||
interface CustomElementNode extends ParentLikeNode {
|
||||
type: 'custom-element';
|
||||
name: string;
|
||||
attributes: AttributeNode[];
|
||||
}
|
||||
type TagLikeNode = ElementNode | FragmentNode | ComponentNode | CustomElementNode;
|
||||
interface DoctypeNode extends ValueNode {
|
||||
type: 'doctype';
|
||||
}
|
||||
interface CommentNode extends ValueNode {
|
||||
type: 'comment';
|
||||
}
|
||||
interface FrontmatterNode extends ValueNode {
|
||||
type: 'frontmatter';
|
||||
}
|
||||
interface ExpressionNode extends ParentLikeNode {
|
||||
type: 'expression';
|
||||
}
|
||||
|
||||
export { AttributeNode, BaseNode, CommentNode, ComponentNode, CustomElementNode, DoctypeNode, ElementNode, ExpressionNode, FragmentNode, FrontmatterNode, LiteralNode, Node, ParentLikeNode, ParentNode, Point, Position, RootNode, TagLikeNode, TextNode, ValueNode };
|
||||
0
dealplustech-astro/node_modules/@astrojs/compiler/dist/shared/ast.js
generated
vendored
0
dealplustech-astro/node_modules/@astrojs/compiler/dist/shared/ast.js
generated
vendored
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user