mirror of
https://github.com/System-End/cdn.git
synced 2026-04-19 19:45:07 +00:00
more more more
This commit is contained in:
parent
bbf815cf30
commit
4619ba5944
9 changed files with 108 additions and 340 deletions
|
|
@ -36,6 +36,8 @@ class Components::Uploads::Row < Components::Base
|
|||
end
|
||||
|
||||
div(style: "display: flex; gap: 8px; align-items: center;") do
|
||||
render(Primer::Beta::ClipboardCopyButton.new(value: upload.cdn_url, size: :small, "aria-label": "Copy link")) { "Copy link" }
|
||||
|
||||
a(href: upload.cdn_url, target: "_blank", rel: "noopener", class: "btn btn-sm") do
|
||||
plain "View"
|
||||
end
|
||||
|
|
@ -51,7 +53,7 @@ class Components::Uploads::Row < Components::Base
|
|||
div(style: "font-size: 14px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;") do
|
||||
plain upload.filename.to_s
|
||||
end
|
||||
render(Primer::Beta::Label.new(scheme: :secondary, size: :small)) { plain upload.provenance.titleize }
|
||||
render(Primer::Beta::Label.new(scheme: :secondary)) { plain upload.provenance.titleize }
|
||||
end
|
||||
div(style: "font-size: 12px; color: var(--fgColor-muted, #656d76);") do
|
||||
plain "#{upload.human_file_size} • #{upload.content_type} • #{time_ago_in_words(upload.created_at)} ago"
|
||||
|
|
@ -59,6 +61,8 @@ class Components::Uploads::Row < Components::Base
|
|||
end
|
||||
|
||||
div(style: "display: flex; gap: 8px; align-items: center;") do
|
||||
render(Primer::Beta::ClipboardCopyButton.new(value: upload.cdn_url, size: :small, "aria-label": "Copy link")) { "Copy link" }
|
||||
|
||||
a(href: upload.cdn_url, target: "_blank", rel: "noopener", class: "btn btn-sm") do
|
||||
render Primer::Beta::Octicon.new(icon: :link, mr: 1)
|
||||
plain "View"
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ class Components::Uploads::Index < Components::Base
|
|||
end
|
||||
|
||||
def view_template
|
||||
dropzone_form
|
||||
div(style: "max-width: 1200px; margin: 0 auto; padding: 24px;") do
|
||||
header_section
|
||||
search_section
|
||||
|
|
@ -34,7 +35,7 @@ class Components::Uploads::Index < Components::Base
|
|||
end
|
||||
end
|
||||
|
||||
link_to new_upload_path, class: "btn btn-primary" do
|
||||
label(for: "dropzone-file-input", class: "btn btn-primary", style: "cursor: pointer;") do
|
||||
render Primer::Beta::Octicon.new(icon: :upload, mr: 1)
|
||||
plain "Upload File"
|
||||
end
|
||||
|
|
@ -43,18 +44,20 @@ class Components::Uploads::Index < Components::Base
|
|||
|
||||
def search_section
|
||||
div(style: "margin-bottom: 24px;") do
|
||||
form_with url: uploads_path, method: :get, style: "display: flex; gap: 8px;" do
|
||||
input(
|
||||
type: "search",
|
||||
name: "query",
|
||||
placeholder: "Search files...",
|
||||
value: query,
|
||||
class: "form-control",
|
||||
style: "flex: 1; max-width: 400px;"
|
||||
)
|
||||
button(type: "submit", class: "btn") do
|
||||
render Primer::Beta::Octicon.new(icon: :search, mr: 1)
|
||||
plain "Search"
|
||||
form_with url: uploads_path, method: :get do
|
||||
div(style: "display: flex; gap: 12px;") do
|
||||
input(
|
||||
type: "search",
|
||||
name: "query",
|
||||
placeholder: "Search files...",
|
||||
value: query,
|
||||
class: "form-control",
|
||||
style: "flex: 1; max-width: 400px;"
|
||||
)
|
||||
button(type: "submit", class: "btn") do
|
||||
render Primer::Beta::Octicon.new(icon: :search, mr: 1)
|
||||
plain "Search"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -76,17 +79,15 @@ class Components::Uploads::Index < Components::Base
|
|||
|
||||
def empty_state
|
||||
render Primer::Beta::Blankslate.new(border: true) do |component|
|
||||
component.with_visual_icon(icon: :inbox)
|
||||
component.with_visual_icon(icon: query.present? ? :search : :upload, size: :medium)
|
||||
component.with_heading(tag: :h2) do
|
||||
query.present? ? "No files found" : "No uploads yet"
|
||||
query.present? ? "No files found" : "Drop files here"
|
||||
end
|
||||
component.with_description do
|
||||
query.present? ? "Try a different search query" : "Upload your first file to get started"
|
||||
end
|
||||
unless query.present?
|
||||
component.with_primary_action(href: new_upload_path) do
|
||||
render Primer::Beta::Octicon.new(icon: :upload, mr: 1)
|
||||
plain "Upload File"
|
||||
if query.present?
|
||||
"Try a different search query"
|
||||
else
|
||||
"Drag and drop files anywhere on this page, or use the Upload button"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -97,4 +98,10 @@ class Components::Uploads::Index < Components::Base
|
|||
paginate uploads
|
||||
end
|
||||
end
|
||||
|
||||
def dropzone_form
|
||||
form_with url: uploads_path, method: :post, multipart: true, data: { dropzone_form: true } do
|
||||
input(type: "file", name: "file", id: "dropzone-file-input", data: { dropzone_input: true }, style: "display: none;")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,88 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Components::Uploads::New < Components::Base
|
||||
include Phlex::Rails::Helpers::FormWith
|
||||
include Phlex::Rails::Helpers::LinkTo
|
||||
|
||||
def view_template
|
||||
div(style: "max-width: 1200px; margin: 0 auto; padding: 24px;") do
|
||||
header_section
|
||||
upload_form
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def header_section
|
||||
header(style: "margin-bottom: 32px;") do
|
||||
div(style: "display: flex; align-items: center; gap: 8px; margin-bottom: 16px;") do
|
||||
link_to uploads_path, style: "color: var(--fgColor-muted, #656d76); text-decoration: none;" do
|
||||
render Primer::Beta::Octicon.new(icon: :"arrow-left")
|
||||
end
|
||||
h1(style: "font-size: 2rem; font-weight: 600; margin: 0;") { "Upload File" }
|
||||
end
|
||||
p(style: "color: var(--fgColor-muted, #656d76); margin: 0; font-size: 14px;") do
|
||||
plain "Drop a file anywhere on this page or click to browse"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def upload_form
|
||||
form_with url: uploads_path, method: :post, multipart: true, data: { dropzone_form: true } do
|
||||
div(
|
||||
class: "upload-area",
|
||||
style: upload_area_styles
|
||||
) do
|
||||
div(style: "text-align: center;") do
|
||||
render Primer::Beta::Octicon.new(icon: :upload, size: :medium)
|
||||
h2(style: "font-size: 32px; font-weight: 600; margin: 24px 0 16px;") { "Drag & Drop" }
|
||||
p(style: "color: var(--fgColor-muted, #656d76); margin: 0 0 32px; font-size: 16px;") do
|
||||
plain "Drop a file anywhere on this page to upload instantly"
|
||||
end
|
||||
|
||||
label(
|
||||
for: "file-input",
|
||||
class: "btn btn-primary btn-large",
|
||||
style: "cursor: pointer; display: inline-block; font-size: 16px; padding: 12px 24px;"
|
||||
) do
|
||||
render Primer::Beta::Octicon.new(icon: :file, mr: 2)
|
||||
plain "Choose File"
|
||||
end
|
||||
|
||||
input(
|
||||
type: "file",
|
||||
name: "file",
|
||||
id: "file-input",
|
||||
data: { dropzone_input: true },
|
||||
style: "display: none;"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
render Primer::Beta::BorderBox.new(mt: 5) do |box|
|
||||
box.with_header do
|
||||
h3(style: "font-size: 16px; font-weight: 600; margin: 0;") { "How it works" }
|
||||
end
|
||||
box.with_body do
|
||||
ul(style: "margin: 0; padding-left: 24px; font-size: 14px; color: var(--fgColor-muted, #656d76); line-height: 1.8;") do
|
||||
li { "Drag and drop a file anywhere on this page for instant upload" }
|
||||
li { "Or click the button above to browse and select a file" }
|
||||
li { "Files are stored securely and accessible via CDN URLs" }
|
||||
li { "Supports images, videos, documents, and more" }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def upload_area_styles
|
||||
<<~CSS.strip
|
||||
border: 3px dashed var(--borderColor-default, #d0d7de);
|
||||
border-radius: 16px;
|
||||
padding: 96px 48px;
|
||||
background: var(--bgColor-default, #fff);
|
||||
text-align: center;
|
||||
transition: all 0.2s ease;
|
||||
CSS
|
||||
end
|
||||
end
|
||||
|
|
@ -13,14 +13,11 @@ class UploadsController < ApplicationController
|
|||
@uploads = @uploads.page(params[:page]).per(50)
|
||||
end
|
||||
|
||||
def new
|
||||
end
|
||||
|
||||
def create
|
||||
uploaded_file = params[:file]
|
||||
|
||||
if uploaded_file.blank?
|
||||
redirect_to new_upload_path, alert: "Please select a file to upload."
|
||||
redirect_to uploads_path, alert: "Please select a file to upload."
|
||||
return
|
||||
end
|
||||
|
||||
|
|
@ -37,7 +34,7 @@ class UploadsController < ApplicationController
|
|||
|
||||
redirect_to uploads_path, notice: "File uploaded successfully!"
|
||||
rescue StandardError => e
|
||||
redirect_to new_upload_path, alert: "Upload failed: #{e.message}"
|
||||
redirect_to uploads_path, alert: "Upload failed: #{e.message}"
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
|
|
|||
|
|
@ -2,26 +2,31 @@
|
|||
let dropzone;
|
||||
let counter = 0;
|
||||
let fileInput, form;
|
||||
let initialized = false;
|
||||
|
||||
function init() {
|
||||
const formElement = document.querySelector("[data-dropzone-form]");
|
||||
if (!formElement) {
|
||||
fileInput = null;
|
||||
form = null;
|
||||
initialized = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (initialized && form === formElement) return;
|
||||
|
||||
form = formElement;
|
||||
fileInput = form.querySelector("[data-dropzone-input]");
|
||||
|
||||
if (!fileInput) return;
|
||||
|
||||
initialized = true;
|
||||
|
||||
// Handle file input change
|
||||
fileInput.addEventListener("change", (e) => {
|
||||
const file = e.target.files[0];
|
||||
if (file) {
|
||||
// Auto-submit on file selection
|
||||
form.submit();
|
||||
form.requestSubmit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -61,8 +66,7 @@
|
|||
const files = e.dataTransfer.files;
|
||||
if (files.length > 0) {
|
||||
fileInput.files = files;
|
||||
// Auto-submit on drop
|
||||
form.submit();
|
||||
form.requestSubmit();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -96,10 +100,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Initialize
|
||||
// Initialize on first load
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
|
||||
// Re-initialize on Turbo navigations
|
||||
document.addEventListener("turbo:load", init);
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -4,198 +4,69 @@ icon: code
|
|||
order: 3
|
||||
---
|
||||
|
||||
# API Documentation 🔧
|
||||
# API Documentation
|
||||
|
||||
Want to upload files programmatically? You've come to the right place! Our API lets you integrate CDN uploads directly into your apps.
|
||||
Upload images programmatically using the CDN API.
|
||||
|
||||
## Authentication
|
||||
|
||||
First, you'll need an API key! Head over to [API Keys](/api_keys) to create one.
|
||||
Create an API key at [API Keys](/api_keys). Keys are shown once, so copy it immediately.
|
||||
|
||||
Your API key will look something like this:
|
||||
Include the key in the `Authorization` header:
|
||||
|
||||
```
|
||||
sk_cdn_a1b2c3d4e5f6...
|
||||
```
|
||||
|
||||
**Important**: Copy it immediately after creation—you won't be able to see it again.
|
||||
|
||||
### Using Your API Key
|
||||
|
||||
Include your API key in the `Authorization` header with the `Bearer` prefix:
|
||||
|
||||
```bash
|
||||
Authorization: Bearer sk_cdn_your_key_here
|
||||
```
|
||||
|
||||
## Endpoints
|
||||
## POST /api/v4/upload
|
||||
|
||||
### GET /api/v4/me
|
||||
|
||||
Get information about the currently authenticated user!
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "usr_abc123",
|
||||
"email": "cat@hackclub.com",
|
||||
"name": "Cool Cat"
|
||||
}
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
|
||||
#### cURL
|
||||
|
||||
```bash
|
||||
curl -H "Authorization: Bearer sk_cdn_your_key_here" \
|
||||
https://cdn.hackclub.com/api/v4/me
|
||||
```
|
||||
|
||||
#### JavaScript
|
||||
|
||||
```javascript
|
||||
const response = await fetch('https://cdn.hackclub.com/api/v4/me', {
|
||||
headers: {
|
||||
'Authorization': 'Bearer sk_cdn_your_key_here'
|
||||
}
|
||||
});
|
||||
|
||||
const user = await response.json();
|
||||
console.log(user);
|
||||
```
|
||||
|
||||
#### Ruby
|
||||
|
||||
```ruby
|
||||
require 'faraday'
|
||||
require 'json'
|
||||
|
||||
conn = Faraday.new(url: 'https://cdn.hackclub.com')
|
||||
response = conn.get('/api/v4/me') do |req|
|
||||
req.headers['Authorization'] = 'Bearer sk_cdn_your_key_here'
|
||||
end
|
||||
|
||||
user = JSON.parse(response.body)
|
||||
puts user
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### POST /api/v4/upload
|
||||
|
||||
Upload a file directly! This endpoint accepts multipart form data.
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `file` (required): The file to upload
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "01234567-89ab-cdef-0123-456789abcdef",
|
||||
"filename": "cat.png",
|
||||
"size": 12345,
|
||||
"content_type": "image/png",
|
||||
"url": "https://cdn.hackclub.com/01234567-89ab-cdef-0123-456789abcdef/cat.png",
|
||||
"created_at": "2026-01-29T12:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
|
||||
#### cURL
|
||||
Upload a file via multipart form data.
|
||||
|
||||
```bash
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer sk_cdn_your_key_here" \
|
||||
-F "file=@/path/to/cat.png" \
|
||||
-F "file=@photo.jpg" \
|
||||
https://cdn.hackclub.com/api/v4/upload
|
||||
```
|
||||
|
||||
#### JavaScript
|
||||
|
||||
```javascript
|
||||
const formData = new FormData();
|
||||
formData.append('file', fileInput.files[0]);
|
||||
|
||||
const response = await fetch('https://cdn.hackclub.com/api/v4/upload', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': 'Bearer sk_cdn_your_key_here'
|
||||
},
|
||||
headers: { 'Authorization': 'Bearer sk_cdn_your_key_here' },
|
||||
body: formData
|
||||
});
|
||||
|
||||
const upload = await response.json();
|
||||
console.log('Uploaded to:', upload.url);
|
||||
const { url } = await response.json();
|
||||
```
|
||||
|
||||
#### Ruby
|
||||
|
||||
```ruby
|
||||
require 'faraday'
|
||||
require 'faraday/multipart'
|
||||
require 'json'
|
||||
|
||||
conn = Faraday.new(url: 'https://cdn.hackclub.com') do |f|
|
||||
f.request :multipart
|
||||
f.adapter Faraday.default_adapter
|
||||
end
|
||||
|
||||
response = conn.post('/api/v4/upload') do |req|
|
||||
req.headers['Authorization'] = 'Bearer sk_cdn_your_key_here'
|
||||
req.body = {
|
||||
file: Faraday::Multipart::FilePart.new(
|
||||
'/path/to/cat.png',
|
||||
'image/png'
|
||||
)
|
||||
}
|
||||
end
|
||||
|
||||
upload = JSON.parse(response.body)
|
||||
puts "Uploaded to: #{upload['url']}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### POST /api/v4/upload\_from\_url
|
||||
|
||||
Upload a file from a URL. Perfect for grabbing images from the internet.
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `url` (required): The URL of the file to upload
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "01234567-89ab-cdef-0123-456789abcdef",
|
||||
"filename": "image.jpg",
|
||||
"size": 54321,
|
||||
"filename": "photo.jpg",
|
||||
"size": 12345,
|
||||
"content_type": "image/jpeg",
|
||||
"url": "https://cdn.hackclub.com/01234567-89ab-cdef-0123-456789abcdef/image.jpg",
|
||||
"url": "https://cdn.hackclub.com/01234567-89ab-cdef-0123-456789abcdef/photo.jpg",
|
||||
"created_at": "2026-01-29T12:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
## POST /api/v4/upload\_from\_url
|
||||
|
||||
#### cURL
|
||||
Upload an image from a URL.
|
||||
|
||||
```bash
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer sk_cdn_your_key_here" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"url":"https://example.com/cat.jpg"}' \
|
||||
-d '{"url":"https://example.com/image.jpg"}' \
|
||||
https://cdn.hackclub.com/api/v4/upload_from_url
|
||||
```
|
||||
|
||||
#### JavaScript
|
||||
|
||||
```javascript
|
||||
const response = await fetch('https://cdn.hackclub.com/api/v4/upload_from_url', {
|
||||
method: 'POST',
|
||||
|
|
@ -203,48 +74,37 @@ const response = await fetch('https://cdn.hackclub.com/api/v4/upload_from_url',
|
|||
'Authorization': 'Bearer sk_cdn_your_key_here',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
url: 'https://example.com/cat.jpg'
|
||||
})
|
||||
body: JSON.stringify({ url: 'https://example.com/image.jpg' })
|
||||
});
|
||||
|
||||
const upload = await response.json();
|
||||
console.log('Uploaded to:', upload.url);
|
||||
const { url } = await response.json();
|
||||
```
|
||||
|
||||
#### Ruby
|
||||
## GET /api/v4/me
|
||||
|
||||
```ruby
|
||||
require 'faraday'
|
||||
require 'json'
|
||||
Get the authenticated user.
|
||||
|
||||
conn = Faraday.new(url: 'https://cdn.hackclub.com')
|
||||
response = conn.post('/api/v4/upload_from_url') do |req|
|
||||
req.headers['Authorization'] = 'Bearer sk_cdn_your_key_here'
|
||||
req.headers['Content-Type'] = 'application/json'
|
||||
req.body = { url: 'https://example.com/cat.jpg' }.to_json
|
||||
end
|
||||
|
||||
upload = JSON.parse(response.body)
|
||||
puts "Uploaded to: #{upload['url']}"
|
||||
```bash
|
||||
curl -H "Authorization: Bearer sk_cdn_your_key_here" \
|
||||
https://cdn.hackclub.com/api/v4/me
|
||||
```
|
||||
|
||||
---
|
||||
```json
|
||||
{
|
||||
"id": "usr_abc123",
|
||||
"email": "you@hackclub.com",
|
||||
"name": "Your Name"
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
## Errors
|
||||
|
||||
When something goes wrong, you'll get an error response with details.
|
||||
|
||||
**Status Codes:**
|
||||
|
||||
- `200 OK` - Success!
|
||||
- `201 Created` - File uploaded successfully
|
||||
- `400 Bad Request` - Missing required parameters
|
||||
- `401 Unauthorized` - Invalid or missing API key
|
||||
- `404 Not Found` - Resource not found
|
||||
- `422 Unprocessable Entity` - Validation failed
|
||||
|
||||
**Error Response Format:**
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| 400 | Missing required parameters |
|
||||
| 401 | Invalid or missing API key |
|
||||
| 404 | Resource not found |
|
||||
| 422 | Validation failed |
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
@ -252,26 +112,7 @@ When something goes wrong, you'll get an error response with details.
|
|||
}
|
||||
```
|
||||
|
||||
Or with validation details:
|
||||
## Help
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "Validation failed",
|
||||
"details": ["Name can't be blank"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
Be nice to our servers. While we don't enforce strict rate limits yet, please use the API responsibly.
|
||||
|
||||
## Need Help?
|
||||
|
||||
Got questions? Found a bug? Let us know!
|
||||
|
||||
- Join the [#cdn channel on Slack](https://hackclub.enterprise.slack.com/archives/C016DEDUL87)
|
||||
- Open an issue on [GitHub](https://github.com/hackclub/cdn/issues)
|
||||
|
||||
Happy uploading!
|
||||
- [#cdn-dev on Slack](https://hackclub.slack.com/archives/C08RYDPS36V)
|
||||
- [GitHub Issues](https://github.com/hackclub/cdn/issues)
|
||||
|
|
|
|||
|
|
@ -6,38 +6,39 @@ order: 1
|
|||
|
||||
# Getting Started
|
||||
|
||||
Welcome to Hack Club CDN. This guide will help you get started with file hosting.
|
||||
Hack Club CDN is image hosting for your HTML pages. Upload files, get permanent URLs, embed them anywhere.
|
||||
|
||||
## Sign In
|
||||
|
||||
Click the **Sign in with Hack Club** button on the homepage to authenticate with your Hack Club account.
|
||||
Click **Sign in with Hack Club** on the homepage to authenticate.
|
||||
|
||||
## Uploading Files
|
||||
## Upload an Image
|
||||
|
||||
Once you're logged in:
|
||||
1. Go to **My Files**
|
||||
2. Drag and drop images or click **Upload**
|
||||
3. Copy the URL
|
||||
|
||||
1. Navigate to **My Files**
|
||||
2. Click **Upload** or drag and drop files
|
||||
3. Your file receives a permanent URL
|
||||
## Use in HTML
|
||||
|
||||
## Sharing Files
|
||||
|
||||
Every uploaded file gets a unique URL you can share anywhere:
|
||||
|
||||
```
|
||||
https://cdn.hackclub.com/your-file-id
|
||||
```html
|
||||
<img src="https://cdn.hackclub.com/019505e2-c85b-7f80-9c31-4b2e5a8d9f12/photo.jpg" alt="My image">
|
||||
```
|
||||
|
||||
## File Limits
|
||||
## Use in Markdown
|
||||
|
||||
- Maximum file size: varies by account
|
||||
- Supported formats: images, documents, archives, and more
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||
## API Usage
|
||||
## Hotlinking
|
||||
|
||||
For programmatic uploads, check out the [API documentation](/docs/api).
|
||||
URLs work everywhere—GitHub READMEs, Notion, Discord, Slack, personal websites, etc.
|
||||
|
||||
## Programmatic Uploads
|
||||
|
||||
Need to upload from code? See the [API documentation](/docs/api).
|
||||
|
||||
## Need Help?
|
||||
|
||||
- Join the [#cdn-dev channel on Slack](https://hackclub.slack.com/archives/C08RYDPS36V)
|
||||
- Open an issue on [GitHub](https://github.com/hackclub/cdn/issues)
|
||||
- [#cdn-dev on Slack](https://hackclub.slack.com/archives/C08RYDPS36V)
|
||||
- [GitHub Issues](https://github.com/hackclub/cdn/issues)
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
<%= render Components::Uploads::New.new %>
|
||||
|
|
@ -13,7 +13,7 @@ Rails.application.routes.draw do
|
|||
get "/auth/hack_club/callback", to: "sessions#create"
|
||||
get "/auth/failure", to: "sessions#failure"
|
||||
|
||||
resources :uploads, only: [:index, :new, :create, :destroy]
|
||||
resources :uploads, only: [:index, :create, :destroy]
|
||||
|
||||
resources :api_keys, only: [:index, :create, :destroy]
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue