init
commit
11eb64b5e5
|
@ -0,0 +1,26 @@
|
|||
# build output
|
||||
dist/
|
||||
# generated types
|
||||
.astro/
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
|
||||
# environment variables
|
||||
.env
|
||||
.env.production
|
||||
|
||||
# macOS-specific files
|
||||
.DS_Store
|
||||
|
||||
# jetbrains setting folder
|
||||
.idea/
|
||||
|
||||
.vscode/
|
|
@ -0,0 +1,15 @@
|
|||
// @ts-check
|
||||
import { defineConfig } from 'astro/config';
|
||||
import tailwind from '@astrojs/tailwind';
|
||||
import react from '@astrojs/react';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
site: 'https://siliconpin.com',
|
||||
integrations: [tailwind(), react()],
|
||||
server: {
|
||||
host: '0.0.0.0',
|
||||
port: 3000
|
||||
},
|
||||
output: 'static',
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
build:
|
||||
command: npm run build
|
||||
static_build_dir: dist
|
||||
dev:
|
||||
command: npm run dev
|
||||
port: 3000
|
||||
redirects:
|
||||
- from: /*
|
||||
to: /
|
||||
status: 200
|
|
@ -0,0 +1,13 @@
|
|||
[build]
|
||||
command = "npm run build"
|
||||
publish = "dist"
|
||||
|
||||
[dev]
|
||||
command = "npm run dev"
|
||||
port = 3000
|
||||
|
||||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/index.html"
|
||||
status = 200
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "siliconpin-services",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/react": "^4.2.1",
|
||||
"@astrojs/tailwind": "^6.0.0",
|
||||
"@shadcn/ui": "^0.0.4",
|
||||
"astro": "^5.5.2",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"postcss": "^8.5.3",
|
||||
"tailwind-merge": "^3.0.2",
|
||||
"tailwindcss": "^3.4.17"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
|
@ -0,0 +1,7 @@
|
|||
<svg width="60" height="60" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="50" height="50" fill="#FF0000"/>
|
||||
<rect y="100" width="50" height="50" fill="#0000FF"/>
|
||||
<rect x="100" width="50" height="50" fill="#FF0000"/>
|
||||
<rect x="100" y="100" width="50" height="50" fill="#0000FF"/>
|
||||
<rect x="50" y="50" width="50" height="50" fill="#008000"/>
|
||||
</svg>
|
After Width: | Height: | Size: 401 B |
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
|
@ -0,0 +1,7 @@
|
|||
<svg width="60" height="60" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="50" height="50" fill="#FF0000"/>
|
||||
<rect y="100" width="50" height="50" fill="#0000FF"/>
|
||||
<rect x="100" width="50" height="50" fill="#FF0000"/>
|
||||
<rect x="100" y="100" width="50" height="50" fill="#0000FF"/>
|
||||
<rect x="50" y="50" width="50" height="50" fill="#008000"/>
|
||||
</svg>
|
After Width: | Height: | Size: 401 B |
|
@ -0,0 +1,7 @@
|
|||
<svg width="60" height="60" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="50" height="50" fill="#FF0000"/>
|
||||
<rect y="100" width="50" height="50" fill="#0000FF"/>
|
||||
<rect x="100" width="50" height="50" fill="#FF0000"/>
|
||||
<rect x="100" y="100" width="50" height="50" fill="#0000FF"/>
|
||||
<rect x="50" y="50" width="50" height="50" fill="#008000"/>
|
||||
</svg>
|
After Width: | Height: | Size: 401 B |
|
@ -0,0 +1,162 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Input } from './ui/input';
|
||||
import { Textarea } from './ui/textarea';
|
||||
import { Label } from './ui/label';
|
||||
import { Select } from './ui/select';
|
||||
import { Button } from './ui/button';
|
||||
|
||||
export function ContactForm() {
|
||||
const [formState, setFormState] = useState({
|
||||
name: '',
|
||||
email: '',
|
||||
company: '',
|
||||
service: '',
|
||||
message: '',
|
||||
});
|
||||
|
||||
const [formStatus, setFormStatus] = useState<'idle' | 'submitting' | 'success' | 'error'>('idle');
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
|
||||
const { name, value } = e.target;
|
||||
setFormState(prev => ({ ...prev, [name]: value }));
|
||||
};
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setFormStatus('submitting');
|
||||
|
||||
// Simulate form submission with a timeout
|
||||
setTimeout(() => {
|
||||
// In a real app, you would send the data to a server here
|
||||
console.log('Form submitted:', formState);
|
||||
setFormStatus('success');
|
||||
|
||||
// Reset form after successful submission
|
||||
setFormState({
|
||||
name: '',
|
||||
email: '',
|
||||
company: '',
|
||||
service: '',
|
||||
message: '',
|
||||
});
|
||||
|
||||
// Reset status after showing success message for a while
|
||||
setTimeout(() => {
|
||||
setFormStatus('idle');
|
||||
}, 3000);
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} className="space-y-4 sm:space-y-6">
|
||||
<div className="space-y-3 sm:space-y-4">
|
||||
{/* Name and Email - Stack on mobile, side-by-side on tablet+ */}
|
||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 sm:gap-4">
|
||||
<div className="space-y-1 sm:space-y-2">
|
||||
<Label htmlFor="name" className="text-sm sm:text-base">Name</Label>
|
||||
<Input
|
||||
id="name"
|
||||
name="name"
|
||||
placeholder="Your name"
|
||||
value={formState.name}
|
||||
onChange={handleChange}
|
||||
required
|
||||
className="text-sm sm:text-base"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1 sm:space-y-2">
|
||||
<Label htmlFor="email" className="text-sm sm:text-base">Email</Label>
|
||||
<Input
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
placeholder="your.email@example.com"
|
||||
value={formState.email}
|
||||
onChange={handleChange}
|
||||
required
|
||||
className="text-sm sm:text-base"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Company and Service Interest - Stack on mobile, side-by-side on tablet+ */}
|
||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 sm:gap-4">
|
||||
<div className="space-y-1 sm:space-y-2">
|
||||
<Label htmlFor="company" className="text-sm sm:text-base">Company</Label>
|
||||
<Input
|
||||
id="company"
|
||||
name="company"
|
||||
placeholder="Your company name"
|
||||
value={formState.company}
|
||||
onChange={handleChange}
|
||||
className="text-sm sm:text-base"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1 sm:space-y-2">
|
||||
<Label htmlFor="service" className="text-sm sm:text-base">Service Interest</Label>
|
||||
<Select
|
||||
id="service"
|
||||
name="service"
|
||||
value={formState.service}
|
||||
onChange={handleChange}
|
||||
required
|
||||
className="text-sm sm:text-base"
|
||||
>
|
||||
<option value="" disabled>Select a service</option>
|
||||
<option value="php">PHP Hosting</option>
|
||||
<option value="nodejs">Node.js Hosting</option>
|
||||
<option value="python">Python Hosting</option>
|
||||
<option value="kubernetes">Kubernetes (K8s)</option>
|
||||
<option value="k3s">K3s Lightweight Kubernetes</option>
|
||||
<option value="custom">Custom Solution</option>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1 sm:space-y-2">
|
||||
<Label htmlFor="message" className="text-sm sm:text-base">Message</Label>
|
||||
<Textarea
|
||||
id="message"
|
||||
name="message"
|
||||
placeholder="Tell us about your project requirements..."
|
||||
value={formState.message}
|
||||
onChange={handleChange}
|
||||
required
|
||||
className="min-h-[100px] sm:min-h-[150px] text-sm sm:text-base"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
size="lg"
|
||||
className="w-full mt-2 text-sm sm:text-base py-2 sm:py-3"
|
||||
disabled={formStatus === 'submitting'}
|
||||
>
|
||||
{formStatus === 'submitting' ? (
|
||||
<>
|
||||
<svg className="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
|
||||
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
Sending...
|
||||
</>
|
||||
) : 'Send Message'}
|
||||
</Button>
|
||||
|
||||
{formStatus === 'success' && (
|
||||
<div className="p-3 sm:p-4 bg-green-900/30 border border-green-800 rounded-md text-green-400 text-center text-sm sm:text-base">
|
||||
Thank you for your message! We'll get back to you soon.
|
||||
</div>
|
||||
)}
|
||||
|
||||
{formStatus === 'error' && (
|
||||
<div className="p-3 sm:p-4 bg-red-900/30 border border-red-800 rounded-md text-red-400 text-center text-sm sm:text-base">
|
||||
There was an error sending your message. Please try again.
|
||||
</div>
|
||||
)}
|
||||
</form>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,713 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Toast } from './Toast';
|
||||
import { TemplatePreview } from './TemplatePreview';
|
||||
|
||||
export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||||
// Deployment type and app selections
|
||||
const [deploymentType, setDeploymentType] = useState('app');
|
||||
const [appType, setAppType] = useState('wordpress');
|
||||
const [sampleWebAppType, setSampleWebAppType] = useState('developer'); // New state for sample web app type
|
||||
const [sourceType, setSourceType] = useState('public');
|
||||
const [repoUrl, setRepoUrl] = useState('');
|
||||
const [deploymentKey, setDeploymentKey] = useState('');
|
||||
const [fileName, setFileName] = useState('');
|
||||
|
||||
// Domain configuration
|
||||
const [useSubdomain, setUseSubdomain] = useState(true);
|
||||
const [useCustomDomain, setUseCustomDomain] = useState(false);
|
||||
const [customDomain, setCustomDomain] = useState('');
|
||||
const [customSubdomain, setCustomSubdomain] = useState('');
|
||||
const [domainType, setDomainType] = useState('domain'); // 'domain' or 'subdomain'
|
||||
|
||||
// Domain validation states
|
||||
const [isValidating, setIsValidating] = useState(false);
|
||||
const [isValidDomain, setIsValidDomain] = useState(false);
|
||||
const [validationMessage, setValidationMessage] = useState('');
|
||||
|
||||
// DNS configuration
|
||||
const [dnsMethod, setDnsMethod] = useState('cname');
|
||||
const [showDnsConfig, setShowDnsConfig] = useState(false);
|
||||
const [dnsVerified, setDnsVerified] = useState({
|
||||
cname: false,
|
||||
ns: false,
|
||||
a: false
|
||||
});
|
||||
|
||||
// Form validation
|
||||
const [formValid, setFormValid] = useState(true);
|
||||
|
||||
// Toast notification
|
||||
const [toast, setToast] = useState({ visible: false, message: '' });
|
||||
|
||||
// File upload reference
|
||||
const fileInputRef = React.useRef(null);
|
||||
|
||||
// Function to clean domain input
|
||||
const cleanDomainInput = (input) => {
|
||||
// Remove http://, https://, www., and trailing slashes
|
||||
return input
|
||||
.replace(/^(https?:\/\/)?(www\.)?/i, '')
|
||||
.replace(/\/+$/, '')
|
||||
.trim();
|
||||
};
|
||||
|
||||
// Effect for handling domain type changes
|
||||
useEffect(() => {
|
||||
if (!useCustomDomain) {
|
||||
setShowDnsConfig(false);
|
||||
setIsValidDomain(false);
|
||||
setValidationMessage('');
|
||||
setIsValidating(false);
|
||||
}
|
||||
|
||||
validateForm();
|
||||
}, [useCustomDomain, dnsVerified.cname, dnsVerified.ns, domainType, dnsMethod]);
|
||||
|
||||
// Show toast notification
|
||||
const showToast = (message) => {
|
||||
setToast({ visible: true, message });
|
||||
setTimeout(() => setToast({ visible: false, message: '' }), 3000);
|
||||
};
|
||||
|
||||
// Handle deployment type change
|
||||
const handleDeploymentTypeChange = (e) => {
|
||||
setDeploymentType(e.target.value);
|
||||
};
|
||||
|
||||
// Handle source type change
|
||||
const handleSourceTypeChange = (e) => {
|
||||
setSourceType(e.target.value);
|
||||
};
|
||||
|
||||
// Handle file upload
|
||||
const handleFileChange = (e) => {
|
||||
if (e.target.files.length > 0) {
|
||||
setFileName(e.target.files[0].name);
|
||||
} else {
|
||||
setFileName('');
|
||||
}
|
||||
};
|
||||
|
||||
// Handle domain checkbox changes
|
||||
const handleUseSubdomainChange = (e) => {
|
||||
setUseSubdomain(e.target.checked);
|
||||
|
||||
// If CNAME record is selected, SiliconPin subdomain must be enabled
|
||||
if (useCustomDomain && dnsMethod === 'cname' && !e.target.checked) {
|
||||
setUseCustomDomain(false);
|
||||
}
|
||||
|
||||
validateForm();
|
||||
};
|
||||
|
||||
const handleUseCustomDomainChange = (e) => {
|
||||
setUseCustomDomain(e.target.checked);
|
||||
if (!e.target.checked) {
|
||||
setShowDnsConfig(false);
|
||||
setIsValidDomain(false);
|
||||
setValidationMessage('');
|
||||
setIsValidating(false);
|
||||
setDnsVerified({
|
||||
cname: false,
|
||||
ns: false,
|
||||
a: false
|
||||
});
|
||||
} else {
|
||||
// Force SiliconPin subdomain to be checked if custom domain is checked
|
||||
setUseSubdomain(true);
|
||||
}
|
||||
|
||||
validateForm();
|
||||
};
|
||||
|
||||
// Handle domain type change
|
||||
const handleDomainTypeChange = (e) => {
|
||||
setDomainType(e.target.value);
|
||||
|
||||
// Reset validation when changing domain type
|
||||
setIsValidDomain(false);
|
||||
setValidationMessage('');
|
||||
setDnsVerified({
|
||||
cname: false,
|
||||
ns: false,
|
||||
a: false
|
||||
});
|
||||
|
||||
validateForm();
|
||||
};
|
||||
|
||||
// Handle domain and subdomain input changes
|
||||
const handleDomainChange = (e) => {
|
||||
const cleanedValue = cleanDomainInput(e.target.value);
|
||||
setCustomDomain(cleanedValue);
|
||||
};
|
||||
|
||||
const handleSubdomainChange = (e) => {
|
||||
const cleanedValue = cleanDomainInput(e.target.value);
|
||||
setCustomSubdomain(cleanedValue);
|
||||
};
|
||||
|
||||
// Handle DNS method change
|
||||
const handleDnsMethodChange = (e) => {
|
||||
setDnsMethod(e.target.value);
|
||||
|
||||
// If changing to CNAME, ensure SiliconPin subdomain is enabled
|
||||
if (e.target.value === 'cname') {
|
||||
setUseSubdomain(true);
|
||||
}
|
||||
|
||||
// Reset DNS verification
|
||||
setDnsVerified(prev => ({
|
||||
...prev,
|
||||
[e.target.value]: false
|
||||
}));
|
||||
|
||||
validateForm();
|
||||
};
|
||||
|
||||
// Validate domain
|
||||
const validateDomain = () => {
|
||||
const domain = domainType === 'domain' ? customDomain : customSubdomain;
|
||||
|
||||
if (!domain) {
|
||||
setValidationMessage('Please enter a domain name.');
|
||||
setIsValidDomain(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Initial validation: check format with regex
|
||||
const validFormat = /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/.test(domain);
|
||||
if (!validFormat) {
|
||||
setValidationMessage('Domain format is invalid. Please check your entry.');
|
||||
setIsValidDomain(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setIsValidating(true);
|
||||
setValidationMessage('');
|
||||
setShowDnsConfig(false);
|
||||
|
||||
// Simulate an API call to validate the domain
|
||||
setTimeout(() => {
|
||||
// Simulate a real domain check - in a real app this would be an API call
|
||||
const checkResult = true; // Assume domain is valid for demo
|
||||
|
||||
setIsValidating(false);
|
||||
setIsValidDomain(checkResult);
|
||||
|
||||
if (checkResult) {
|
||||
setValidationMessage('Domain is valid and registered.');
|
||||
setShowDnsConfig(true);
|
||||
} else {
|
||||
setValidationMessage('Domain appears to be unregistered or unavailable.');
|
||||
}
|
||||
|
||||
validateForm();
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
// Check DNS configuration
|
||||
const checkDnsConfig = (type) => {
|
||||
showToast(`Checking ${type}... (This would verify DNS in a real app)`);
|
||||
|
||||
// Simulate DNS check
|
||||
setTimeout(() => {
|
||||
setDnsVerified(prev => ({
|
||||
...prev,
|
||||
[type]: true
|
||||
}));
|
||||
|
||||
showToast(`${type} verified successfully!`);
|
||||
validateForm();
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
// Copy to clipboard
|
||||
const copyToClipboard = (text) => {
|
||||
navigator.clipboard.writeText(text)
|
||||
.then(() => {
|
||||
showToast('Copied to clipboard!');
|
||||
})
|
||||
.catch(err => {
|
||||
showToast('Failed to copy: ' + err);
|
||||
});
|
||||
};
|
||||
|
||||
// Validate form
|
||||
const validateForm = () => {
|
||||
// For custom domain, require DNS verification
|
||||
if (useCustomDomain) {
|
||||
if (dnsMethod === 'cname' && !dnsVerified.cname) {
|
||||
setFormValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dnsMethod === 'ns' && !dnsVerified.ns) {
|
||||
setFormValid(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setFormValid(true);
|
||||
};
|
||||
|
||||
// Handle form submission
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!formValid) {
|
||||
showToast('Please complete DNS verification before deploying.');
|
||||
return;
|
||||
}
|
||||
|
||||
// In a real app, this would submit the form data to the server
|
||||
console.log({
|
||||
deploymentType,
|
||||
appType,
|
||||
sampleWebAppType,
|
||||
sourceType,
|
||||
repoUrl,
|
||||
deploymentKey,
|
||||
useSubdomain,
|
||||
useCustomDomain,
|
||||
customDomain,
|
||||
customSubdomain,
|
||||
domainType,
|
||||
dnsMethod
|
||||
});
|
||||
|
||||
showToast('Form submitted successfully!');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
{/* Deployment Type Selection */}
|
||||
<div className="space-y-2">
|
||||
<label htmlFor="deployment-type" className="block text-white font-medium">Deployment Type</label>
|
||||
<select
|
||||
id="deployment-type"
|
||||
value={deploymentType}
|
||||
onChange={handleDeploymentTypeChange}
|
||||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||
>
|
||||
<option value="app">💻 Deploy an App</option>
|
||||
<option value="source">⚙️ From Source</option>
|
||||
<option value="static">📄 Static Site Upload</option>
|
||||
<option value="sample-web-app">🌐 Sample Web App</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* App Options */}
|
||||
{deploymentType === 'app' && (
|
||||
<div className="space-y-2">
|
||||
<label htmlFor="app-type" className="block text-white font-medium">Select Application</label>
|
||||
<select
|
||||
id="app-type"
|
||||
value={appType}
|
||||
onChange={(e) => setAppType(e.target.value)}
|
||||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||
>
|
||||
<option value="wordpress">🔌 WordPress</option>
|
||||
<option value="prestashop">🛒 PrestaShop</option>
|
||||
<option value="laravel">🚀 Laravel</option>
|
||||
<option value="cakephp">🍰 CakePHP</option>
|
||||
<option value="symfony">🎯 Symfony</option>
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Sample Web App Options */}
|
||||
{deploymentType === 'sample-web-app' && (
|
||||
<div className="space-y-2">
|
||||
<label htmlFor="sample-web-app-type" className="block text-white font-medium">Select Template Type</label>
|
||||
<select
|
||||
id="sample-web-app-type"
|
||||
value={sampleWebAppType}
|
||||
onChange={(e) => setSampleWebAppType(e.target.value)}
|
||||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||
>
|
||||
<option value="developer">👨💻 Developer Portfolio</option>
|
||||
<option value="designer">🎨 Designer Portfolio</option>
|
||||
<option value="photographer">📸 Photographer Portfolio</option>
|
||||
<option value="documentation">📚 Documentation Site</option>
|
||||
<option value="business">🏢 Single Page Business Site</option>
|
||||
</select>
|
||||
|
||||
<div className="mt-4 p-4 bg-neutral-700/30 rounded-md border border-neutral-600">
|
||||
<div className="flex items-start">
|
||||
<div className="mr-3 text-2xl">ℹ️</div>
|
||||
<div className="flex-1">
|
||||
<p className="text-sm text-neutral-300">
|
||||
Deploy a ready-to-use template that you can customize. We'll set up the basic structure and you can modify it to fit your needs.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Template Preview */}
|
||||
<TemplatePreview templateType={sampleWebAppType} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Source Options */}
|
||||
{deploymentType === 'source' && (
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<label htmlFor="source-type" className="block text-white font-medium">Source Type</label>
|
||||
<select
|
||||
id="source-type"
|
||||
value={sourceType}
|
||||
onChange={handleSourceTypeChange}
|
||||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||
>
|
||||
<option value="public">🌐 Public Repository</option>
|
||||
<option value="private">🔒 Private Repository</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="pt-2">
|
||||
<label htmlFor="repo-url" className="block text-white font-medium mb-2">Repository URL</label>
|
||||
<input
|
||||
type="text"
|
||||
id="repo-url"
|
||||
value={repoUrl}
|
||||
onChange={(e) => setRepoUrl(e.target.value)}
|
||||
placeholder="https://github.com/username/repository"
|
||||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{sourceType === 'private' && (
|
||||
<div className="pt-2">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<label htmlFor="deployment-key" className="block text-white font-medium">Deployment Key</label>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => showToast('Deployment keys are used for secure access to private repositories')}
|
||||
className="text-neutral-400 hover:text-white focus:outline-none"
|
||||
aria-label="Deployment Key Information"
|
||||
>
|
||||
<span className="text-lg">❓</span>
|
||||
</button>
|
||||
</div>
|
||||
<textarea
|
||||
id="deployment-key"
|
||||
value={deploymentKey}
|
||||
onChange={(e) => setDeploymentKey(e.target.value)}
|
||||
placeholder="Paste your SSH private key here"
|
||||
rows="6"
|
||||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37] font-mono text-sm"
|
||||
/>
|
||||
<p className="mt-1 text-sm text-neutral-400">Your private key is used only for deploying and is never stored on our servers.</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Static Site Options */}
|
||||
{deploymentType === 'static' && (
|
||||
<div className="space-y-4">
|
||||
<div className="p-4 bg-neutral-700/50 rounded-md text-neutral-300 text-center">
|
||||
Upload the zip file containing your static website
|
||||
</div>
|
||||
|
||||
<div className="pt-2">
|
||||
<label htmlFor="file-upload" className="block text-white font-medium mb-2">Upload File (ZIP/TAR)</label>
|
||||
<div className="flex items-center justify-center w-full">
|
||||
<label
|
||||
htmlFor="file-upload"
|
||||
className="flex flex-col items-center justify-center w-full h-32 border-2 border-dashed rounded-lg cursor-pointer border-neutral-600 hover:border-[#6d9e37]"
|
||||
>
|
||||
<div className="flex flex-col items-center justify-center pt-5 pb-6">
|
||||
<span className="text-3xl mb-3 text-neutral-400">📁</span>
|
||||
<p className="mb-2 text-sm text-neutral-400">
|
||||
<span className="font-semibold">Click to upload</span> or drag and drop
|
||||
</p>
|
||||
<p className="text-xs text-neutral-500">ZIP or TAR files only (max. 100MB)</p>
|
||||
</div>
|
||||
<input
|
||||
id="file-upload"
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
onChange={handleFileChange}
|
||||
className="hidden"
|
||||
accept=".zip,.tar"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
{fileName && (
|
||||
<div className="mt-2 text-sm text-neutral-400">
|
||||
Selected file: {fileName}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Domain Configuration */}
|
||||
<div className="pt-4 border-t border-neutral-700">
|
||||
<h3 className="text-lg font-medium text-white mb-4">Destination</h3>
|
||||
|
||||
<div className="space-y-4">
|
||||
{/* SiliconPin Subdomain */}
|
||||
<div className="flex items-start gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="use-subdomain"
|
||||
checked={useSubdomain}
|
||||
onChange={handleUseSubdomainChange}
|
||||
className="mt-1"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<label htmlFor="use-subdomain" className="block text-white font-medium">Use SiliconPin Subdomain</label>
|
||||
<div className="mt-2 flex">
|
||||
<input
|
||||
type="text"
|
||||
id="subdomain"
|
||||
value={defaultSubdomain}
|
||||
className="rounded-l-md py-2 px-3 bg-neutral-600 border-y border-l border-neutral-600 text-neutral-300 focus:outline-none w-1/3 font-mono"
|
||||
readOnly
|
||||
/>
|
||||
<span className="rounded-r-md py-2 px-3 bg-neutral-800 border border-neutral-700 text-neutral-400 w-2/3">.subdomain.siliconpin.com</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Custom Domain */}
|
||||
<div className="flex items-start gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="use-custom-domain"
|
||||
checked={useCustomDomain}
|
||||
onChange={handleUseCustomDomainChange}
|
||||
className="mt-1"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<label htmlFor="use-custom-domain" className="block text-white font-medium">Use Custom Domain</label>
|
||||
|
||||
{useCustomDomain && (
|
||||
<div className="mt-3 space-y-4">
|
||||
{/* Domain Type Selection */}
|
||||
<div className="flex flex-col space-y-3 sm:flex-row sm:space-y-0 sm:space-x-4">
|
||||
<div className="flex items-center">
|
||||
<input
|
||||
type="radio"
|
||||
id="domain-type-domain"
|
||||
name="domain-type"
|
||||
value="domain"
|
||||
checked={domainType === 'domain'}
|
||||
onChange={handleDomainTypeChange}
|
||||
className="mr-2"
|
||||
/>
|
||||
<label htmlFor="domain-type-domain" className="text-white">Root Domain</label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center">
|
||||
<input
|
||||
type="radio"
|
||||
id="domain-type-subdomain"
|
||||
name="domain-type"
|
||||
value="subdomain"
|
||||
checked={domainType === 'subdomain'}
|
||||
onChange={handleDomainTypeChange}
|
||||
className="mr-2"
|
||||
/>
|
||||
<label htmlFor="domain-type-subdomain" className="text-white">Subdomain</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Domain Input */}
|
||||
{domainType === 'domain' ? (
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
id="custom-domain"
|
||||
value={customDomain}
|
||||
onChange={handleDomainChange}
|
||||
placeholder="yourdomain.com"
|
||||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||
/>
|
||||
<p className="mt-1 text-xs text-neutral-400">
|
||||
Enter domain without http://, www, or trailing slashes (example.com). You can configure www or other subdomains later.
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
id="custom-subdomain"
|
||||
value={customSubdomain}
|
||||
onChange={handleSubdomainChange}
|
||||
placeholder="blog.yourdomain.com"
|
||||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||
/>
|
||||
<p className="mt-1 text-xs text-neutral-400">
|
||||
Enter the full subdomain without http:// or trailing slashes. www and protocol prefixes will be automatically removed.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Domain Validation */}
|
||||
<button
|
||||
type="button"
|
||||
onClick={validateDomain}
|
||||
className="px-4 py-2 bg-neutral-600 text-white font-medium rounded-md hover:bg-neutral-500 transition-colors focus:outline-none focus:ring-2 focus:ring-neutral-500"
|
||||
>
|
||||
Validate Domain
|
||||
</button>
|
||||
|
||||
{/* Validation Status */}
|
||||
{useCustomDomain && isValidating && (
|
||||
<div className="p-3 bg-neutral-700/50 rounded-md">
|
||||
<div className="flex items-center justify-center space-x-2">
|
||||
<div className="animate-spin rounded-full h-5 w-5 border-b-2 border-white"></div>
|
||||
<p className="text-white">Verifying domain registration and availability...</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{useCustomDomain && !isValidating && validationMessage && (
|
||||
<div className={`p-3 rounded-md ${isValidDomain ? 'bg-green-900/20 border border-green-700/50' : 'bg-red-900/20 border border-red-700/50'}`}>
|
||||
<p className={isValidDomain ? 'text-green-400' : 'text-red-400'}>
|
||||
{validationMessage}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* DNS Configuration Options */}
|
||||
{showDnsConfig && (
|
||||
<div className="mt-4 space-y-4 p-4 rounded-md bg-neutral-800/50 border border-neutral-700">
|
||||
<h4 className="text-white font-medium">Connect Your Domain</h4>
|
||||
|
||||
{/* CNAME Record Option */}
|
||||
<div className="p-4 bg-neutral-700/30 rounded-md border border-neutral-600 space-y-3">
|
||||
<div className="flex items-start">
|
||||
<input
|
||||
type="radio"
|
||||
id="dns-cname"
|
||||
name="dns-method"
|
||||
value="cname"
|
||||
checked={dnsMethod === 'cname'}
|
||||
onChange={handleDnsMethodChange}
|
||||
className="mt-1 mr-2"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<label htmlFor="dns-cname" className="block text-white font-medium">Use CNAME Record</label>
|
||||
<p className="text-sm text-neutral-300">Point your domain to our SiliconPin subdomain</p>
|
||||
|
||||
<div className="mt-3 flex items-center">
|
||||
<div className="bg-neutral-800 p-2 rounded font-mono text-sm text-neutral-300">
|
||||
{defaultSubdomain}.subdomain.siliconpin.com
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => copyToClipboard(`${defaultSubdomain}.subdomain.siliconpin.com`)}
|
||||
className="ml-2 text-[#6d9e37] hover:text-white"
|
||||
aria-label="Copy CNAME value"
|
||||
>
|
||||
<span className="text-lg">📋</span>
|
||||
</button>
|
||||
</div>
|
||||
<div className="mt-2 text-right">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => checkDnsConfig('cname')}
|
||||
className={`px-3 py-1 text-white text-sm rounded
|
||||
${dnsVerified.cname
|
||||
? 'bg-green-700 hover:bg-green-600'
|
||||
: 'bg-neutral-600 hover:bg-neutral-500'}`}
|
||||
>
|
||||
{dnsVerified.cname ? '✓ CNAME Verified' : 'Check CNAME'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Nameserver Option (only for full domains, not subdomains) */}
|
||||
{domainType === 'domain' && (
|
||||
<div className="p-4 bg-neutral-700/30 rounded-md border border-neutral-600 space-y-3">
|
||||
<div className="flex items-start">
|
||||
<input
|
||||
type="radio"
|
||||
id="dns-ns"
|
||||
name="dns-method"
|
||||
value="ns"
|
||||
checked={dnsMethod === 'ns'}
|
||||
onChange={handleDnsMethodChange}
|
||||
className="mt-1 mr-2"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<label htmlFor="dns-ns" className="block text-white font-medium">Use Our Nameservers</label>
|
||||
<p className="text-sm text-neutral-300">Update your domain's nameservers to use ours</p>
|
||||
|
||||
<div className="mt-3 space-y-2">
|
||||
<div className="flex items-center">
|
||||
<div className="bg-neutral-800 p-2 rounded font-mono text-sm text-neutral-300">ns1.siliconpin.com</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => copyToClipboard('ns1.siliconpin.com')}
|
||||
className="ml-2 text-[#6d9e37] hover:text-white"
|
||||
aria-label="Copy nameserver value"
|
||||
>
|
||||
<span className="text-lg">📋</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center">
|
||||
<div className="bg-neutral-800 p-2 rounded font-mono text-sm text-neutral-300">ns2.siliconpin.com</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => copyToClipboard('ns2.siliconpin.com')}
|
||||
className="ml-2 text-[#6d9e37] hover:text-white"
|
||||
aria-label="Copy nameserver value"
|
||||
>
|
||||
<span className="text-lg">📋</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-2 text-right">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => checkDnsConfig('ns')}
|
||||
className={`px-3 py-1 text-white text-sm rounded
|
||||
${dnsVerified.ns
|
||||
? 'bg-green-700 hover:bg-green-600'
|
||||
: 'bg-neutral-600 hover:bg-neutral-500'}`}
|
||||
>
|
||||
{dnsVerified.ns ? '✓ Nameservers Verified' : 'Check Nameservers'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Form Submit Button */}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={useCustomDomain && !formValid}
|
||||
className={`w-full mt-6 px-6 py-3 text-white font-medium rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-neutral-800
|
||||
${useCustomDomain && !formValid
|
||||
? 'bg-neutral-600 cursor-not-allowed'
|
||||
: 'bg-[#6d9e37] hover:bg-[#598035] focus:ring-[#6d9e37] transition-colors'
|
||||
}`}
|
||||
>
|
||||
Start the Deployment
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<Toast visible={toast.visible} message={toast.message} />
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,46 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Toast } from './Toast';
|
||||
|
||||
export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||||
// Deployment state
|
||||
const [deploymentType, setDeploymentType] = useState('app');
|
||||
const [appType, setAppType] = useState('wordpress');
|
||||
const [sampleWebAppType, setSampleWebAppType] = useState('developer'); // New state for sample web app type
|
||||
const [sourceType, setSourceType] = useState('public');
|
||||
const [repoUrl, setRepoUrl] = useState('');
|
||||
const [deploymentKey, setDeploymentKey] = useState('');
|
||||
const [fileName, setFileName] = useState('');
|
||||
|
||||
// Sample web app template information
|
||||
const templateInfo = {
|
||||
developer: {
|
||||
name: "Developer Portfolio",
|
||||
description: "A modern, responsive portfolio site with sections for projects, skills, and contact information. Perfect for developers to showcase their work.",
|
||||
features: ["Project showcase", "Skills section", "GitHub integration", "Contact form", "Blog ready"],
|
||||
image: "https://images.unsplash.com/photo-1498050108023-c5249f4df085?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2072&q=80"
|
||||
},
|
||||
designer: {
|
||||
name: "Designer Portfolio",
|
||||
description: "A visually stunning portfolio for designers with image galleries, case studies, and animations to showcase creative work.",
|
||||
features: ["Visual gallery", "Case studies", "Color scheme customization", "Smooth animations", "Design process showcase"],
|
||||
image: "https://images.unsplash.com/photo-1561070791-2526d30994b5?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2000&q=80"
|
||||
},
|
||||
photographer: {
|
||||
name: "Photographer Portfolio",
|
||||
description: "An elegant portfolio with fullscreen galleries, image zooming, and lightbox features designed for photographers to display their work.",
|
||||
features: ["Fullscreen galleries", "Image zoom", "Lightbox", "Category filtering", "Client proofing"],
|
||||
image: "https://images.unsplash.com/photo-1542038784456-1ea8e935640e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2070&q=80"
|
||||
},
|
||||
documentation: {
|
||||
name: "Documentation Site",
|
||||
description: "A comprehensive documentation site with search, code snippets, and versioning support for technical documentation.",
|
||||
features: ["Search functionality", "Code snippets with syntax highlighting", "Versioning", "Sidebar navigation", "Mobile-friendly"],
|
||||
image: "https://images.unsplash.com/photo-1456406644174-8ddd4cd52a06?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2068&q=80"
|
||||
},
|
||||
business: {
|
||||
name: "Single Page Business Site",
|
||||
description: "A professional one-page website for businesses with sections for services, testimonials, team members, and contact information.",
|
||||
features: ["Single page layout", "Services section", "Testimonials", "Team profiles", "Contact form with map"],
|
||||
image: "https://images.unsplash.com/photo-1560179707-f14e90ef3623?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2073&q=80"
|
||||
}
|
||||
};
|
|
@ -0,0 +1,318 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Toast } from './Toast';
|
||||
|
||||
export const FeedbackForm = () => {
|
||||
// Form state
|
||||
const [formType, setFormType] = useState('suggestion'); // 'suggestion' or 'report'
|
||||
const [name, setName] = useState('');
|
||||
const [email, setEmail] = useState('');
|
||||
const [title, setTitle] = useState('');
|
||||
const [details, setDetails] = useState('');
|
||||
const [urgency, setUrgency] = useState('low');
|
||||
const [category, setCategory] = useState('general');
|
||||
const [referrer, setReferrer] = useState('');
|
||||
const [screenshot, setScreenshot] = useState(null);
|
||||
const [screenshotName, setScreenshotName] = useState('');
|
||||
|
||||
// UI states
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [toast, setToast] = useState({ visible: false, message: '', type: 'success' });
|
||||
|
||||
// Get referrer information on mount
|
||||
useEffect(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const savedReferrer = localStorage.getItem('pageReferrer') || 'Direct Access';
|
||||
setReferrer(savedReferrer);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Handle form type toggle
|
||||
const handleFormTypeChange = (e) => {
|
||||
setFormType(e.target.checked ? 'report' : 'suggestion');
|
||||
};
|
||||
|
||||
// Handle file upload
|
||||
const handleFileChange = (e) => {
|
||||
if (e.target.files.length > 0) {
|
||||
setScreenshot(e.target.files[0]);
|
||||
setScreenshotName(e.target.files[0].name);
|
||||
} else {
|
||||
setScreenshot(null);
|
||||
setScreenshotName('');
|
||||
}
|
||||
};
|
||||
|
||||
// Show toast notification
|
||||
const showToast = (message, type = 'success') => {
|
||||
setToast({ visible: true, message, type });
|
||||
setTimeout(() => setToast({ visible: false, message: '', type: 'success' }), 5000);
|
||||
};
|
||||
|
||||
// Form validation
|
||||
const validateForm = () => {
|
||||
if (!name.trim()) {
|
||||
showToast('Please enter your name.', 'error');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!email.trim() || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
||||
showToast('Please enter a valid email address.', 'error');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!title.trim()) {
|
||||
showToast('Please enter a title for your ' + formType + '.', 'error');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!details.trim()) {
|
||||
showToast('Please provide details for your ' + formType + '.', 'error');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// Handle form submission
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!validateForm()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSubmitting(true);
|
||||
|
||||
// In a real app, this would be an API call to submit the form
|
||||
setTimeout(() => {
|
||||
console.log({
|
||||
formType,
|
||||
name,
|
||||
email,
|
||||
title,
|
||||
details,
|
||||
urgency: formType === 'report' ? urgency : undefined,
|
||||
category,
|
||||
referrer,
|
||||
screenshot: screenshot ? 'File attached' : 'No file'
|
||||
});
|
||||
|
||||
// Reset form
|
||||
setTitle('');
|
||||
setDetails('');
|
||||
setUrgency('low');
|
||||
setCategory('general');
|
||||
setScreenshot(null);
|
||||
setScreenshotName('');
|
||||
|
||||
setIsSubmitting(false);
|
||||
showToast(
|
||||
formType === 'suggestion'
|
||||
? 'Thank you for your suggestion! We appreciate your feedback.'
|
||||
: 'Your report has been submitted. We will look into it as soon as possible.'
|
||||
);
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<div className="mb-6">
|
||||
<div className="flex items-center justify-center gap-3">
|
||||
<span className={`text-lg font-medium ${formType === 'suggestion' ? 'text-[#6d9e37]' : 'text-neutral-400'}`}>
|
||||
Suggestion
|
||||
</span>
|
||||
|
||||
{/* Toggle Switch */}
|
||||
<label className="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="sr-only peer"
|
||||
checked={formType === 'report'}
|
||||
onChange={handleFormTypeChange}
|
||||
/>
|
||||
<div className="w-11 h-6 bg-neutral-700 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-[#6d9e37] rounded-full peer peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-neutral-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#6d9e37]"></div>
|
||||
</label>
|
||||
|
||||
<span className={`text-lg font-medium ${formType === 'report' ? 'text-[#6d9e37]' : 'text-neutral-400'}`}>
|
||||
Report
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-5">
|
||||
{/* Hidden referrer field */}
|
||||
<input
|
||||
type="hidden"
|
||||
id="referrerField"
|
||||
name="referrer"
|
||||
value={referrer}
|
||||
/>
|
||||
|
||||
{/* Name and Email (2-column layout on larger screens) */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-5">
|
||||
<div>
|
||||
<label htmlFor="name" className="block text-white font-medium mb-1">Name <span className="text-red-500">*</span></label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||
placeholder="Your full name"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="email" className="block text-white font-medium mb-1">Email <span className="text-red-500">*</span></label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||
placeholder="Your email address"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Title */}
|
||||
<div>
|
||||
<label htmlFor="title" className="block text-white font-medium mb-1">
|
||||
{formType === 'suggestion' ? 'Suggestion Title' : 'Report Title'} <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="title"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||
placeholder={formType === 'suggestion' ? "Brief title for your suggestion" : "Brief title for your report"}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Category */}
|
||||
<div>
|
||||
<label htmlFor="category" className="block text-white font-medium mb-1">Category</label>
|
||||
<select
|
||||
id="category"
|
||||
value={category}
|
||||
onChange={(e) => setCategory(e.target.value)}
|
||||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||
>
|
||||
<option value="general">General</option>
|
||||
<option value="ui">User Interface</option>
|
||||
<option value="performance">Performance</option>
|
||||
<option value="feature">Feature Request</option>
|
||||
<option value="technical">Technical Issue</option>
|
||||
<option value="billing">Billing/Payment</option>
|
||||
<option value="security">Security</option>
|
||||
<option value="other">Other</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* Urgency (only for reports) */}
|
||||
{formType === 'report' && (
|
||||
<div>
|
||||
<label htmlFor="urgency" className="block text-white font-medium mb-1">Urgency Level</label>
|
||||
<select
|
||||
id="urgency"
|
||||
value={urgency}
|
||||
onChange={(e) => setUrgency(e.target.value)}
|
||||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||
>
|
||||
<option value="low">Low - Not urgent</option>
|
||||
<option value="medium">Medium - Needs attention</option>
|
||||
<option value="high">High - Impacts usage</option>
|
||||
<option value="critical">Critical - Service unavailable</option>
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Details */}
|
||||
<div>
|
||||
<label htmlFor="details" className="block text-white font-medium mb-1">
|
||||
Details <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="details"
|
||||
value={details}
|
||||
onChange={(e) => setDetails(e.target.value)}
|
||||
rows="6"
|
||||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||
placeholder={formType === 'suggestion'
|
||||
? "Please describe your suggestion in detail. What would you like to see improved or added?"
|
||||
: "Please describe the issue in detail. What happened, and what were you trying to do?"
|
||||
}
|
||||
required
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
{/* Screenshot upload (primarily for reports, but available for both) */}
|
||||
<div>
|
||||
<label htmlFor="screenshot" className="block text-white font-medium mb-1">
|
||||
{formType === 'report' ? 'Screenshot (Optional)' : 'Attachment (Optional)'}
|
||||
</label>
|
||||
<div className="flex flex-col items-center justify-center w-full">
|
||||
<label
|
||||
htmlFor="screenshot"
|
||||
className="flex flex-col items-center justify-center w-full h-24 border-2 border-dashed rounded-lg cursor-pointer border-neutral-600 hover:border-[#6d9e37]"
|
||||
>
|
||||
<div className="flex flex-col items-center justify-center pt-3 pb-3">
|
||||
<span className="text-2xl mb-1 text-neutral-400">📎</span>
|
||||
<p className="mb-1 text-sm text-neutral-400">
|
||||
<span className="font-semibold">Click to upload</span> or drag and drop
|
||||
</p>
|
||||
<p className="text-xs text-neutral-500">PNG, JPG, or PDF (max. 5MB)</p>
|
||||
</div>
|
||||
<input
|
||||
id="screenshot"
|
||||
type="file"
|
||||
onChange={handleFileChange}
|
||||
className="hidden"
|
||||
accept=".png,.jpg,.jpeg,.pdf"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
{screenshotName && (
|
||||
<div className="mt-2 text-sm text-neutral-400">
|
||||
Selected file: {screenshotName}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Referrer information display */}
|
||||
<div className="text-sm text-neutral-400 italic">
|
||||
<span>Page referrer: {referrer}</span>
|
||||
</div>
|
||||
|
||||
{/* Submit button */}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className="w-full mt-2 px-6 py-3 bg-[#6d9e37] text-white font-medium rounded-md hover:bg-[#598035] transition-colors focus:outline-none focus:ring-2 focus:ring-[#6d9e37] focus:ring-offset-2 focus:ring-offset-neutral-800 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<span className="flex items-center justify-center">
|
||||
<svg className="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
|
||||
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
Processing...
|
||||
</span>
|
||||
) : (
|
||||
`Submit ${formType === 'suggestion' ? 'Suggestion' : 'Report'}`
|
||||
)}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<Toast
|
||||
visible={toast.visible}
|
||||
message={toast.message}
|
||||
type={toast.type === 'error' ? 'error' : 'success'}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,54 @@
|
|||
import React from 'react';
|
||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './ui/card';
|
||||
|
||||
export interface ServiceCardProps {
|
||||
title: string;
|
||||
description: string;
|
||||
imageUrl: string;
|
||||
features: string[];
|
||||
learnMoreUrl: string;
|
||||
}
|
||||
|
||||
export function ServiceCard({ title, description, imageUrl, features, learnMoreUrl }: ServiceCardProps) {
|
||||
return (
|
||||
<Card className="overflow-hidden transition-all hover:shadow-lg dark:border-neutral-700 h-full flex flex-col">
|
||||
<div className="relative h-48 w-full overflow-hidden bg-neutral-100 dark:bg-neutral-800">
|
||||
<img
|
||||
src={imageUrl}
|
||||
alt={`${title} illustration`}
|
||||
className="object-cover w-full h-full transition-transform duration-300 hover:scale-105"
|
||||
/>
|
||||
</div>
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-xl text-[#6d9e37]">{title}</CardTitle>
|
||||
<CardDescription className="text-neutral-400">{description}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex-grow">
|
||||
<ul className="space-y-2 text-sm">
|
||||
{features.map((feature, index) => (
|
||||
<li key={index} className="flex items-start">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-5 w-5 mr-2 text-[#6d9e37] shrink-0"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
<span>{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<a
|
||||
href={learnMoreUrl}
|
||||
className="inline-flex items-center justify-center rounded-md bg-[#6d9e37] px-4 py-2 text-sm font-medium text-white hover:bg-[#598035] transition-colors w-full"
|
||||
>
|
||||
Learn More
|
||||
</a>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
import React from 'react';
|
||||
|
||||
export const TemplatePreview = ({ templateType }) => {
|
||||
// Template information for different types
|
||||
const templateInfo = {
|
||||
developer: {
|
||||
name: "Developer Portfolio",
|
||||
description: "A modern, responsive portfolio site with sections for projects, skills, and contact information. Perfect for developers to showcase their work.",
|
||||
features: ["Project showcase", "Skills section", "GitHub integration", "Contact form", "Blog ready"],
|
||||
image: "https://images.unsplash.com/photo-1498050108023-c5249f4df085?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2072&q=80"
|
||||
},
|
||||
designer: {
|
||||
name: "Designer Portfolio",
|
||||
description: "A visually stunning portfolio for designers with image galleries, case studies, and animations to showcase creative work.",
|
||||
features: ["Visual gallery", "Case studies", "Color scheme customization", "Smooth animations", "Design process showcase"],
|
||||
image: "https://images.unsplash.com/photo-1561070791-2526d30994b5?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2000&q=80"
|
||||
},
|
||||
photographer: {
|
||||
name: "Photographer Portfolio",
|
||||
description: "An elegant portfolio with fullscreen galleries, image zooming, and lightbox features designed for photographers to display their work.",
|
||||
features: ["Fullscreen galleries", "Image zoom", "Lightbox", "Category filtering", "Client proofing"],
|
||||
image: "https://images.unsplash.com/photo-1542038784456-1ea8e935640e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2070&q=80"
|
||||
},
|
||||
documentation: {
|
||||
name: "Documentation Site",
|
||||
description: "A comprehensive documentation site with search, code snippets, and versioning support for technical documentation.",
|
||||
features: ["Search functionality", "Code snippets with syntax highlighting", "Versioning", "Sidebar navigation", "Mobile-friendly"],
|
||||
image: "https://images.unsplash.com/photo-1456406644174-8ddd4cd52a06?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2068&q=80"
|
||||
},
|
||||
business: {
|
||||
name: "Single Page Business Site",
|
||||
description: "A professional one-page website for businesses with sections for services, testimonials, team members, and contact information.",
|
||||
features: ["Single page layout", "Services section", "Testimonials", "Team profiles", "Contact form with map"],
|
||||
image: "https://images.unsplash.com/photo-1560179707-f14e90ef3623?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2073&q=80"
|
||||
}
|
||||
};
|
||||
|
||||
const template = templateInfo[templateType] || templateInfo.developer;
|
||||
|
||||
return (
|
||||
<div className="mt-6 bg-neutral-800 rounded-lg border border-neutral-700 overflow-hidden">
|
||||
{/* Template preview image */}
|
||||
<div className="relative h-48 overflow-hidden">
|
||||
<img
|
||||
src={template.image}
|
||||
alt={`${template.name} Preview`}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/70 to-transparent flex items-end">
|
||||
<div className="p-4">
|
||||
<h3 className="text-xl font-semibold text-white">{template.name}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Template details */}
|
||||
<div className="p-5 space-y-4">
|
||||
<p className="text-neutral-300">{template.description}</p>
|
||||
|
||||
<div>
|
||||
<h4 className="text-white font-medium mb-2">Features:</h4>
|
||||
<ul className="grid grid-cols-1 sm:grid-cols-2 gap-2">
|
||||
{template.features.map((feature, index) => (
|
||||
<li key={index} className="text-neutral-400 flex items-center">
|
||||
<span className="mr-2 text-[#6d9e37]">✓</span>
|
||||
{feature}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="pt-2">
|
||||
<button className="px-4 py-2 bg-[#6d9e37] text-white rounded-md hover:bg-[#598035] transition-colors w-full">
|
||||
Select This Template
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
import React from 'react';
|
||||
|
||||
export const Toast = ({ visible, message, type = 'success' }) => {
|
||||
// Color scheme based on type
|
||||
const bgColor = type === 'error' ? 'bg-red-900' : 'bg-green-900';
|
||||
const icon = type === 'error' ? '✕' : '✓';
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`fixed bottom-5 right-5 p-3 ${bgColor} text-white rounded-md shadow-lg transform transition-all duration-300 z-50 ${
|
||||
visible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10 pointer-events-none'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-lg">{icon}</span>
|
||||
<span>{message}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
import * as React from "react";
|
||||
import { cn } from "../../lib/utils";
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
variant?: "default" | "outline";
|
||||
size?: "default" | "sm" | "lg";
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant = "default", size = "default", ...props }, ref) => {
|
||||
return (
|
||||
<button
|
||||
className={cn(
|
||||
"inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#6d9e37] focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-neutral-900",
|
||||
{
|
||||
"bg-[#6d9e37] text-white hover:bg-[#598035]": variant === "default",
|
||||
"border border-[#6d9e37] text-[#6d9e37] hover:bg-[#6d9e37] hover:text-white": variant === "outline",
|
||||
"h-10 py-2 px-4": size === "default",
|
||||
"h-9 px-3 rounded-md": size === "sm",
|
||||
"h-11 px-8 rounded-md": size === "lg",
|
||||
},
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
Button.displayName = "Button";
|
||||
|
||||
export { Button };
|
|
@ -0,0 +1,78 @@
|
|||
import * as React from 'react';
|
||||
import { cn } from "../../lib/utils";
|
||||
|
||||
const Card = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"rounded-lg border border-neutral-200 bg-white text-neutral-950 shadow-sm dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
Card.displayName = "Card";
|
||||
|
||||
const CardHeader = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
CardHeader.displayName = "CardHeader";
|
||||
|
||||
const CardTitle = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLHeadingElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<h3
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-2xl font-semibold leading-none tracking-tight",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
CardTitle.displayName = "CardTitle";
|
||||
|
||||
const CardDescription = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<p
|
||||
ref={ref}
|
||||
className={cn("text-sm text-neutral-500 dark:text-neutral-400", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
CardDescription.displayName = "CardDescription";
|
||||
|
||||
const CardContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
||||
));
|
||||
CardContent.displayName = "CardContent";
|
||||
|
||||
const CardFooter = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("flex items-center p-6 pt-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
CardFooter.displayName = "CardFooter";
|
||||
|
||||
export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter };
|
|
@ -0,0 +1,24 @@
|
|||
import * as React from "react";
|
||||
import { cn } from "../../lib/utils";
|
||||
|
||||
export interface InputProps
|
||||
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
({ className, type, ...props }, ref) => {
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"flex h-10 w-full rounded-md border border-neutral-600 bg-neutral-800 px-3 py-2 text-sm ring-offset-neutral-900 file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-neutral-400 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#6d9e37] focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
Input.displayName = "Input";
|
||||
|
||||
export { Input };
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from "react";
|
||||
import { cn } from "../../lib/utils";
|
||||
|
||||
export interface LabelProps
|
||||
extends React.LabelHTMLAttributes<HTMLLabelElement> {}
|
||||
|
||||
const Label = React.forwardRef<HTMLLabelElement, LabelProps>(
|
||||
({ className, ...props }, ref) => (
|
||||
<label
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
);
|
||||
Label.displayName = "Label";
|
||||
|
||||
export { Label };
|
|
@ -0,0 +1,25 @@
|
|||
import * as React from "react";
|
||||
import { cn } from "../../lib/utils";
|
||||
|
||||
export interface SelectProps
|
||||
extends React.SelectHTMLAttributes<HTMLSelectElement> {}
|
||||
|
||||
const Select = React.forwardRef<HTMLSelectElement, SelectProps>(
|
||||
({ className, children, ...props }, ref) => {
|
||||
return (
|
||||
<select
|
||||
className={cn(
|
||||
"flex h-10 w-full rounded-md border border-neutral-600 bg-neutral-800 px-3 py-2 text-sm ring-offset-neutral-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#6d9e37] focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</select>
|
||||
);
|
||||
}
|
||||
);
|
||||
Select.displayName = "Select";
|
||||
|
||||
export { Select };
|
|
@ -0,0 +1,23 @@
|
|||
import * as React from "react";
|
||||
import { cn } from "../../lib/utils";
|
||||
|
||||
export interface TextareaProps
|
||||
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
||||
|
||||
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
({ className, ...props }, ref) => {
|
||||
return (
|
||||
<textarea
|
||||
className={cn(
|
||||
"flex min-h-[120px] w-full rounded-md border border-neutral-600 bg-neutral-800 px-3 py-2 text-sm ring-offset-neutral-900 placeholder:text-neutral-400 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#6d9e37] focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
Textarea.displayName = "Textarea";
|
||||
|
||||
export { Textarea };
|
|
@ -0,0 +1,301 @@
|
|||
---
|
||||
import '../styles/global.css';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
description?: string;
|
||||
image?: string;
|
||||
canonicalURL?: string;
|
||||
type?: 'website' | 'article';
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
description = "SiliconPin offers high-performance hosting solutions for PHP, Node.js, Python, K8s, and K3s applications with 24/7 support.",
|
||||
image = "https://images.unsplash.com/photo-1551731409-43eb3e517a1a?q=80&w=2000&auto=format&fit=crop",
|
||||
canonicalURL = new URL(Astro.url.pathname, Astro.site).href,
|
||||
type = "website",
|
||||
} = Astro.props;
|
||||
|
||||
// Organization schema
|
||||
const organizationSchema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Organization",
|
||||
"name": "SiliconPin",
|
||||
"url": "https://siliconpin.com",
|
||||
"logo": "https://siliconpin.com/assets/logo.svg",
|
||||
"contactPoint": {
|
||||
"@type": "ContactPoint",
|
||||
"telephone": "+91-700-160-1485",
|
||||
"contactType": "customer service",
|
||||
"availableLanguage": ["English"]
|
||||
},
|
||||
"address": {
|
||||
"@type": "PostalAddress",
|
||||
"streetAddress": "121 Lalbari, GourBongo Road",
|
||||
"addressLocality": "Habra",
|
||||
"addressRegion": "W.B.",
|
||||
"postalCode": "743271",
|
||||
"addressCountry": "India"
|
||||
},
|
||||
"sameAs": [
|
||||
"https://www.linkedin.com/company/siliconpin",
|
||||
"https://x.com/dwd_consultancy",
|
||||
"https://www.facebook.com/profile.php?id=100088549643337",
|
||||
"https://instagram.com/siliconpin.com_"
|
||||
]
|
||||
};
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Basic Meta Tags -->
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
|
||||
<!-- SEO Meta Tags -->
|
||||
<title>{title}</title>
|
||||
<meta name="description" content={description} />
|
||||
<meta name="keywords" content="hosting, PHP hosting, Node.js hosting, Python hosting, Kubernetes, K8s, K3s, cloud services, web hosting, application hosting, server hosting, India hosting" />
|
||||
<meta name="author" content="SiliconPin" />
|
||||
<link rel="canonical" href={canonicalURL} />
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content={type} />
|
||||
<meta property="og:url" content={canonicalURL} />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:image" content={image} />
|
||||
<meta property="og:site_name" content="SiliconPin" />
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
<meta property="twitter:url" content={canonicalURL} />
|
||||
<meta property="twitter:title" content={title} />
|
||||
<meta property="twitter:description" content={description} />
|
||||
<meta property="twitter:image" content={image} />
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/svg+xml" href="https://siliconpin.com/assets/logo.svg" />
|
||||
<link rel="apple-touch-icon" href="https://siliconpin.com/assets/logo.svg" />
|
||||
|
||||
<!-- Structured Data -->
|
||||
<script type="application/ld+json" set:html={JSON.stringify(organizationSchema)}></script>
|
||||
</head>
|
||||
<body class="min-h-screen flex flex-col">
|
||||
<!-- Top header - visible on all devices -->
|
||||
<header class="py-3 sm:py-4 px-4 sm:px-6 border-b border-neutral-700" style="background-color: #262626;">
|
||||
<div class="container mx-auto flex justify-between items-center">
|
||||
<a href="/" class="flex items-center gap-2" aria-label="SiliconPin Home">
|
||||
<img src="https://siliconpin.com/assets/logo.svg" alt="SiliconPin Logo" class="w-6 h-6 sm:w-8 sm:h-8" />
|
||||
<span class="text-lg sm:text-xl font-bold text-[#6d9e37]">SiliconPin</span>
|
||||
</a>
|
||||
<!-- Desktop navigation -->
|
||||
<nav class="hidden md:flex items-center gap-6" aria-label="Main Navigation">
|
||||
<a href="/" class="hover:text-[#6d9e37] transition-colors">Home</a>
|
||||
<a href="/services" class="hover:text-[#6d9e37] transition-colors">Services</a>
|
||||
<a href="/contact" class="hover:text-[#6d9e37] transition-colors">Contact</a>
|
||||
<a
|
||||
href="/get-started"
|
||||
class="inline-flex items-center justify-center rounded-md bg-[#6d9e37] px-4 py-2 text-sm font-medium text-white hover:bg-[#598035] transition-colors"
|
||||
>
|
||||
Get Started
|
||||
</a>
|
||||
</nav>
|
||||
<!-- Mobile menu button -->
|
||||
<div class="md:hidden relative">
|
||||
<button id="mobileMenuBtn" class="text-[#c7ccd5] p-1 hover:text-white" aria-label="Toggle Menu">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="4" y1="12" x2="20" y2="12"></line><line x1="4" y1="6" x2="20" y2="6"></line><line x1="4" y1="18" x2="20" y2="18"></line></svg>
|
||||
</button>
|
||||
|
||||
<!-- Mobile dropdown menu -->
|
||||
<div id="mobileMenu" class="absolute right-0 mt-2 w-48 bg-neutral-800 rounded-md shadow-lg py-1 z-50 hidden border border-neutral-700">
|
||||
<a href="/" class="block px-4 py-2 text-sm text-white hover:bg-neutral-700">Home</a>
|
||||
<a href="/services" class="block px-4 py-2 text-sm text-white hover:bg-neutral-700">Services</a>
|
||||
<a href="/contact" class="block px-4 py-2 text-sm text-white hover:bg-neutral-700">Contact</a>
|
||||
<a href="/about-us" class="block px-4 py-2 text-sm text-white hover:bg-neutral-700">About Us</a>
|
||||
<a href="/get-started" class="block px-4 py-2 text-sm text-white hover:bg-neutral-700 font-medium text-[#6d9e37]">Get Started</a>
|
||||
<a href="/suggestion-or-report" class="block px-4 py-2 text-sm text-white hover:bg-neutral-700">Suggestion or Report</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="flex-grow pb-16 md:pb-0">
|
||||
<slot />
|
||||
</main>
|
||||
|
||||
<footer class="border-t border-neutral-700 mt-8 sm:mt-12 md:mb-0 mb-16">
|
||||
<!-- Copyright and social links section with #262626 background -->
|
||||
<div class="py-6 sm:py-8 px-4 sm:px-6" style="background-color: #262626;">
|
||||
<div class="container mx-auto">
|
||||
<div class="flex flex-col sm:flex-row justify-between items-center gap-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<img src="https://siliconpin.com/assets/logo.svg" alt="SiliconPin Logo" class="w-7 h-7 sm:w-8 sm:h-8" />
|
||||
<span class="text-sm sm:text-base">© {new Date().getFullYear()} SiliconPin. All rights reserved.</span>
|
||||
</div>
|
||||
|
||||
<div class="hidden sm:block">
|
||||
<a href="/suggestion-or-report" class="text-[#6d9e37] hover:text-white transition-colors">
|
||||
Suggestion or Report
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-5 mt-4 sm:mt-0">
|
||||
<a href="https://www.linkedin.com/company/siliconpin" aria-label="LinkedIn" class="text-[#6d9e37] hover:text-white transition-colors" target="_blank" rel="noopener">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path><rect x="2" y="9" width="4" height="12"></rect><circle cx="4" cy="4" r="2"></circle></svg>
|
||||
</a>
|
||||
<a href="https://x.com/dwd_consultancy?t=MBvjcclvVgCPdIHspV9HWQ&s=09" aria-label="X (Twitter)" class="text-[#6d9e37] hover:text-white transition-colors" target="_blank" rel="noopener">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M4 4l11.733 16h4.267l-11.733 -16z"></path>
|
||||
<path d="M4 20l6.768 -6.768m2.46 -2.46l6.772 -6.772"></path>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="https://www.facebook.com/profile.php?id=100088549643337&mibextid=ZbWKwL" aria-label="Facebook" class="text-[#6d9e37] hover:text-white transition-colors" target="_blank" rel="noopener">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"></path></svg>
|
||||
</a>
|
||||
<a href="https://instagram.com/siliconpin.com_?igshid=OGQ5ZDc2ODk2ZA==" aria-label="Instagram" class="text-[#6d9e37] hover:text-white transition-colors" target="_blank" rel="noopener">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect><path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path><line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line></svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer links section with main background -->
|
||||
<div class="py-10 px-4 sm:px-6">
|
||||
<div class="container mx-auto">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
<!-- Services column - Card Style -->
|
||||
<div class="bg-neutral-800 p-5 rounded-lg border border-neutral-700 shadow-lg">
|
||||
<h3 class="font-medium text-lg text-white mb-4 pb-2 border-b border-neutral-700">Services</h3>
|
||||
<ul class="space-y-2 text-neutral-400">
|
||||
<li><a href="/services" class="hover:text-[#6d9e37] transition-colors">All Services</a></li>
|
||||
<li><a href="/get-started" class="hover:text-[#6d9e37] transition-colors">Get Started</a></li>
|
||||
<li><a href="/services/hire-developer" class="hover:text-[#6d9e37] transition-colors">Hire a Human Developer</a></li>
|
||||
<li><a href="/services/hire-ai-agent" class="hover:text-[#6d9e37] transition-colors">Hire an AI Agent</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Company column - Card Style -->
|
||||
<div class="bg-neutral-800 p-5 rounded-lg border border-neutral-700 shadow-lg">
|
||||
<h3 class="font-medium text-lg text-white mb-4 pb-2 border-b border-neutral-700">Company</h3>
|
||||
<ul class="space-y-2 text-neutral-400">
|
||||
<li><a href="/about-us" class="hover:text-[#6d9e37] transition-colors">About Us</a></li>
|
||||
<li><a href="/contact" class="hover:text-[#6d9e37] transition-colors">Contact</a></li>
|
||||
<li><a href="/careers" class="hover:text-[#6d9e37] transition-colors">Careers</a></li>
|
||||
<li><a href="/partners" class="hover:text-[#6d9e37] transition-colors">Partners</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Legal column - Card Style -->
|
||||
<div class="bg-neutral-800 p-5 rounded-lg border border-neutral-700 shadow-lg">
|
||||
<h3 class="font-medium text-lg text-white mb-4 pb-2 border-b border-neutral-700">Legal</h3>
|
||||
<ul class="space-y-2 text-neutral-400">
|
||||
<li><a href="/privacy-policy" class="hover:text-[#6d9e37] transition-colors">Privacy Policy</a></li>
|
||||
<li><a href="/terms-and-conditions" class="hover:text-[#6d9e37] transition-colors">Terms & Conditions</a></li>
|
||||
<li><a href="/refund-policy" class="hover:text-[#6d9e37] transition-colors">Refund Policy</a></li>
|
||||
<li><a href="/legal-agreement" class="hover:text-[#6d9e37] transition-colors">Legal Agreement</a></li>
|
||||
<li><a href="/suggestion-or-report" class="hover:text-[#6d9e37] transition-colors">Suggestion or Report</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Contact column - Card Style -->
|
||||
<div class="bg-neutral-800 p-5 rounded-lg border border-neutral-700 shadow-lg">
|
||||
<h3 class="font-medium text-lg text-white mb-4 pb-2 border-b border-neutral-700">Contact Us</h3>
|
||||
<address class="not-italic space-y-2 text-neutral-400">
|
||||
<p>121 Lalbari, GourBongo Road</p>
|
||||
<p>Habra, W.B. 743271, India</p>
|
||||
<p>Phone: <a href="tel:+917001601485" class="text-[#6d9e37] hover:underline">+91-700-160-1485</a></p>
|
||||
<p>Email: <a href="mailto:contact@siliconpin.com" class="text-[#6d9e37] hover:underline">contact@siliconpin.com</a></p>
|
||||
</address>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Mobile bottom navigation - positioned last in the DOM -->
|
||||
<nav class="fixed bottom-0 left-0 right-0 md:hidden bg-[#262626] border-t border-neutral-700 shadow-lg z-50">
|
||||
<div class="flex justify-around items-center h-16">
|
||||
<a href="/" class="flex flex-col items-center justify-center w-full h-full text-[#6d9e37] hover:text-white transition-colors">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg>
|
||||
<span class="text-xs mt-1">Home</span>
|
||||
</a>
|
||||
<a href="/services" class="flex flex-col items-center justify-center w-full h-full text-[#6d9e37] hover:text-white transition-colors">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
|
||||
<span class="text-xs mt-1">Services</span>
|
||||
</a>
|
||||
<a href="/get-started" class="flex flex-col items-center justify-center w-full h-full text-[#6d9e37] hover:text-white transition-colors">
|
||||
<div class="w-10 h-10 rounded-full bg-[#6d9e37] flex items-center justify-center -mt-5 shadow-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
|
||||
</div>
|
||||
<span class="text-xs mt-1">Start</span>
|
||||
</a>
|
||||
<a href="/about-us" class="flex flex-col items-center justify-center w-full h-full text-[#6d9e37] hover:text-white transition-colors">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><circle cx="12" cy="10" r="3"></circle><path d="M7 20.662V19c0-1.18.822-2.2 2-2.5a5.5 5.5 0 0 1 6 0c1.178.3 2 1.323 2 2.5v1.662"></path></svg>
|
||||
<span class="text-xs mt-1">About</span>
|
||||
</a>
|
||||
<a href="/contact" class="flex flex-col items-center justify-center w-full h-full text-[#6d9e37] hover:text-white transition-colors">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path><polyline points="22,6 12,13 2,6"></polyline></svg>
|
||||
<span class="text-xs mt-1">Contact</span>
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<script>
|
||||
// Mobile menu toggle functionality
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const menuBtn = document.getElementById('mobileMenuBtn');
|
||||
const mobileMenu = document.getElementById('mobileMenu');
|
||||
|
||||
if (menuBtn && mobileMenu) {
|
||||
menuBtn.addEventListener('click', function() {
|
||||
mobileMenu.classList.toggle('hidden');
|
||||
});
|
||||
|
||||
// Close menu when clicking outside
|
||||
document.addEventListener('click', function(event) {
|
||||
if (!menuBtn.contains(event.target) && !mobileMenu.contains(event.target)) {
|
||||
mobileMenu.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style is:global>
|
||||
/* Custom scroll bar */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: #2b323b;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #6d9e37;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #598035;
|
||||
}
|
||||
|
||||
/* Fix mobile viewport height issues */
|
||||
html, body {
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
body {
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,6 @@
|
|||
import { clsx, type ClassValue } from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
|
||||
// Page-specific SEO metadata
|
||||
const pageTitle = "About Us | SiliconPin";
|
||||
const pageDescription = "Learn more about SiliconPin, our mission, values, and the team behind our high-performance hosting solutions.";
|
||||
const pageImage = "https://images.unsplash.com/photo-1551731409-43eb3e517a1a?q=80&w=2000&auto=format&fit=crop";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={pageTitle}
|
||||
description={pageDescription}
|
||||
image={pageImage}
|
||||
type="website"
|
||||
>
|
||||
<main class="container mx-auto px-4 sm:px-6 py-8 sm:py-12">
|
||||
<div class="text-center mb-8 sm:mb-12">
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-[#6d9e37] mb-3 sm:mb-4">About SiliconPin</h1>
|
||||
<p class="text-lg sm:text-xl max-w-3xl mx-auto text-neutral-300">
|
||||
Empowering businesses with reliable, high-performance hosting solutions
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="max-w-4xl mx-auto space-y-12">
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">Our Story</h2>
|
||||
<p class="text-neutral-300 mb-4">
|
||||
SiliconPin was founded in 2021 with a clear mission: to provide businesses of all sizes with reliable, high-performance hosting solutions that enable growth and innovation. What started as a small team of passionate developers and system administrators has grown into a trusted hosting provider serving clients across various industries.
|
||||
</p>
|
||||
<p class="text-neutral-300">
|
||||
Based in Habra, West Bengal, India, our team combines technical expertise with a deep understanding of business needs to deliver hosting solutions that are not just technically sound but also aligned with our clients' business objectives.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">Our Mission</h2>
|
||||
<p class="text-neutral-300">
|
||||
At SiliconPin, our mission is to empower businesses through technology by providing reliable, secure, and scalable hosting solutions. We believe that technology should enable businesses to focus on what they do best, without worrying about infrastructure management or technical complexities.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">Our Values</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<h3 class="text-xl font-medium text-[#6d9e37] mb-2">Reliability</h3>
|
||||
<p class="text-neutral-300">
|
||||
We understand that downtime means lost business. That's why we prioritize reliability in everything we do, from our infrastructure to our customer service.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-xl font-medium text-[#6d9e37] mb-2">Security</h3>
|
||||
<p class="text-neutral-300">
|
||||
In an increasingly digital world, security is paramount. We implement robust security measures to protect our clients' data and applications.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-xl font-medium text-[#6d9e37] mb-2">Innovation</h3>
|
||||
<p class="text-neutral-300">
|
||||
We continuously explore new technologies and methodologies to improve our services and provide our clients with cutting-edge solutions.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-xl font-medium text-[#6d9e37] mb-2">Customer Focus</h3>
|
||||
<p class="text-neutral-300">
|
||||
Our clients' success is our success. We work closely with our clients to understand their needs and provide tailored solutions that help them achieve their goals.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">Why Choose SiliconPin?</h2>
|
||||
<ul class="list-disc list-inside space-y-3 text-neutral-300">
|
||||
<li>24/7 expert technical support</li>
|
||||
<li>99.9% uptime guarantee</li>
|
||||
<li>Scalable infrastructure to grow with your business</li>
|
||||
<li>Comprehensive security measures including DDoS protection and SSL certificates</li>
|
||||
<li>Expertise across various technologies including PHP, Node.js, Python, and Kubernetes</li>
|
||||
<li>Commitment to customer success through personalized service</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<div class="text-center">
|
||||
<a
|
||||
href="/contact"
|
||||
class="inline-flex items-center justify-center rounded-md bg-[#6d9e37] px-6 py-3 text-base font-medium text-white hover:bg-[#598035] transition-colors"
|
||||
>
|
||||
Get in Touch
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
|
@ -0,0 +1,144 @@
|
|||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
import { ContactForm } from '../components/ContactForm';
|
||||
|
||||
// Page-specific SEO metadata
|
||||
const pageTitle = "Contact Us | SiliconPin";
|
||||
const pageDescription = "Contact SiliconPin for reliable hosting solutions. Our team is available 24/7 to help with your PHP, Node.js, Python, Kubernetes, and K3s hosting needs.";
|
||||
const pageImage = "https://images.unsplash.com/photo-1551731409-43eb3e517a1a?q=80&w=2000&auto=format&fit=crop";
|
||||
|
||||
// Contact schema for structured data
|
||||
const contactSchema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "ContactPage",
|
||||
"name": "SiliconPin Contact Page",
|
||||
"description": "Contact SiliconPin for reliable hosting solutions",
|
||||
"url": "https://siliconpin.com/contact",
|
||||
"mainEntityOfPage": {
|
||||
"@type": "Organization",
|
||||
"name": "SiliconPin",
|
||||
"telephone": "+91-700-160-1485",
|
||||
"email": "contact@siliconpin.com",
|
||||
"address": {
|
||||
"@type": "PostalAddress",
|
||||
"streetAddress": "121 Lalbari, GourBongo Road",
|
||||
"addressLocality": "Habra",
|
||||
"addressRegion": "W.B.",
|
||||
"postalCode": "743271",
|
||||
"addressCountry": "India"
|
||||
},
|
||||
"openingHoursSpecification": [
|
||||
{
|
||||
"@type": "OpeningHoursSpecification",
|
||||
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
||||
"opens": "09:00",
|
||||
"closes": "18:00"
|
||||
},
|
||||
{
|
||||
"@type": "OpeningHoursSpecification",
|
||||
"dayOfWeek": "Saturday",
|
||||
"opens": "10:00",
|
||||
"closes": "16:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={pageTitle}
|
||||
description={pageDescription}
|
||||
image={pageImage}
|
||||
type="website"
|
||||
>
|
||||
<script type="application/ld+json" set:html={JSON.stringify(contactSchema)}></script>
|
||||
|
||||
<main class="container mx-auto px-4 sm:px-6 py-8 sm:py-12">
|
||||
<div class="text-center mb-8 sm:mb-12">
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-[#6d9e37] mb-3 sm:mb-4">Contact Us</h1>
|
||||
<p class="text-lg sm:text-xl max-w-3xl mx-auto text-neutral-300">
|
||||
Have questions about our hosting services? Get in touch with our team of experts.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Full width contact form section -->
|
||||
<section aria-labelledby="contact-form-heading" class="mb-8 sm:mb-12 bg-neutral-800 rounded-lg p-4 sm:p-6 lg:p-8 border border-neutral-700">
|
||||
<h2 id="contact-form-heading" class="text-xl sm:text-2xl font-bold text-white mb-4 sm:mb-6">Send us a message</h2>
|
||||
<ContactForm client:load />
|
||||
</section>
|
||||
|
||||
<!-- Information sections in a grid -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 sm:gap-8">
|
||||
<section aria-labelledby="company-info-heading" class="bg-neutral-800 rounded-lg p-4 sm:p-6 lg:p-8 border border-neutral-700">
|
||||
<h2 id="company-info-heading" class="text-xl sm:text-2xl font-bold text-white mb-4 sm:mb-6">Our Information</h2>
|
||||
|
||||
<div class="space-y-4 sm:space-y-6">
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0 h-10 w-10 rounded-full bg-[#6d9e37]/20 flex items-center justify-center mr-4" aria-hidden="true">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-[#6d9e37]" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-medium text-white">Email</h3>
|
||||
<a href="mailto:contact@siliconpin.com" class="mt-1 text-neutral-300 break-words hover:text-[#6d9e37] transition-colors">contact@siliconpin.com</a>
|
||||
<a href="mailto:support@siliconpin.com" class="mt-1 text-neutral-300 break-words hover:text-[#6d9e37] transition-colors block">support@siliconpin.com</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0 h-10 w-10 rounded-full bg-[#6d9e37]/20 flex items-center justify-center mr-4" aria-hidden="true">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-[#6d9e37]" 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" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-medium text-white">Phone</h3>
|
||||
<a href="tel:+917001601485" class="mt-1 text-neutral-300 hover:text-[#6d9e37] transition-colors">+91-700-160-1485</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0 h-10 w-10 rounded-full bg-[#6d9e37]/20 flex items-center justify-center mr-4" aria-hidden="true">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-[#6d9e37]" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-medium text-white">Address</h3>
|
||||
<address class="mt-1 text-neutral-300 not-italic">
|
||||
121 Lalbari, GourBongo Road<br/>
|
||||
Habra, W.B. 743271<br/>
|
||||
India
|
||||
</address>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section aria-labelledby="business-hours-heading" class="bg-neutral-800 rounded-lg p-4 sm:p-6 lg:p-8 border border-neutral-700">
|
||||
<h2 id="business-hours-heading" class="text-xl sm:text-2xl font-bold text-white mb-4 sm:mb-6">Business Hours</h2>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div class="flex flex-col sm:flex-row sm:justify-between">
|
||||
<span class="text-neutral-300 font-medium">Monday - Friday:</span>
|
||||
<time datetime="09:00-18:00" class="text-white">9:00 AM - 6:00 PM</time>
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row sm:justify-between">
|
||||
<span class="text-neutral-300 font-medium">Saturday:</span>
|
||||
<time datetime="10:00-16:00" class="text-white">10:00 AM - 4:00 PM</time>
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row sm:justify-between">
|
||||
<span class="text-neutral-300 font-medium">Sunday:</span>
|
||||
<span class="text-white">Closed</span>
|
||||
</div>
|
||||
<div class="pt-3 border-t border-neutral-700">
|
||||
<span class="text-neutral-300">Technical Support:</span>
|
||||
<span class="text-[#6d9e37] font-semibold block mt-1">24/7</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
|
@ -0,0 +1,389 @@
|
|||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
|
||||
// Page-specific SEO metadata
|
||||
const pageTitle = "Get Started | SiliconPin";
|
||||
const pageDescription = "Start your project with SiliconPin's hosting services. Deploy a web app, from source code, or upload a static site.";
|
||||
const pageImage = "https://images.unsplash.com/photo-1551731409-43eb3e517a1a?q=80&w=2000&auto=format&fit=crop";
|
||||
|
||||
// Generate a random subdomain
|
||||
const randomString = () => {
|
||||
return Math.random().toString(36).substring(2, 10);
|
||||
};
|
||||
const defaultSubdomain = randomString();
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={pageTitle}
|
||||
description={pageDescription}
|
||||
image={pageImage}
|
||||
type="website"
|
||||
>
|
||||
<main class="container mx-auto px-4 sm:px-6 py-8 sm:py-12">
|
||||
<div class="text-center mb-8 sm:mb-12">
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-[#6d9e37] mb-3 sm:mb-4">Get Started</h1>
|
||||
<p class="text-lg sm:text-xl max-w-3xl mx-auto text-neutral-300">
|
||||
Launch your project with SiliconPin's high-performance hosting services
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="max-w-3xl mx-auto bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<form id="deployment-form" class="space-y-6" action="/api/register-new-service" method="POST">
|
||||
<div class="space-y-2">
|
||||
<label for="deployment-type" class="block text-white font-medium">Deployment Type</label>
|
||||
<select id="deployment-type" name="deployment_type" class="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]">
|
||||
<option value="app" selected>💻 Deploy an App</option>
|
||||
<option value="source">⚙️ From Source</option>
|
||||
<option value="static">📄 Static Site Upload</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="app-options" class="space-y-2">
|
||||
<label for="app-type" class="block text-white font-medium">Select Application</label>
|
||||
<select id="app-type" name="app_type" class="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]">
|
||||
<option value="wordpress">🔌 WordPress</option>
|
||||
<option value="prestashop">🛒 PrestaShop</option>
|
||||
<option value="laravel">🚀 Laravel</option>
|
||||
<option value="cakephp">🍰 CakePHP</option>
|
||||
<option value="symfony">🎯 Symfony</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="source-options" class="space-y-2 hidden">
|
||||
<label for="source-type" class="block text-white font-medium">Source Type</label>
|
||||
<select id="source-type" name="source_type" class="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]">
|
||||
<option value="public">🌐 Public Repository</option>
|
||||
<option value="private">🔒 Private Repository</option>
|
||||
</select>
|
||||
|
||||
<div class="pt-4">
|
||||
<label for="repo-url" class="block text-white font-medium mb-2">Repository URL</label>
|
||||
<input
|
||||
type="text"
|
||||
id="repo-url"
|
||||
name="repo_url"
|
||||
placeholder="https://github.com/username/repository"
|
||||
class="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="deployment-key-section" class="pt-4 hidden">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<label for="deployment-key" class="block text-white font-medium">Deployment Key</label>
|
||||
<button id="help-button" type="button" class="text-neutral-400 hover:text-white focus:outline-none" aria-label="Deployment Key Information">
|
||||
<span class="text-lg">❓</span>
|
||||
</button>
|
||||
</div>
|
||||
<textarea
|
||||
id="deployment-key"
|
||||
name="deployment_key"
|
||||
placeholder="Paste your SSH private key here"
|
||||
rows="6"
|
||||
class="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37] font-mono text-sm"
|
||||
></textarea>
|
||||
<p class="mt-1 text-sm text-neutral-400">Your private key is used only for deploying and is never stored on our servers.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="static-options" class="space-y-2 hidden">
|
||||
<div class="p-4 bg-neutral-700/50 rounded-md text-neutral-300 text-center">
|
||||
Upload the zip file containing your static website
|
||||
</div>
|
||||
|
||||
<div class="pt-2">
|
||||
<label for="file-upload" class="block text-white font-medium mb-2">Upload File (ZIP/TAR)</label>
|
||||
<div class="flex items-center justify-center w-full">
|
||||
<label for="file-upload" class="flex flex-col items-center justify-center w-full h-32 border-2 border-dashed rounded-lg cursor-pointer border-neutral-600 hover:border-[#6d9e37]">
|
||||
<div class="flex flex-col items-center justify-center pt-5 pb-6">
|
||||
<span class="text-3xl mb-3 text-neutral-400">📁</span>
|
||||
<p class="mb-2 text-sm text-neutral-400"><span class="font-semibold">Click to upload</span> or drag and drop</p>
|
||||
<p class="text-xs text-neutral-500">ZIP or TAR files only (max. 100MB)</p>
|
||||
</div>
|
||||
<input id="file-upload" name="file_upload" type="file" class="hidden" accept=".zip,.tar" />
|
||||
</label>
|
||||
</div>
|
||||
<div id="file-name" class="mt-2 text-sm text-neutral-400"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Domain Selection -->
|
||||
<div class="pt-4 border-t border-neutral-700">
|
||||
<h3 class="text-lg font-medium text-white mb-4">Destination</h3>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-start gap-2">
|
||||
<input
|
||||
type="radio"
|
||||
id="use-subdomain"
|
||||
name="domain_type"
|
||||
value="subdomain"
|
||||
class="mt-1"
|
||||
checked
|
||||
/>
|
||||
<div class="flex-1">
|
||||
<label for="use-subdomain" class="block text-white font-medium">Use SiliconPin Subdomain</label>
|
||||
<div class="mt-2 flex">
|
||||
<input
|
||||
type="text"
|
||||
id="subdomain"
|
||||
name="subdomain"
|
||||
value={defaultSubdomain}
|
||||
class="rounded-l-md py-2 px-3 bg-neutral-600 border-y border-l border-neutral-600 text-neutral-300 focus:outline-none w-1/3 font-mono"
|
||||
readonly
|
||||
/>
|
||||
<span class="rounded-r-md py-2 px-3 bg-neutral-800 border border-neutral-700 text-neutral-400 w-2/3">.subdomain.siliconpin.com</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-start gap-2">
|
||||
<input
|
||||
type="radio"
|
||||
id="use-custom-domain"
|
||||
name="domain_type"
|
||||
value="custom"
|
||||
class="mt-1"
|
||||
/>
|
||||
<div class="flex-1">
|
||||
<label for="use-custom-domain" class="block text-white font-medium">Use Custom Domain</label>
|
||||
<input
|
||||
type="text"
|
||||
id="custom-domain"
|
||||
name="custom_domain"
|
||||
placeholder="yourdomain.com"
|
||||
class="mt-2 w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-start gap-2">
|
||||
<input
|
||||
type="radio"
|
||||
id="use-ip"
|
||||
name="domain_type"
|
||||
value="ip"
|
||||
class="mt-1"
|
||||
/>
|
||||
<div class="flex-1">
|
||||
<label for="use-ip" class="block text-white font-medium">Use IP Address</label>
|
||||
<input
|
||||
type="text"
|
||||
id="ip-address"
|
||||
name="ip_address"
|
||||
placeholder="123.45.67.89"
|
||||
class="mt-2 w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||
disabled
|
||||
/>
|
||||
<p class="mt-1 text-xs text-neutral-400">Note: You'll need to configure DNS settings separately if using IP address.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pt-4 flex justify-center">
|
||||
<p class="text-neutral-300">
|
||||
Try our new <a href="/get-started-new" class="text-[#6d9e37] hover:underline">React-based setup wizard</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full mt-6 px-6 py-3 bg-[#6d9e37] text-white font-medium rounded-md hover:bg-[#598035] transition-colors focus:outline-none focus:ring-2 focus:ring-[#6d9e37] focus:ring-offset-2 focus:ring-offset-neutral-800"
|
||||
>
|
||||
Continue to Destination
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Help Modal -->
|
||||
<div id="help-modal" class="fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center hidden">
|
||||
<div class="bg-neutral-800 rounded-lg max-w-2xl mx-4 w-full max-h-[80vh] overflow-auto border border-neutral-700 shadow-xl">
|
||||
<div class="sticky top-0 bg-neutral-800 p-4 border-b border-neutral-700 flex justify-between items-center">
|
||||
<h3 class="text-lg font-medium text-white">Deployment Key Information</h3>
|
||||
<button id="close-modal" type="button" class="text-neutral-400 hover:text-white">
|
||||
<span class="text-xl">✖️</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="p-6 markdown-content">
|
||||
<h2 class="text-xl font-bold text-white mb-4">What is a Deployment Key?</h2>
|
||||
<p class="text-neutral-300 mb-4">A <strong>deployment key</strong> is a type of authentication key used to grant secure, read-only or read-write access to a repository, server, or service without requiring user credentials. It is commonly used in automation and deployment pipelines.</p>
|
||||
|
||||
<h3 class="text-lg font-semibold text-white mb-2 mt-6">Common Uses of Deployment Keys</h3>
|
||||
<ol class="list-decimal list-inside space-y-2 text-neutral-300 mb-4">
|
||||
<li><strong>Git Repositories (e.g., GitHub, GitLab, Bitbucket)</strong>
|
||||
<ul class="list-disc list-inside ml-6 mt-1 text-neutral-400">
|
||||
<li>Deployment keys allow servers to pull from private repositories without using a personal access token or SSH agent.</li>
|
||||
<li>Example: Deploying a website from a private GitHub repo to a production server.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>CI/CD Pipelines</strong>
|
||||
<ul class="list-disc list-inside ml-6 mt-1 text-neutral-400">
|
||||
<li>Used in continuous integration/deployment workflows to securely access resources.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>Cloud Services & Servers</strong>
|
||||
<ul class="list-disc list-inside ml-6 mt-1 text-neutral-400">
|
||||
<li>Some cloud platforms require deployment keys for accessing private assets or environments.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<h3 class="text-lg font-semibold text-white mb-2 mt-6">How Deployment Keys Work</h3>
|
||||
<ul class="list-disc list-inside space-y-2 text-neutral-300 mb-4">
|
||||
<li>Typically an <strong>SSH key pair</strong> (public & private).</li>
|
||||
<li>The <strong>public key</strong> is added to the remote repository or service.</li>
|
||||
<li>The <strong>private key</strong> is stored securely on the deployment server.</li>
|
||||
</ul>
|
||||
|
||||
<h3 class="text-lg font-semibold text-white mb-2 mt-6">Example: Adding a Deployment Key to GitHub</h3>
|
||||
<ol class="list-decimal list-inside space-y-2 text-neutral-300 mb-4">
|
||||
<li>Generate an SSH key:
|
||||
<pre class="bg-neutral-900 p-3 rounded mt-2 overflow-x-auto text-sm font-mono text-neutral-300">ssh-keygen -t rsa -b 4096 -C "deployment-key" -f deploy_key</pre>
|
||||
</li>
|
||||
<li>Add the <strong>public key</strong> (<code class="bg-neutral-900 px-1 py-0.5 rounded text-xs">deploy_key.pub</code>) to GitHub under <strong>Settings → Deploy Keys</strong>.</li>
|
||||
<li>Use the <strong>private key</strong> (<code class="bg-neutral-900 px-1 py-0.5 rounded text-xs">deploy_key</code>) on your server to authenticate Git operations.</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Get DOM elements
|
||||
const deploymentType = document.getElementById('deployment-type');
|
||||
const appOptions = document.getElementById('app-options');
|
||||
const sourceOptions = document.getElementById('source-options');
|
||||
const staticOptions = document.getElementById('static-options');
|
||||
const fileUpload = document.getElementById('file-upload');
|
||||
const fileName = document.getElementById('file-name');
|
||||
const sourceType = document.getElementById('source-type');
|
||||
const deploymentKeySection = document.getElementById('deployment-key-section');
|
||||
const helpButton = document.getElementById('help-button');
|
||||
const helpModal = document.getElementById('help-modal');
|
||||
const closeModal = document.getElementById('close-modal');
|
||||
|
||||
// Domain selection elements
|
||||
const useSubdomain = document.getElementById('use-subdomain');
|
||||
const useCustomDomain = document.getElementById('use-custom-domain');
|
||||
const useIp = document.getElementById('use-ip');
|
||||
const customDomain = document.getElementById('custom-domain');
|
||||
const ipAddress = document.getElementById('ip-address');
|
||||
|
||||
// Function to show/hide options based on selection
|
||||
function updateOptions() {
|
||||
const selectedValue = deploymentType.value;
|
||||
|
||||
// Hide all options first
|
||||
appOptions.classList.add('hidden');
|
||||
sourceOptions.classList.add('hidden');
|
||||
staticOptions.classList.add('hidden');
|
||||
|
||||
// Show selected option
|
||||
if (selectedValue === 'app') {
|
||||
appOptions.classList.remove('hidden');
|
||||
} else if (selectedValue === 'source') {
|
||||
sourceOptions.classList.remove('hidden');
|
||||
updateSourceOptions(); // Update source options based on source type
|
||||
} else if (selectedValue === 'static') {
|
||||
staticOptions.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
// Function to update source options based on source type
|
||||
function updateSourceOptions() {
|
||||
const selectedSourceType = sourceType.value;
|
||||
|
||||
if (selectedSourceType === 'private') {
|
||||
deploymentKeySection.classList.remove('hidden');
|
||||
} else {
|
||||
deploymentKeySection.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
// Function to handle domain type selection
|
||||
function updateDomainFields() {
|
||||
// Disable all input fields first
|
||||
customDomain.disabled = true;
|
||||
ipAddress.disabled = true;
|
||||
|
||||
// Enable the selected option
|
||||
if (useCustomDomain.checked) {
|
||||
customDomain.disabled = false;
|
||||
} else if (useIp.checked) {
|
||||
ipAddress.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle deployment type change
|
||||
deploymentType.addEventListener('change', updateOptions);
|
||||
|
||||
// Handle source type change
|
||||
sourceType.addEventListener('change', updateSourceOptions);
|
||||
|
||||
// Handle file upload
|
||||
fileUpload.addEventListener('change', function(e) {
|
||||
if (e.target.files.length > 0) {
|
||||
fileName.textContent = `Selected file: ${e.target.files[0].name}`;
|
||||
} else {
|
||||
fileName.textContent = '';
|
||||
}
|
||||
});
|
||||
|
||||
// Handle domain type selection
|
||||
useSubdomain.addEventListener('change', updateDomainFields);
|
||||
useCustomDomain.addEventListener('change', updateDomainFields);
|
||||
useIp.addEventListener('change', updateDomainFields);
|
||||
|
||||
// Handle help button click
|
||||
helpButton.addEventListener('click', function() {
|
||||
helpModal.classList.remove('hidden');
|
||||
document.body.style.overflow = 'hidden'; // Prevent scrolling when modal is open
|
||||
});
|
||||
|
||||
// Handle close modal button
|
||||
closeModal.addEventListener('click', function() {
|
||||
helpModal.classList.add('hidden');
|
||||
document.body.style.overflow = 'auto'; // Re-enable scrolling
|
||||
});
|
||||
|
||||
// Close modal when clicking outside
|
||||
helpModal.addEventListener('click', function(e) {
|
||||
if (e.target === helpModal) {
|
||||
helpModal.classList.add('hidden');
|
||||
document.body.style.overflow = 'auto';
|
||||
}
|
||||
});
|
||||
|
||||
// Close modal on escape key
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape' && !helpModal.classList.contains('hidden')) {
|
||||
helpModal.classList.add('hidden');
|
||||
document.body.style.overflow = 'auto';
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize the form
|
||||
updateOptions();
|
||||
updateDomainFields();
|
||||
</script>
|
||||
</Layout>
|
||||
|
||||
<style>
|
||||
/* Fix for mobile dropdown rendering */
|
||||
@media (max-width: 640px) {
|
||||
select {
|
||||
font-size: 16px; /* Prevents iOS zoom on focus */
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom styling for select elements */
|
||||
select {
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%236d9e37' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 0.5rem center;
|
||||
background-size: 1.5em 1.5em;
|
||||
padding-right: 2.5rem;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
import { DomainSetupForm } from '../components/DomainSetupForm';
|
||||
|
||||
// Page-specific SEO metadata
|
||||
const pageTitle = "Get Started | SiliconPin";
|
||||
const pageDescription = "Start your project with SiliconPin's hosting services. Deploy a web app, from source code, or upload a static site.";
|
||||
const pageImage = "https://images.unsplash.com/photo-1551731409-43eb3e517a1a?q=80&w=2000&auto=format&fit=crop";
|
||||
|
||||
// Generate a random subdomain for server side rendering
|
||||
const randomString = () => {
|
||||
return Math.random().toString(36).substring(2, 10);
|
||||
};
|
||||
const defaultSubdomain = randomString();
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={pageTitle}
|
||||
description={pageDescription}
|
||||
image={pageImage}
|
||||
type="website"
|
||||
>
|
||||
<main class="container mx-auto px-4 sm:px-6 py-8 sm:py-12">
|
||||
<div class="text-center mb-8 sm:mb-12">
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-[#6d9e37] mb-3 sm:mb-4">Get Started</h1>
|
||||
<p class="text-lg sm:text-xl max-w-3xl mx-auto text-neutral-300">
|
||||
Launch your project with SiliconPin's high-performance hosting services
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<DomainSetupForm defaultSubdomain={defaultSubdomain} client:load />
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
|
@ -0,0 +1,142 @@
|
|||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
|
||||
// Page-specific SEO metadata
|
||||
const pageTitle = "SiliconPin - High-Performance Hosting Solutions";
|
||||
const pageDescription = "SiliconPin offers reliable, high-performance hosting solutions for PHP, Node.js, Python, Kubernetes (K8s), and K3s with 24/7 technical support.";
|
||||
const pageImage = "https://images.unsplash.com/photo-1551731409-43eb3e517a1a?q=80&w=2000&auto=format&fit=crop";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={pageTitle}
|
||||
description={pageDescription}
|
||||
image={pageImage}
|
||||
>
|
||||
<section class="py-16 sm:py-20 px-6" aria-labelledby="hero-heading">
|
||||
<div class="container mx-auto text-center">
|
||||
<h1 id="hero-heading" class="text-4xl sm:text-5xl font-bold mb-4 sm:mb-6 text-[#6d9e37]">SiliconPin</h1>
|
||||
<p class="text-xl sm:text-2xl mb-8 sm:mb-10 max-w-3xl mx-auto text-neutral-300">
|
||||
High-performance hosting solutions for modern applications
|
||||
</p>
|
||||
<div class="flex gap-4 justify-center flex-wrap">
|
||||
<a
|
||||
href="/get-started"
|
||||
class="inline-flex items-center justify-center rounded-md bg-[#6d9e37] px-6 py-3 text-base font-medium text-white hover:bg-[#598035] transition-colors"
|
||||
rel="prefetch"
|
||||
>
|
||||
Get Started
|
||||
</a>
|
||||
<a
|
||||
href="/services"
|
||||
class="inline-flex items-center justify-center rounded-md border border-[#6d9e37] px-6 py-3 text-base font-medium text-[#6d9e37] hover:bg-[#6d9e37] hover:text-white transition-colors"
|
||||
rel="prefetch"
|
||||
>
|
||||
Explore Our Services
|
||||
</a>
|
||||
<a
|
||||
href="/contact"
|
||||
class="inline-flex items-center justify-center rounded-md border border-neutral-600 px-6 py-3 text-base font-medium text-neutral-300 hover:bg-neutral-700 hover:border-neutral-500 transition-colors"
|
||||
rel="prefetch"
|
||||
>
|
||||
Contact Us
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 py-16 sm:py-20 px-6" aria-labelledby="features-heading">
|
||||
<div class="container mx-auto">
|
||||
<div class="text-center mb-10 sm:mb-12">
|
||||
<h2 id="features-heading" class="text-2xl sm:text-3xl font-bold mb-3 sm:mb-4 text-white">Why Choose SiliconPin?</h2>
|
||||
<p class="text-lg sm:text-xl max-w-3xl mx-auto text-neutral-300">
|
||||
We provide reliable and scalable hosting solutions for businesses of all sizes
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 sm:gap-8">
|
||||
<article class="bg-neutral-700/30 p-6 rounded-lg border border-neutral-700">
|
||||
<div class="flex items-center justify-center h-12 w-12 rounded-md bg-[#6d9e37] text-white mb-4">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline></svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-medium mb-2 text-white">Reliable Performance</h3>
|
||||
<p class="text-neutral-300">Our infrastructure is designed for high availability and optimal performance with 99.9% uptime guarantee.</p>
|
||||
</article>
|
||||
|
||||
<article class="bg-neutral-700/30 p-6 rounded-lg border border-neutral-700">
|
||||
<div class="flex items-center justify-center h-12 w-12 rounded-md bg-[#6d9e37] text-white mb-4">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-medium mb-2 text-white">Advanced Security</h3>
|
||||
<p class="text-neutral-300">Enterprise-grade security measures with automated backups, SSL certificates, and DDoS protection.</p>
|
||||
</article>
|
||||
|
||||
<article class="bg-neutral-700/30 p-6 rounded-lg border border-neutral-700">
|
||||
<div class="flex items-center justify-center h-12 w-12 rounded-md bg-[#6d9e37] text-white mb-4">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-medium mb-2 text-white">24/7 Support</h3>
|
||||
<p class="text-neutral-300">Our expert team is always ready to help with any technical questions with average response time under 30 minutes.</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-10 sm:mt-12">
|
||||
<a
|
||||
href="/services"
|
||||
class="inline-flex items-center justify-center rounded-md bg-[#6d9e37] px-6 py-3 text-base font-medium text-white hover:bg-[#598035] transition-colors"
|
||||
rel="prefetch"
|
||||
>
|
||||
View All Services
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Contact CTA Section with improved mobile responsiveness -->
|
||||
<section class="py-16 sm:py-20 px-6" aria-labelledby="cta-heading">
|
||||
<div class="container mx-auto">
|
||||
<div class="bg-neutral-800 rounded-lg p-6 sm:p-8 lg:p-10 border border-neutral-700 relative overflow-hidden">
|
||||
<!-- Decorative background element -->
|
||||
<div class="absolute inset-0 opacity-10" aria-hidden="true">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 100 100" preserveAspectRatio="none">
|
||||
<path d="M0,0 L100,0 L100,100 L0,100 Z" fill="url(#grad)" />
|
||||
</svg>
|
||||
<defs>
|
||||
<linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stop-color="#6d9e37" />
|
||||
<stop offset="100%" stop-color="#2b323b" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</div>
|
||||
|
||||
<!-- Two-column layout that stacks on mobile -->
|
||||
<div class="relative z-10 flex flex-col lg:flex-row lg:justify-between lg:items-center">
|
||||
<!-- Text content - full width on mobile, partial on desktop -->
|
||||
<div class="mb-8 lg:mb-0 lg:max-w-xl">
|
||||
<h2 id="cta-heading" class="text-2xl sm:text-3xl font-bold text-white mb-3 sm:mb-4">Ready to Get Started?</h2>
|
||||
<p class="text-base sm:text-lg text-neutral-300">
|
||||
Contact our team today to discuss your hosting needs and find the perfect solution for your business.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Buttons - stacked on mobile, side-by-side on tablet -->
|
||||
<div class="flex flex-col sm:flex-row gap-4 w-full lg:w-auto">
|
||||
<a
|
||||
href="/get-started"
|
||||
class="inline-flex items-center justify-center rounded-md bg-[#6d9e37] px-6 py-3 text-base font-medium text-white hover:bg-[#598035] transition-colors w-full sm:w-auto"
|
||||
rel="prefetch"
|
||||
>
|
||||
Get Started
|
||||
</a>
|
||||
<a
|
||||
href="/contact"
|
||||
class="inline-flex items-center justify-center rounded-md border border-[#6d9e37] px-6 py-3 text-base font-medium text-[#6d9e37] hover:bg-[#6d9e37] hover:text-white transition-colors w-full sm:w-auto"
|
||||
rel="prefetch"
|
||||
>
|
||||
Contact Us
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</Layout>
|
|
@ -0,0 +1,182 @@
|
|||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
|
||||
// Page-specific SEO metadata
|
||||
const pageTitle = "Legal Agreement | SiliconPin";
|
||||
const pageDescription = "Review SiliconPin's legal agreement for using our hosting services. Find information about your legal rights and obligations.";
|
||||
const pageImage = "https://images.unsplash.com/photo-1551731409-43eb3e517a1a?q=80&w=2000&auto=format&fit=crop";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={pageTitle}
|
||||
description={pageDescription}
|
||||
image={pageImage}
|
||||
type="website"
|
||||
>
|
||||
<main class="container mx-auto px-4 sm:px-6 py-8 sm:py-12">
|
||||
<div class="text-center mb-8 sm:mb-12">
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-[#6d9e37] mb-3 sm:mb-4">Legal Agreement</h1>
|
||||
<p class="text-lg sm:text-xl max-w-3xl mx-auto text-neutral-300">
|
||||
Terms of our legal relationship
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="max-w-4xl mx-auto space-y-8">
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<p class="text-neutral-300">
|
||||
This Legal Agreement ("Agreement") is a binding contract between you ("Customer" or "you") and SiliconPin ("Company", "we", or "us") governing your use of our hosting services and related products (collectively, the "Services"). By using our Services, you acknowledge that you have read, understood, and agree to be bound by this Agreement.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">1. Relationship of Parties</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<p>
|
||||
The relationship between you and SiliconPin is that of an independent contractor. Nothing in this Agreement shall be construed as creating a partnership, joint venture, agency, employment, or fiduciary relationship between the parties.
|
||||
</p>
|
||||
<p>
|
||||
You acknowledge that SiliconPin has no control over the content of information transmitted by you through our Services and that SiliconPin does not examine the use to which you put the Services or the nature of the content or information you are transmitting.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">2. Term and Termination</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">2.1 Term</h3>
|
||||
<p>
|
||||
This Agreement begins on the date you first use our Services and continues until terminated as described herein.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">2.2 Termination by Customer</h3>
|
||||
<p>
|
||||
You may terminate this Agreement at any time by canceling your account through your control panel or by contacting our customer support. Upon termination, you will be responsible for all fees incurred up to the date of termination.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">2.3 Termination by SiliconPin</h3>
|
||||
<p>
|
||||
SiliconPin may terminate this Agreement at any time if:
|
||||
</p>
|
||||
<ul class="list-disc list-inside space-y-2">
|
||||
<li>You breach any provision of this Agreement</li>
|
||||
<li>You fail to pay any amounts due to SiliconPin</li>
|
||||
<li>Your use of the Services poses a security risk</li>
|
||||
<li>Providing the Services to you becomes unlawful</li>
|
||||
<li>Your use of the Services adversely impacts SiliconPin's systems or other customers</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">3. Intellectual Property</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">3.1 Your Content</h3>
|
||||
<p>
|
||||
You retain all right, title, and interest in and to any content that you create, upload, post, transmit, or otherwise make available through the Services ("Your Content"). By using our Services, you grant SiliconPin a non-exclusive, worldwide, royalty-free license to use, store, and copy Your Content solely for the purpose of providing the Services to you.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">3.2 SiliconPin's Intellectual Property</h3>
|
||||
<p>
|
||||
All intellectual property rights in the Services, including but not limited to software, logos, trademarks, and documentation, are owned by SiliconPin or its licensors. Nothing in this Agreement transfers any of SiliconPin's intellectual property rights to you.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">4. Warranties and Disclaimers</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">4.1 Customer Warranties</h3>
|
||||
<p>
|
||||
You represent and warrant that:
|
||||
</p>
|
||||
<ul class="list-disc list-inside space-y-2">
|
||||
<li>You have the legal capacity to enter into this Agreement</li>
|
||||
<li>Your use of the Services will comply with all applicable laws and regulations</li>
|
||||
<li>Your Content does not infringe or misappropriate any third party's intellectual property rights</li>
|
||||
<li>Your Content does not contain any material that is defamatory, obscene, or otherwise unlawful</li>
|
||||
</ul>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">4.2 Disclaimer of Warranties</h3>
|
||||
<p>
|
||||
THE SERVICES ARE PROVIDED "AS IS" AND "AS AVAILABLE," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND ANY WARRANTY ARISING FROM COURSE OF DEALING OR USAGE OF TRADE. SILICONPIN DOES NOT WARRANT THAT THE SERVICES WILL BE UNINTERRUPTED, ERROR-FREE, OR COMPLETELY SECURE.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">5. Limitation of Liability</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<p>
|
||||
IN NO EVENT WILL SILICONPIN BE LIABLE TO YOU OR ANY THIRD PARTY FOR ANY INDIRECT, CONSEQUENTIAL, EXEMPLARY, INCIDENTAL, SPECIAL, OR PUNITIVE DAMAGES, INCLUDING LOST PROFIT, LOST REVENUE, LOSS OF DATA, OR OTHER DAMAGES ARISING FROM YOUR USE OF THE SERVICES, EVEN IF SILICONPIN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
</p>
|
||||
<p>
|
||||
NOTWITHSTANDING ANYTHING TO THE CONTRARY, SILICONPIN'S LIABILITY TO YOU FOR ANY CAUSE WHATSOEVER AND REGARDLESS OF THE FORM OF THE ACTION, WILL AT ALL TIMES BE LIMITED TO THE AMOUNT PAID, IF ANY, BY YOU TO SILICONPIN FOR THE SERVICES DURING THE PERIOD OF THREE (3) MONTHS PRIOR TO ANY CAUSE OF ACTION ARISING.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">6. Indemnification</h2>
|
||||
<p class="text-neutral-300">
|
||||
You agree to defend, indemnify, and hold harmless SiliconPin and its officers, directors, employees, and agents from and against any and all claims, damages, obligations, losses, liabilities, costs, or debt, and expenses (including but not limited to attorney's fees) arising from: (i) your use of and access to the Services; (ii) your violation of any term of this Agreement; (iii) your violation of any third-party right, including without limitation any copyright, property, or privacy right; or (iv) any claim that Your Content caused damage to a third party.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">7. Dispute Resolution</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">7.1 Governing Law</h3>
|
||||
<p>
|
||||
This Agreement shall be governed by and construed in accordance with the laws of India, without regard to its conflict of law provisions.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">7.2 Arbitration</h3>
|
||||
<p>
|
||||
Any dispute arising out of or in connection with this Agreement, including any question regarding its existence, validity, or termination, shall be referred to and finally resolved by arbitration under the rules of the Indian Arbitration and Conciliation Act, 1996, which rules are deemed to be incorporated by reference into this clause. The number of arbitrators shall be one. The seat, or legal place, of arbitration shall be Kolkata, India. The language to be used in the arbitral proceedings shall be English.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">8. General Provisions</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">8.1 Entire Agreement</h3>
|
||||
<p>
|
||||
This Agreement constitutes the entire agreement between you and SiliconPin regarding the Services and supersedes all prior agreements and understandings, whether written or oral.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">8.2 Severability</h3>
|
||||
<p>
|
||||
If any provision of this Agreement is found to be unenforceable or invalid, that provision will be limited or eliminated to the minimum extent necessary so that this Agreement will otherwise remain in full force and effect.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">8.3 Assignment</h3>
|
||||
<p>
|
||||
You may not assign or transfer this Agreement without SiliconPin's prior written consent. SiliconPin may assign or transfer this Agreement without your consent.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">8.4 No Waiver</h3>
|
||||
<p>
|
||||
The failure of SiliconPin to enforce any right or provision of this Agreement will not be deemed a waiver of such right or provision.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">9. Contact Information</h2>
|
||||
<p class="text-neutral-300 mb-4">
|
||||
If you have any questions about this Legal Agreement, please contact us:
|
||||
</p>
|
||||
<div class="text-neutral-300">
|
||||
<p>Email: <a href="mailto:legal@siliconpin.com" class="text-[#6d9e37] hover:underline">legal@siliconpin.com</a></p>
|
||||
<p>Phone: +91-700-160-1485</p>
|
||||
<p>Address: 121 Lalbari, GourBongo Road, Habra, W.B. 743271, India</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="text-center pt-4">
|
||||
<p class="text-neutral-400 text-sm mb-6">Last Updated: March 18, 2025</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
|
@ -0,0 +1,174 @@
|
|||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
|
||||
// Page-specific SEO metadata
|
||||
const pageTitle = "Privacy Policy | SiliconPin";
|
||||
const pageDescription = "Learn how SiliconPin collects, uses, and protects your personal information. Our privacy policy outlines our data practices and your rights.";
|
||||
const pageImage = "https://images.unsplash.com/photo-1551731409-43eb3e517a1a?q=80&w=2000&auto=format&fit=crop";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={pageTitle}
|
||||
description={pageDescription}
|
||||
image={pageImage}
|
||||
type="website"
|
||||
>
|
||||
<main class="container mx-auto px-4 sm:px-6 py-8 sm:py-12">
|
||||
<div class="text-center mb-8 sm:mb-12">
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-[#6d9e37] mb-3 sm:mb-4">Privacy Policy</h1>
|
||||
<p class="text-lg sm:text-xl max-w-3xl mx-auto text-neutral-300">
|
||||
How we collect, use, and protect your information
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="max-w-4xl mx-auto space-y-8">
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<p class="text-neutral-300 mb-6">
|
||||
At SiliconPin, we are committed to protecting your privacy and ensuring the security of your personal information. This Privacy Policy explains how we collect, use, disclose, and safeguard your information when you use our hosting services or visit our website.
|
||||
</p>
|
||||
<p class="text-neutral-300">
|
||||
Please read this Privacy Policy carefully. By accessing or using our services, you acknowledge that you have read, understood, and agree to be bound by all the terms of this Privacy Policy.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">1. Information We Collect</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">1.1 Personal Information</h3>
|
||||
<p>
|
||||
We may collect personal information that you provide directly to us, such as:
|
||||
</p>
|
||||
<ul class="list-disc list-inside space-y-2">
|
||||
<li>Name</li>
|
||||
<li>Email address</li>
|
||||
<li>Phone number</li>
|
||||
<li>Billing address</li>
|
||||
<li>Payment information</li>
|
||||
<li>Company information</li>
|
||||
<li>Account credentials</li>
|
||||
</ul>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">1.2 Usage Information</h3>
|
||||
<p>
|
||||
We may collect information about how you use our services, including:
|
||||
</p>
|
||||
<ul class="list-disc list-inside space-y-2">
|
||||
<li>Log files</li>
|
||||
<li>IP addresses</li>
|
||||
<li>Browser type</li>
|
||||
<li>Pages visited</li>
|
||||
<li>Time spent on pages</li>
|
||||
<li>Referring website addresses</li>
|
||||
<li>Resource usage statistics</li>
|
||||
</ul>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">1.3 Cookies and Similar Technologies</h3>
|
||||
<p>
|
||||
We use cookies and similar tracking technologies to track activity on our website and to hold certain information. Cookies are files with a small amount of data that may include an anonymous unique identifier. You can instruct your browser to refuse all cookies or to indicate when a cookie is being sent.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">2. How We Use Your Information</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<p>
|
||||
We may use the information we collect for various purposes, including:
|
||||
</p>
|
||||
<ul class="list-disc list-inside space-y-2">
|
||||
<li>Providing, maintaining, and improving our services</li>
|
||||
<li>Processing and completing transactions</li>
|
||||
<li>Sending administrative information, such as service updates and security alerts</li>
|
||||
<li>Responding to your comments, questions, and requests</li>
|
||||
<li>Sending promotional materials and newsletters (with opt-out options)</li>
|
||||
<li>Monitoring and analyzing trends, usage, and activities</li>
|
||||
<li>Detecting, preventing, and addressing technical issues</li>
|
||||
<li>Complying with legal obligations</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">3. Information Sharing and Disclosure</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<p>
|
||||
We may share your information in the following situations:
|
||||
</p>
|
||||
<ul class="list-disc list-inside space-y-2">
|
||||
<li><strong>With Service Providers:</strong> We may share your information with third-party service providers who perform services on our behalf, such as payment processing, data analysis, email delivery, and customer service.</li>
|
||||
<li><strong>For Legal Reasons:</strong> We may disclose your information if required to do so by law or in response to valid requests by public authorities.</li>
|
||||
<li><strong>Business Transfers:</strong> In the event of a merger, acquisition, or asset sale, your information may be transferred as a business asset.</li>
|
||||
<li><strong>With Your Consent:</strong> We may share your information for other purposes with your consent.</li>
|
||||
</ul>
|
||||
<p>
|
||||
We do not sell, rent, or trade your personal information with third parties for their commercial purposes.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">4. Data Security</h2>
|
||||
<p class="text-neutral-300">
|
||||
We implement appropriate technical and organizational measures to protect the security of your personal information. However, please be aware that no method of transmission over the Internet or method of electronic storage is 100% secure. While we strive to use commercially acceptable means to protect your personal information, we cannot guarantee its absolute security.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">5. Data Retention</h2>
|
||||
<p class="text-neutral-300">
|
||||
We will retain your personal information only for as long as is necessary for the purposes set out in this Privacy Policy. We will retain and use your information to the extent necessary to comply with our legal obligations, resolve disputes, and enforce our policies.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">6. Your Rights</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<p>
|
||||
Depending on your location, you may have certain rights regarding your personal information, including:
|
||||
</p>
|
||||
<ul class="list-disc list-inside space-y-2">
|
||||
<li>The right to access the personal information we have about you</li>
|
||||
<li>The right to request correction of inaccurate personal information</li>
|
||||
<li>The right to request deletion of your personal information</li>
|
||||
<li>The right to object to processing of your personal information</li>
|
||||
<li>The right to data portability</li>
|
||||
<li>The right to withdraw consent</li>
|
||||
</ul>
|
||||
<p>
|
||||
To exercise these rights, please contact us using the information provided in the "Contact Us" section.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">7. Children's Privacy</h2>
|
||||
<p class="text-neutral-300">
|
||||
Our services are not intended for use by children under the age of 16. We do not knowingly collect personal information from children under 16. If we become aware that we have collected personal information from a child under 16 without verification of parental consent, we will take steps to remove that information from our servers.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">8. Changes to This Privacy Policy</h2>
|
||||
<p class="text-neutral-300">
|
||||
We may update our Privacy Policy from time to time. We will notify you of any changes by posting the new Privacy Policy on this page and updating the "Last Updated" date. You are advised to review this Privacy Policy periodically for any changes.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">9. Contact Us</h2>
|
||||
<p class="text-neutral-300 mb-4">
|
||||
If you have any questions about this Privacy Policy, please contact us:
|
||||
</p>
|
||||
<div class="text-neutral-300">
|
||||
<p>Email: <a href="mailto:privacy@siliconpin.com" class="text-[#6d9e37] hover:underline">privacy@siliconpin.com</a></p>
|
||||
<p>Phone: +91-700-160-1485</p>
|
||||
<p>Address: 121 Lalbari, GourBongo Road, Habra, W.B. 743271, India</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="text-center pt-4">
|
||||
<p class="text-neutral-400 text-sm mb-6">Last Updated: March 18, 2025</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
|
@ -0,0 +1,122 @@
|
|||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
|
||||
// Page-specific SEO metadata
|
||||
const pageTitle = "Refund Policy | SiliconPin";
|
||||
const pageDescription = "Learn about SiliconPin's refund policy for our hosting services. Find information about eligibility, process, and timeline for refunds.";
|
||||
const pageImage = "https://images.unsplash.com/photo-1551731409-43eb3e517a1a?q=80&w=2000&auto=format&fit=crop";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={pageTitle}
|
||||
description={pageDescription}
|
||||
image={pageImage}
|
||||
type="website"
|
||||
>
|
||||
<main class="container mx-auto px-4 sm:px-6 py-8 sm:py-12">
|
||||
<div class="text-center mb-8 sm:mb-12">
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-[#6d9e37] mb-3 sm:mb-4">Refund Policy</h1>
|
||||
<p class="text-lg sm:text-xl max-w-3xl mx-auto text-neutral-300">
|
||||
Our commitment to fair and transparent refund procedures
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="max-w-4xl mx-auto space-y-8">
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<p class="text-neutral-300 mb-6">
|
||||
At SiliconPin, we strive to provide high-quality hosting services that meet our customers' expectations. We understand that there may be circumstances where a refund is warranted, and we have established this refund policy to outline the conditions and procedures for such situations.
|
||||
</p>
|
||||
|
||||
<h2 class="text-2xl font-bold text-white mb-4">1. Eligibility for Refunds</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">1.1 Service Cancellation within 30 Days</h3>
|
||||
<p>
|
||||
If you are dissatisfied with our services for any reason, you may request a refund within 30 days of the initial purchase date. This is our "30-day satisfaction guarantee" and applies to first-time purchases of hosting plans.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">1.2 Service Unavailability</h3>
|
||||
<p>
|
||||
If our service experiences extended downtime (exceeding our 99.9% uptime guarantee) within a billing period, you may be eligible for a prorated refund for the affected period. This will be calculated based on the duration of the downtime and the cost of your hosting plan.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">1.3 Service Termination by SiliconPin</h3>
|
||||
<p>
|
||||
If SiliconPin terminates your service for reasons other than violation of our Terms and Conditions, you may be eligible for a prorated refund for the unused portion of your current billing period.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">2. Non-Refundable Items</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<p>The following items and circumstances are generally not eligible for refunds:</p>
|
||||
<ul class="list-disc list-inside space-y-2">
|
||||
<li>Domain registration fees</li>
|
||||
<li>Setup fees</li>
|
||||
<li>Additional services or add-ons</li>
|
||||
<li>Services cancelled after the 30-day satisfaction guarantee period</li>
|
||||
<li>Services terminated due to violation of our Terms and Conditions</li>
|
||||
<li>Transaction fees or currency conversion charges</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">3. Refund Process</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">3.1 Requesting a Refund</h3>
|
||||
<p>
|
||||
To request a refund, please contact our customer support team through one of the following methods:
|
||||
</p>
|
||||
<ul class="list-disc list-inside space-y-2">
|
||||
<li>Email: <a href="mailto:support@siliconpin.com" class="text-[#6d9e37] hover:underline">support@siliconpin.com</a></li>
|
||||
<li>Phone: +91-700-160-1485</li>
|
||||
<li>Contact form on our website</li>
|
||||
</ul>
|
||||
<p>
|
||||
Please include your account information, the service you wish to cancel, and the reason for your refund request.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">3.2 Processing Time</h3>
|
||||
<p>
|
||||
We aim to process all refund requests within 7 business days of receiving the request. The actual time for the refunded amount to appear in your account may vary depending on your payment provider.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">3.3 Refund Method</h3>
|
||||
<p>
|
||||
Refunds will be issued using the same payment method used for the original purchase. If this is not possible, we will work with you to find an alternative method.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">4. Policy Modifications</h2>
|
||||
<p class="text-neutral-300">
|
||||
SiliconPin reserves the right to modify this refund policy at any time. Any changes to this policy will be posted on our website and will apply to purchases made after the date of modification.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">5. Contact Us</h2>
|
||||
<p class="text-neutral-300 mb-4">
|
||||
If you have any questions or concerns about our refund policy, please don't hesitate to contact us:
|
||||
</p>
|
||||
<div class="text-neutral-300">
|
||||
<p>Email: <a href="mailto:support@siliconpin.com" class="text-[#6d9e37] hover:underline">support@siliconpin.com</a></p>
|
||||
<p>Phone: +91-700-160-1485</p>
|
||||
<p>Address: 121 Lalbari, GourBongo Road, Habra, W.B. 743271, India</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="text-center pt-4">
|
||||
<p class="text-neutral-400 text-sm mb-6">Last Updated: March 18, 2025</p>
|
||||
<a
|
||||
href="/contact"
|
||||
class="inline-flex items-center justify-center rounded-md bg-[#6d9e37] px-6 py-3 text-base font-medium text-white hover:bg-[#598035] transition-colors"
|
||||
>
|
||||
Contact Support
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
|
@ -0,0 +1,21 @@
|
|||
import type { APIRoute } from 'astro';
|
||||
|
||||
export const GET: APIRoute = async ({ site }) => {
|
||||
if (!site) {
|
||||
return new Response('Site configuration error', { status: 500 });
|
||||
}
|
||||
|
||||
const siteUrl = site.toString();
|
||||
|
||||
return new Response(
|
||||
`User-agent: *
|
||||
Allow: /
|
||||
|
||||
Sitemap: ${siteUrl}/sitemap.xml`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'text/plain',
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
|
@ -0,0 +1,132 @@
|
|||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
import { ServiceCard } from '../components/ServiceCard';
|
||||
|
||||
// Page-specific SEO metadata
|
||||
const pageTitle = "Hosting Services | SiliconPin";
|
||||
const pageDescription = "Explore SiliconPin's reliable hosting services for PHP, Node.js, Python, Kubernetes (K8s), and K3s. Scalable solutions for businesses of all sizes with 24/7 support.";
|
||||
const pageImage = "https://images.unsplash.com/photo-1551731409-43eb3e517a1a?q=80&w=2000&auto=format&fit=crop";
|
||||
|
||||
// Service data
|
||||
const services = [
|
||||
{
|
||||
title: 'PHP Hosting',
|
||||
description: 'Fast, secure, and reliable PHP hosting solutions for your web applications.',
|
||||
imageUrl: 'https://images.unsplash.com/photo-1599507593499-a3f7d7d97667?q=80&w=2000&auto=format&fit=crop',
|
||||
features: [
|
||||
'PHP 8.x support',
|
||||
'One-click installation of popular CMS',
|
||||
'Free SSL certificates',
|
||||
'Optimized for WordPress, Laravel, etc.',
|
||||
'24/7 Technical support'
|
||||
],
|
||||
learnMoreUrl: '/services/php'
|
||||
},
|
||||
{
|
||||
title: 'Node.js Hosting',
|
||||
description: 'High-performance Node.js hosting with seamless deployment pipelines.',
|
||||
imageUrl: 'https://images.unsplash.com/photo-1570063578733-6a33b69d1538?q=80&w=2000&auto=format&fit=crop',
|
||||
features: [
|
||||
'Latest Node.js versions',
|
||||
'NPM/Yarn support',
|
||||
'Express, Next.js, and more',
|
||||
'Managed SSL certificates',
|
||||
'Automatic scaling'
|
||||
],
|
||||
learnMoreUrl: '/services/nodejs'
|
||||
},
|
||||
{
|
||||
title: 'Python Hosting',
|
||||
description: 'Scalable Python hosting for web applications, APIs, and data science projects.',
|
||||
imageUrl: 'https://images.unsplash.com/photo-1526379879527-8559ecfcaec0?q=80&w=2000&auto=format&fit=crop',
|
||||
features: [
|
||||
'Python 3.x support',
|
||||
'Django, Flask, and FastAPI ready',
|
||||
'Virtual environments',
|
||||
'Jupyter notebook integration',
|
||||
'Seamless deployment'
|
||||
],
|
||||
learnMoreUrl: '/services/python'
|
||||
},
|
||||
{
|
||||
title: 'Kubernetes (K8s)',
|
||||
description: 'Enterprise-grade Kubernetes clusters for container orchestration at scale.',
|
||||
imageUrl: 'https://images.unsplash.com/photo-1551731409-43eb3e517a1a?q=80&w=2000&auto=format&fit=crop',
|
||||
features: [
|
||||
'Fully managed K8s clusters',
|
||||
'Auto-scaling and load balancing',
|
||||
'Advanced networking options',
|
||||
'Persistent storage solutions',
|
||||
'Enterprise support available'
|
||||
],
|
||||
learnMoreUrl: '/services/kubernetes'
|
||||
},
|
||||
{
|
||||
title: 'K3s Lightweight Kubernetes',
|
||||
description: 'Lightweight Kubernetes for edge, IoT, and resource-constrained environments.',
|
||||
imageUrl: 'https://images.unsplash.com/photo-1558494949-ef010cbdcc31?q=80&w=2000&auto=format&fit=crop',
|
||||
features: [
|
||||
'Minimal resource requirements',
|
||||
'Single binary < 100MB',
|
||||
'Edge computing optimized',
|
||||
'ARM support (Raspberry Pi compatible)',
|
||||
'Simplified management'
|
||||
],
|
||||
learnMoreUrl: '/services/k3s'
|
||||
}
|
||||
];
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={pageTitle}
|
||||
description={pageDescription}
|
||||
image={pageImage}
|
||||
type="website"
|
||||
>
|
||||
<main class="container mx-auto px-4 sm:px-6 py-8 sm:py-12">
|
||||
<div class="text-center mb-8 sm:mb-12">
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-[#6d9e37] mb-3 sm:mb-4">Hosting Services</h1>
|
||||
<p class="text-lg sm:text-xl max-w-3xl mx-auto text-neutral-300">
|
||||
Reliable, scalable, and secure hosting solutions for all your applications, from simple websites to complex microservices.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<section aria-labelledby="services-heading">
|
||||
<h2 id="services-heading" class="sr-only">Our hosting services</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8">
|
||||
{services.map((service, index) => (
|
||||
<ServiceCard
|
||||
client:load
|
||||
title={service.title}
|
||||
description={service.description}
|
||||
imageUrl={service.imageUrl}
|
||||
features={service.features}
|
||||
learnMoreUrl={service.learnMoreUrl}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mt-12 sm:mt-16 bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700" aria-labelledby="custom-solutions-heading">
|
||||
<div class="text-center mb-6 sm:mb-8">
|
||||
<h2 id="custom-solutions-heading" class="text-xl sm:text-2xl font-bold text-white">Need a Custom Hosting Solution?</h2>
|
||||
<p class="mt-2 text-neutral-300">Our experts can design a tailored hosting environment for your specific needs.</p>
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row items-center justify-center gap-4">
|
||||
<a
|
||||
href="/contact"
|
||||
class="inline-flex items-center justify-center rounded-md bg-[#6d9e37] px-6 py-3 text-base font-medium text-white hover:bg-[#598035] transition-colors w-full sm:w-auto"
|
||||
rel="prefetch"
|
||||
>
|
||||
Contact Us
|
||||
</a>
|
||||
<a
|
||||
href="/services/custom"
|
||||
class="inline-flex items-center justify-center rounded-md border border-[#6d9e37] px-6 py-3 text-base font-medium text-[#6d9e37] hover:bg-[#6d9e37] hover:text-white transition-colors w-full sm:w-auto"
|
||||
>
|
||||
Learn About Custom Solutions
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</Layout>
|
|
@ -0,0 +1,37 @@
|
|||
import type { APIRoute } from 'astro';
|
||||
|
||||
// List of all pages
|
||||
const pages = [
|
||||
'',
|
||||
'/services',
|
||||
'/contact'
|
||||
];
|
||||
|
||||
// Function to generate sitemap
|
||||
export const GET: APIRoute = async ({ site }) => {
|
||||
if (!site) {
|
||||
return new Response('Site configuration error', { status: 500 });
|
||||
}
|
||||
|
||||
const siteUrl = site.toString();
|
||||
const currentDate = new Date().toISOString().split('T')[0];
|
||||
|
||||
return new Response(
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
${pages.map(page => `
|
||||
<url>
|
||||
<loc>${siteUrl}${page}</loc>
|
||||
<lastmod>${currentDate}</lastmod>
|
||||
<changefreq>${page === '' ? 'daily' : 'weekly'}</changefreq>
|
||||
<priority>${page === '' ? '1.0' : '0.7'}</priority>
|
||||
</url>
|
||||
`).join('')}
|
||||
</urlset>`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/xml',
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
import { FeedbackForm } from '../components/FeedbackForm';
|
||||
|
||||
// Page-specific SEO metadata
|
||||
const pageTitle = "Suggestion or Report | SiliconPin";
|
||||
const pageDescription = "Submit your suggestions or report issues to help us improve our services.";
|
||||
const pageImage = "https://images.unsplash.com/photo-1511467687858-23d96c32e4ae?q=80&w=2000&auto=format&fit=crop";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={pageTitle}
|
||||
description={pageDescription}
|
||||
image={pageImage}
|
||||
type="website"
|
||||
>
|
||||
<main class="container mx-auto px-4 sm:px-6 py-8 sm:py-12">
|
||||
<div class="text-center mb-8 sm:mb-12">
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-[#6d9e37] mb-3 sm:mb-4">Suggestion or Report</h1>
|
||||
<p class="text-lg sm:text-xl max-w-3xl mx-auto text-neutral-300">
|
||||
We value your feedback! Use this form to submit suggestions or report any issues you've encountered.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<FeedbackForm client:load />
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
|
||||
<script>
|
||||
// Script to capture referrer information
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Check if there is a referrer
|
||||
const referrer = document.referrer || 'Direct Access';
|
||||
// Store the referrer in a hidden field or local storage
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('pageReferrer', referrer);
|
||||
|
||||
// Add referrer to hidden field if it exists
|
||||
const referrerField = document.getElementById('referrerField') as HTMLInputElement;
|
||||
if (referrerField) {
|
||||
referrerField.value = referrer;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,164 @@
|
|||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
|
||||
// Page-specific SEO metadata
|
||||
const pageTitle = "Terms & Conditions | SiliconPin";
|
||||
const pageDescription = "Review SiliconPin's Terms & Conditions for using our hosting services. Find information about service usage, account management, and legal obligations.";
|
||||
const pageImage = "https://images.unsplash.com/photo-1551731409-43eb3e517a1a?q=80&w=2000&auto=format&fit=crop";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={pageTitle}
|
||||
description={pageDescription}
|
||||
image={pageImage}
|
||||
type="website"
|
||||
>
|
||||
<main class="container mx-auto px-4 sm:px-6 py-8 sm:py-12">
|
||||
<div class="text-center mb-8 sm:mb-12">
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-[#6d9e37] mb-3 sm:mb-4">Terms & Conditions</h1>
|
||||
<p class="text-lg sm:text-xl max-w-3xl mx-auto text-neutral-300">
|
||||
Please read these terms carefully before using our services
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="max-w-4xl mx-auto space-y-8">
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<p class="text-neutral-300 mb-6">
|
||||
Welcome to SiliconPin. By accessing or using our services, you agree to be bound by these Terms and Conditions. If you disagree with any part of these terms, you may not access or use our services.
|
||||
</p>
|
||||
|
||||
<h2 class="text-2xl font-bold text-white mb-4">1. Service Terms</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">1.1 Service Description</h3>
|
||||
<p>
|
||||
SiliconPin provides web hosting, application hosting, and related services. We reserve the right to modify, suspend, or discontinue any aspect of our services at any time.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">1.2 Service Level Agreement (SLA)</h3>
|
||||
<p>
|
||||
SiliconPin aims to provide 99.9% uptime for our services. In the event that we fail to meet this commitment, you may be eligible for service credits as outlined in our SLA.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">1.3 Service Limitations</h3>
|
||||
<p>
|
||||
Our services are subject to certain limitations, including but not limited to bandwidth, storage, and computational resources. These limitations are specified in your hosting plan.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">2. Account Terms</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">2.1 Account Creation</h3>
|
||||
<p>
|
||||
To use our services, you must create an account with accurate, complete, and up-to-date information. You are responsible for maintaining the security of your account and password.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">2.2 Account Termination</h3>
|
||||
<p>
|
||||
SiliconPin reserves the right to suspend or terminate your account if you violate these Terms and Conditions, engage in illegal activities, or if your usage negatively impacts our services or other users.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">2.3 Account Security</h3>
|
||||
<p>
|
||||
You are responsible for all activities that occur under your account. You must immediately notify SiliconPin of any unauthorized use of your account or any other breach of security.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">3. Acceptable Use Policy</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<p>
|
||||
You agree not to use our services for any purpose that is illegal, harmful, or prohibited by these Terms and Conditions. Prohibited activities include but are not limited to:
|
||||
</p>
|
||||
<ul class="list-disc list-inside space-y-2">
|
||||
<li>Distribution of malware or other malicious software</li>
|
||||
<li>Phishing or attempting to gain unauthorized access to other systems</li>
|
||||
<li>Hosting content that infringes on intellectual property rights</li>
|
||||
<li>Sending unsolicited mass emails (spam)</li>
|
||||
<li>Hosting illegal content or engaging in illegal activities</li>
|
||||
<li>Overusing server resources in a way that disrupts service for other users</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">4. Payment Terms</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">4.1 Billing Cycle</h3>
|
||||
<p>
|
||||
Services are billed according to the plan you select. Payment is due at the beginning of each billing cycle.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">4.2 Late Payments</h3>
|
||||
<p>
|
||||
If payment is not received by the due date, SiliconPin reserves the right to suspend or terminate services until payment is made. A late fee may be applied to overdue accounts.
|
||||
</p>
|
||||
|
||||
<h3 class="text-xl font-medium text-[#6d9e37]">4.3 Refunds</h3>
|
||||
<p>
|
||||
Refunds are governed by our Refund Policy. Please refer to the <a href="/refund-policy" class="text-[#6d9e37] hover:underline">Refund Policy</a> for details.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">5. Intellectual Property</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<p>
|
||||
SiliconPin respects intellectual property rights and expects our users to do the same. You retain ownership of your content hosted on our services, but you grant SiliconPin the right to access and use this content as necessary to provide our services.
|
||||
</p>
|
||||
<p>
|
||||
SiliconPin's name, logo, and other trademarks are the property of SiliconPin and may not be used without prior written permission.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">6. Limitation of Liability</h2>
|
||||
<div class="space-y-4 text-neutral-300">
|
||||
<p>
|
||||
To the maximum extent permitted by law, SiliconPin shall not be liable for any indirect, incidental, special, consequential, or punitive damages, including without limitation, loss of profits, data, use, goodwill, or other intangible losses, resulting from:
|
||||
</p>
|
||||
<ul class="list-disc list-inside space-y-2">
|
||||
<li>Your use or inability to use our services</li>
|
||||
<li>Any unauthorized access to or use of our servers and/or any personal information stored therein</li>
|
||||
<li>Any interruption or cessation of transmission to or from our services</li>
|
||||
<li>Any bugs, viruses, trojan horses, or the like that may be transmitted to or through our service</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">7. Changes to Terms</h2>
|
||||
<p class="text-neutral-300">
|
||||
SiliconPin reserves the right to modify these Terms and Conditions at any time. We will notify users of any significant changes. Your continued use of our services after such modifications constitutes your acceptance of the new Terms and Conditions.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">8. Governing Law</h2>
|
||||
<p class="text-neutral-300">
|
||||
These Terms and Conditions shall be governed by and construed in accordance with the laws of India, without regard to its conflict of law provisions.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||||
<h2 class="text-2xl font-bold text-white mb-4">9. Contact Information</h2>
|
||||
<p class="text-neutral-300 mb-4">
|
||||
If you have any questions about these Terms and Conditions, please contact us:
|
||||
</p>
|
||||
<div class="text-neutral-300">
|
||||
<p>Email: <a href="mailto:support@siliconpin.com" class="text-[#6d9e37] hover:underline">support@siliconpin.com</a></p>
|
||||
<p>Phone: +91-700-160-1485</p>
|
||||
<p>Address: 121 Lalbari, GourBongo Road, Habra, W.B. 743271, India</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="text-center pt-4">
|
||||
<p class="text-neutral-400 text-sm mb-6">Last Updated: March 18, 2025</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
|
@ -0,0 +1,20 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 222 17% 20%;
|
||||
--foreground: 220 13% 82%;
|
||||
|
||||
--primary: 87 49% 42%;
|
||||
--primary-foreground: 0 0% 100%;
|
||||
|
||||
--secondary: 87 49% 35%;
|
||||
--secondary-foreground: 0 0% 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-[#2b323b] text-[#c7ccd5];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
'sp-dark': '#2b323b',
|
||||
'sp-light': '#c7ccd5',
|
||||
'sp-primary': '#6d9e37',
|
||||
'sp-secondary': '#598035',
|
||||
},
|
||||
},
|
||||
},
|
||||
darkMode: 'class',
|
||||
plugins: [],
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"extends": "astro/tsconfigs/strict",
|
||||
"include": [".astro/types.d.ts", "**/*"],
|
||||
"exclude": ["dist"]
|
||||
}
|
Loading…
Reference in New Issue