00Boobs00 commited on
Commit
9586cdd
Β·
verified Β·
1 Parent(s): 3d39e8a

A deeply integrated CivitAI client that accepts user supplied CivitAI keys and quick check-box age verification to unlock the vast and diverse world of different base modes

Browse files
Files changed (6) hide show
  1. README.md +8 -5
  2. components/footer.js +94 -0
  3. components/header.js +106 -0
  4. index.html +57 -19
  5. script.js +99 -0
  6. style.css +40 -19
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Civitai Explorer
3
- emoji: πŸ‘
4
- colorFrom: pink
5
- colorTo: gray
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
  ---
2
+ title: CivitAI Explorer πŸ”
3
+ colorFrom: purple
4
+ colorTo: pink
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://huggingface.co/deepsite).
components/footer.js ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomFooter extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ :host {
7
+ display: block;
8
+ margin-top: 4rem;
9
+ }
10
+
11
+ footer {
12
+ background-color: #111827;
13
+ border-top: 1px solid #374151;
14
+ padding: 2rem 0;
15
+ }
16
+
17
+ .container {
18
+ max-width: 1200px;
19
+ margin: 0 auto;
20
+ padding: 0 1rem;
21
+ }
22
+
23
+ .footer-content {
24
+ display: flex;
25
+ flex-direction: column;
26
+ align-items: center;
27
+ text-align: center;
28
+ }
29
+
30
+ .social-links {
31
+ display: flex;
32
+ margin: 1rem 0;
33
+ }
34
+
35
+ .social-link {
36
+ margin: 0 0.5rem;
37
+ color: #d1d5db;
38
+ transition: color 0.3s;
39
+ }
40
+
41
+ .social-link:hover {
42
+ color: #10b981;
43
+ }
44
+
45
+ .copyright {
46
+ color: #9ca3af;
47
+ font-size: 0.875rem;
48
+ margin-top: 1rem;
49
+ }
50
+ </style>
51
+
52
+ <footer>
53
+ <div class="container">
54
+ <div class="footer-content">
55
+ <div class="logo">
56
+ <i data-feather="box" style="color: #10b981;"></i>
57
+ <span style="margin-left: 0.5rem; font-weight: bold;">CivitAI Explorer</span>
58
+ </div>
59
+
60
+ <div class="social-links">
61
+ <a href="#" class="social-link">
62
+ <i data-feather="github"></i>
63
+ </a>
64
+ <a href="#" class="social-link">
65
+ <i data-feather="twitter"></i>
66
+ </a>
67
+ <a href="#" class="social-link">
68
+ <i data-feather="discord"></i>
69
+ </a>
70
+ </div>
71
+
72
+ <p class="copyright">
73
+ &copy; ${new Date().getFullYear()} CivitAI Explorer. This is an unofficial client. All models belong to their respective creators.
74
+ </p>
75
+ </div>
76
+ </div>
77
+ </footer>
78
+ `;
79
+
80
+ // Initialize feather icons
81
+ setTimeout(() => {
82
+ const featherScript = document.createElement('script');
83
+ featherScript.src = "https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js";
84
+ featherScript.onload = () => {
85
+ if (this.shadowRoot) {
86
+ feather.replace({}, this.shadowRoot);
87
+ }
88
+ };
89
+ this.shadowRoot.appendChild(featherScript);
90
+ }, 0);
91
+ }
92
+ }
93
+
94
+ customElements.define('custom-footer', CustomFooter);
components/header.js ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomHeader extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ :host {
7
+ display: block;
8
+ }
9
+
10
+ header {
11
+ background-color: #111827;
12
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
13
+ }
14
+
15
+ .container {
16
+ max-width: 1200px;
17
+ margin: 0 auto;
18
+ padding: 0 1rem;
19
+ }
20
+
21
+ nav {
22
+ display: flex;
23
+ justify-content: space-between;
24
+ align-items: center;
25
+ padding: 1rem 0;
26
+ }
27
+
28
+ .logo {
29
+ display: flex;
30
+ align-items: center;
31
+ font-weight: bold;
32
+ font-size: 1.5rem;
33
+ color: #10b981;
34
+ }
35
+
36
+ .logo i {
37
+ margin-right: 0.5rem;
38
+ }
39
+
40
+ ul {
41
+ display: flex;
42
+ list-style: none;
43
+ }
44
+
45
+ li {
46
+ margin-left: 2rem;
47
+ }
48
+
49
+ a {
50
+ color: #d1d5db;
51
+ text-decoration: none;
52
+ transition: color 0.3s;
53
+ }
54
+
55
+ a:hover {
56
+ color: #10b981;
57
+ }
58
+
59
+ @media (max-width: 768px) {
60
+ nav {
61
+ flex-direction: column;
62
+ }
63
+
64
+ ul {
65
+ margin-top: 1rem;
66
+ }
67
+
68
+ li {
69
+ margin: 0 1rem;
70
+ }
71
+ }
72
+ </style>
73
+
74
+ <header>
75
+ <div class="container">
76
+ <nav>
77
+ <a href="/" class="logo">
78
+ <i data-feather="box"></i>
79
+ <span>CivitAI Explorer</span>
80
+ </a>
81
+ <ul>
82
+ <li><a href="/">Home</a></li>
83
+ <li><a href="#">Models</a></li>
84
+ <li><a href="#">Collections</a></li>
85
+ <li><a href="#">About</a></li>
86
+ </ul>
87
+ </nav>
88
+ </div>
89
+ </header>
90
+ `;
91
+
92
+ // Initialize feather icons after a short delay to ensure DOM is ready
93
+ setTimeout(() => {
94
+ const featherScript = document.createElement('script');
95
+ featherScript.src = "https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js";
96
+ featherScript.onload = () => {
97
+ if (this.shadowRoot) {
98
+ feather.replace({}, this.shadowRoot);
99
+ }
100
+ };
101
+ this.shadowRoot.appendChild(featherScript);
102
+ }, 0);
103
+ }
104
+ }
105
+
106
+ customElements.define('custom-header', CustomHeader);
index.html CHANGED
@@ -1,19 +1,57 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>CivitAI Explorer</title>
7
+ <link rel="icon" type="image/x-icon" href="/static/favicon.ico">
8
+ <link rel="stylesheet" href="style.css">
9
+ <script src="https://cdn.tailwindcss.com"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
11
+ <script src="https://unpkg.com/feather-icons"></script>
12
+ </head>
13
+ <body class="bg-gray-900 text-white">
14
+ <custom-header></custom-header>
15
+
16
+ <main class="container mx-auto px-4 py-8">
17
+ <section class="mb-12">
18
+ <h1 class="text-4xl font-bold mb-6 text-center">Unlock the World of AI Models</h1>
19
+ <p class="text-lg text-center max-w-2xl mx-auto mb-8">
20
+ Access thousands of AI models from CivitAI with our secure explorer.
21
+ Simply provide your API key and verify your age to get started.
22
+ </p>
23
+
24
+ <div class="max-w-md mx-auto bg-gray-800 rounded-xl shadow-md overflow-hidden p-6">
25
+ <div class="mb-4">
26
+ <label for="apiKey" class="block text-sm font-medium mb-2">CivitAI API Key</label>
27
+ <input type="password" id="apiKey" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500" placeholder="Enter your API key">
28
+ </div>
29
+
30
+ <div class="flex items-center mb-6">
31
+ <input id="ageVerification" type="checkbox" class="w-4 h-4 text-green-500 bg-gray-700 border-gray-600 rounded focus:ring-green-500">
32
+ <label for="ageVerification" class="ml-2 text-sm">I am 18+ years old</label>
33
+ </div>
34
+
35
+ <button id="unlockBtn" class="w-full bg-green-500 hover:bg-green-600 text-white font-bold py-2 px-4 rounded transition duration-300">
36
+ Unlock Models
37
+ </button>
38
+ </div>
39
+ </section>
40
+
41
+ <section id="modelsSection" class="hidden">
42
+ <h2 class="text-3xl font-bold mb-6">Featured Models</h2>
43
+ <div id="modelsContainer" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
44
+ <!-- Model cards will be populated here -->
45
+ </div>
46
+ </section>
47
+ </main>
48
+
49
+ <custom-footer></custom-footer>
50
+
51
+ <script src="components/header.js"></script>
52
+ <script src="components/footer.js"></script>
53
+ <script src="script.js"></script>
54
+ <script>feather.replace();</script>
55
+ <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
56
+ </body>
57
+ </html>
script.js ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ document.addEventListener('DOMContentLoaded', function() {
2
+ const apiKeyInput = document.getElementById('apiKey');
3
+ const ageVerification = document.getElementById('ageVerification');
4
+ const unlockBtn = document.getElementById('unlockBtn');
5
+ const modelsSection = document.getElementById('modelsSection');
6
+ const modelsContainer = document.getElementById('modelsContainer');
7
+
8
+ // Check if API key is stored in localStorage
9
+ const storedApiKey = localStorage.getItem('civitaiApiKey');
10
+ if (storedApiKey) {
11
+ apiKeyInput.value = storedApiKey;
12
+ }
13
+
14
+ unlockBtn.addEventListener('click', async function() {
15
+ const apiKey = apiKeyInput.value.trim();
16
+ const isVerified = ageVerification.checked;
17
+
18
+ if (!apiKey) {
19
+ alert('Please enter your CivitAI API key');
20
+ return;
21
+ }
22
+
23
+ if (!isVerified) {
24
+ alert('Please verify your age to proceed');
25
+ return;
26
+ }
27
+
28
+ // Store API key in localStorage
29
+ localStorage.setItem('civitaiApiKey', apiKey);
30
+
31
+ // Show loading state
32
+ unlockBtn.innerHTML = '<svg class="animate-spin -ml-1 mr-2 h-4 w-4 text-white inline" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="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> Loading...';
33
+ unlockBtn.disabled = true;
34
+
35
+ try {
36
+ // Fetch models from CivitAI API
37
+ const response = await fetch('https://civitai.com/api/v1/models?limit=6', {
38
+ headers: {
39
+ 'Authorization': `Bearer ${apiKey}`
40
+ }
41
+ });
42
+
43
+ if (!response.ok) {
44
+ throw new Error('Invalid API key or network error');
45
+ }
46
+
47
+ const data = await response.json();
48
+ displayModels(data.items);
49
+
50
+ // Show models section
51
+ modelsSection.classList.remove('hidden');
52
+
53
+ // Scroll to models section
54
+ modelsSection.scrollIntoView({ behavior: 'smooth' });
55
+ } catch (error) {
56
+ alert('Error: ' + error.message);
57
+ } finally {
58
+ // Reset button
59
+ unlockBtn.textContent = 'Unlock Models';
60
+ unlockBtn.disabled = false;
61
+ }
62
+ });
63
+
64
+ function displayModels(models) {
65
+ modelsContainer.innerHTML = '';
66
+
67
+ models.forEach(model => {
68
+ const modelCard = document.createElement('div');
69
+ modelCard.className = 'model-card';
70
+
71
+ // Get first image or use placeholder
72
+ const imageUrl = model.images && model.images.length > 0 ?
73
+ model.images[0].url :
74
+ `http://static.photos/technology/320x240/${model.id}`;
75
+
76
+ modelCard.innerHTML = `
77
+ <img src="${imageUrl}" alt="${model.name}" class="model-image">
78
+ <div class="p-4">
79
+ <h3 class="font-bold text-lg mb-2">${model.name}</h3>
80
+ <p class="text-gray-400 text-sm mb-3 line-clamp-2">${model.description || 'No description available'}</p>
81
+ <div class="model-stats">
82
+ <i data-feather="download"></i>
83
+ <span>${model.downloads}</span>
84
+ <i data-feather="heart" class="ml-3"></i>
85
+ <span>${model.favorites}</span>
86
+ </div>
87
+ <div class="mt-3">
88
+ <span class="inline-block bg-green-500 text-xs px-2 py-1 rounded">${model.type}</span>
89
+ </div>
90
+ </div>
91
+ `;
92
+
93
+ modelsContainer.appendChild(modelCard);
94
+ });
95
+
96
+ // Reinitialize feather icons
97
+ feather.replace();
98
+ }
99
+ });
style.css CHANGED
@@ -1,28 +1,49 @@
1
- body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
 
 
 
 
 
 
 
 
 
 
 
 
4
  }
5
 
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
9
  }
10
 
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
  }
17
 
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
  }
25
 
26
- .card p:last-child {
27
- margin-bottom: 0;
 
28
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ /* Custom styles for model cards */
6
+ .model-card {
7
+ @apply bg-gray-800 rounded-xl shadow-lg overflow-hidden transition-transform duration-300 hover:scale-105;
8
+ }
9
+
10
+ .model-image {
11
+ @apply w-full h-48 object-cover;
12
+ }
13
+
14
+ .model-stats {
15
+ @apply flex items-center text-sm text-gray-400 mt-2;
16
  }
17
 
18
+ .model-stats svg {
19
+ @apply mr-1;
 
20
  }
21
 
22
+ /* Animation for loading spinner */
23
+ @keyframes spin {
24
+ to {
25
+ transform: rotate(360deg);
26
+ }
27
  }
28
 
29
+ .animate-spin {
30
+ animation: spin 1s linear infinite;
 
 
 
 
31
  }
32
 
33
+ /* Custom scrollbar */
34
+ ::-webkit-scrollbar {
35
+ width: 8px;
36
  }
37
+
38
+ ::-webkit-scrollbar-track {
39
+ background: #1f2937;
40
+ }
41
+
42
+ ::-webkit-scrollbar-thumb {
43
+ background: #4b5563;
44
+ border-radius: 4px;
45
+ }
46
+
47
+ ::-webkit-scrollbar-thumb:hover {
48
+ background: #6b7280;
49
+ }