mirror of
https://github.com/revanced/revanced-website.git
synced 2025-04-30 14:44:28 +02:00
feat: logo pages
This commit is contained in:
parent
6c4e30256b
commit
ff3ee24a98
@ -31,11 +31,17 @@ body {
|
|||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
width: min(90%, 95rem);
|
width: min(90%, 95rem);
|
||||||
margin-top: 4rem;
|
margin-top: 4rem;
|
||||||
|
padding-bottom: 2rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.wrapper {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--white: #fff;
|
--white: #fff;
|
||||||
|
@ -5,9 +5,10 @@
|
|||||||
export let maxWidth = false;
|
export let maxWidth = false;
|
||||||
export let icon = '';
|
export let icon = '';
|
||||||
export let target = '';
|
export let target = '';
|
||||||
|
export let unclickable = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<a {href} {target}>
|
<a {href} {target} on:click class:unclickable>
|
||||||
<div class={type} style="width: {maxWidth ? '100%' : 'max-content'}">
|
<div class={type} style="width: {maxWidth ? '100%' : 'max-content'}">
|
||||||
{#if icon}
|
{#if icon}
|
||||||
<img src="../icons/{icon}.svg" alt={icon} />
|
<img src="../icons/{icon}.svg" alt={icon} />
|
||||||
@ -22,6 +23,10 @@
|
|||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.unclickable {
|
||||||
|
pointer-events: none;
|
||||||
|
cursor:not-allowed;
|
||||||
|
}
|
||||||
div,
|
div,
|
||||||
.button-secondary {
|
.button-secondary {
|
||||||
min-width: max-content;
|
min-width: max-content;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let name: string;
|
export let name: string;
|
||||||
export let logo: string;
|
export let logo: string;
|
||||||
export let file: string;
|
export let filename: string;
|
||||||
export let id: string;
|
export let id: string;
|
||||||
export let selected: Array<string>;
|
export let selected: Array<string>;
|
||||||
|
export let clicked = false;
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
clicked = !clicked;
|
clicked = !clicked;
|
||||||
@ -15,16 +16,16 @@
|
|||||||
// the Updater
|
// the Updater
|
||||||
selected = selected;
|
selected = selected;
|
||||||
}
|
}
|
||||||
|
console.log(selected)
|
||||||
};
|
};
|
||||||
|
|
||||||
let clicked = false;
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div on:click={handleClick} class:clicked>
|
<div on:click={handleClick} class:clicked>
|
||||||
<img src={logo} alt={file} />
|
<img src={logo} alt={filename} />
|
||||||
<span class="text">
|
<span class="text">
|
||||||
<h2>{name}</h2>
|
<h2>{name}</h2>
|
||||||
<h6>{file}</h6>
|
<h6>{filename}</h6>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -69,8 +70,8 @@
|
|||||||
color: var(--accent-color);
|
color: var(--accent-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
div:hover:not(.clicked) {
|
div:hover {
|
||||||
background-color: var(--grey-two);
|
filter: brightness(0.85);
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
#markup-content {
|
|
||||||
/* Defaults for text */
|
|
||||||
color: var(--white);
|
|
||||||
font-weight: 300;
|
|
||||||
font-size: 1rem;
|
|
||||||
letter-spacing: 0.02rem;
|
|
||||||
padding: 100px 30px 0px 30px;
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: var(--white);
|
|
||||||
border-bottom: 1.5px solid var(--accent-color);
|
|
||||||
padding: 0px 5px;
|
|
||||||
transition: all 0.4s var(--bezier-one);
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
background-color: var(--accent-color);
|
|
||||||
border-radius: 6px;
|
|
||||||
color: var(--grey-four);
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
background-color: var(--grey-six);
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h5 {
|
|
||||||
color: var(--accent-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Markup processors output this for bold text, but css spec is goofy aah */
|
|
||||||
strong {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
padding-left: 2rem;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,210 +0,0 @@
|
|||||||
import { is_tree } from './documentation.shared';
|
|
||||||
import type { Document, DocsTree, DocsTreeNode, DocumentInfo } from './documentation.shared';
|
|
||||||
|
|
||||||
import { browser, prerendering } from '$app/environment';
|
|
||||||
|
|
||||||
import fs, { existsSync as exists } from 'fs';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
|
|
||||||
import { parse as parse_md } from 'marked';
|
|
||||||
import AsciiDocProcessor from 'asciidoctor'
|
|
||||||
|
|
||||||
// This file does not work in a browser.
|
|
||||||
if (browser) {
|
|
||||||
throw Error('SvelteKit has skill issues');
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constants
|
|
||||||
|
|
||||||
const supported_formats: Map<string, (markup: string) => Document> = new Map();
|
|
||||||
|
|
||||||
supported_formats.set("md", markup => {
|
|
||||||
let lines = markup.split('\n');
|
|
||||||
|
|
||||||
// Get and remove the first line.
|
|
||||||
const first_line = lines.splice(0, 1)[0];
|
|
||||||
// Remove `# `.
|
|
||||||
const title = first_line.substring(2);
|
|
||||||
|
|
||||||
// Convert the rest to html
|
|
||||||
const content = parse_md(lines.join('\n'));
|
|
||||||
|
|
||||||
return { title, content };
|
|
||||||
});
|
|
||||||
|
|
||||||
const asciidoctor = AsciiDocProcessor();
|
|
||||||
const adoc_fn = markup => {
|
|
||||||
// Get first line.
|
|
||||||
const first_line = markup.split('\n')[0];
|
|
||||||
// Remove `= `.
|
|
||||||
const title = first_line.substring(2);
|
|
||||||
|
|
||||||
// Convert it to html. Unlike markdown, we do not need to remove the first title heading.
|
|
||||||
// NOTE: Maybe consider change the safe mode value.
|
|
||||||
const content = asciidoctor.convert(markup, { doctype: "book" })
|
|
||||||
|
|
||||||
return { title, content };
|
|
||||||
}
|
|
||||||
|
|
||||||
supported_formats.set("adoc", adoc_fn)
|
|
||||||
supported_formats.set("asciidoc", adoc_fn)
|
|
||||||
|
|
||||||
const supported_filetypes = [...supported_formats.keys()];
|
|
||||||
|
|
||||||
let docs_folder = process.env.REVANCED_DOCS_FOLDER;
|
|
||||||
if (docs_folder === undefined) {
|
|
||||||
if (prerendering) { console.warn("Using testing docs in production build") }
|
|
||||||
docs_folder = "testing-docs";
|
|
||||||
}
|
|
||||||
|
|
||||||
const ignored_items = ["assets"];
|
|
||||||
|
|
||||||
/// Utility functions
|
|
||||||
|
|
||||||
function is_directory(item: string) {
|
|
||||||
return fs.lstatSync(item).isDirectory();
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_ext(fname: string) {
|
|
||||||
// Get extname and remove the first dot.
|
|
||||||
return path.extname(fname).substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_slug_of_node(node: DocsTreeNode): string {
|
|
||||||
if (is_tree(node)) {
|
|
||||||
return node.index.slug;
|
|
||||||
}
|
|
||||||
|
|
||||||
return node.slug;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Important functions
|
|
||||||
|
|
||||||
// Get a document. Returns null if it does not exist.
|
|
||||||
export function get(slug: string): Document|null {
|
|
||||||
let target = path.join(docs_folder, slug);
|
|
||||||
// Handle index (readme) file for folder.
|
|
||||||
if (exists(target) && is_directory(target)) {
|
|
||||||
target += "/README";
|
|
||||||
}
|
|
||||||
|
|
||||||
const dir = path.dirname(target);
|
|
||||||
if (!exists(dir)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let full_path, ext, found = false;
|
|
||||||
// We are looking for the file `${target}.(any_supported_extension)`. Try to find it.
|
|
||||||
for (const item of fs.readdirSync(dir)) {
|
|
||||||
full_path = path.join(dir, item);
|
|
||||||
// Get file extension
|
|
||||||
ext = get_ext(item);
|
|
||||||
|
|
||||||
// Unsupported/unrelated file.
|
|
||||||
if (!supported_formats.has(ext)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const desired_path = `${target}.${ext}`; // Don't grab some other random supported file.
|
|
||||||
if (!is_directory(full_path) && desired_path == full_path) {
|
|
||||||
// We found it.
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the file and return.
|
|
||||||
return supported_formats.get(ext)(fs.readFileSync(full_path, 'utf-8'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get file information
|
|
||||||
function process_file(fname: string): DocumentInfo {
|
|
||||||
// Remove docs folder prefix and file extension suffix, then split it.
|
|
||||||
const parts = fname
|
|
||||||
.substring(`${docs_folder}/`.length, fname.length - (get_ext(fname).length + 1))
|
|
||||||
.split("/");
|
|
||||||
|
|
||||||
// Remove `README` suffix if present.
|
|
||||||
const last_part_index = parts.length - 1;
|
|
||||||
if (parts[last_part_index] == "README") {
|
|
||||||
parts.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
const slug = parts.join("/");
|
|
||||||
const title = get(slug).title;
|
|
||||||
|
|
||||||
return { slug, title };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a document tree.
|
|
||||||
function process_folder(dir: string): DocsTree|null {
|
|
||||||
let tree: DocsTree = {
|
|
||||||
index: null,
|
|
||||||
nodes: []
|
|
||||||
};
|
|
||||||
|
|
||||||
// List everything in the directory.
|
|
||||||
const items = fs.readdirSync(dir);
|
|
||||||
|
|
||||||
for (const item of items) {
|
|
||||||
if (ignored_items.includes(item) || [".", "_"].includes(item[0])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const itemPath = path.join(dir, item);
|
|
||||||
|
|
||||||
const is_dir = is_directory(itemPath);
|
|
||||||
let is_index_file = false;
|
|
||||||
|
|
||||||
if (!is_dir) {
|
|
||||||
// Ignore files we cannot process.
|
|
||||||
if (!supported_formats.has(get_ext(item))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const ext of supported_filetypes) {
|
|
||||||
if (item == `README.${ext}`) {
|
|
||||||
is_index_file = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const node = is_dir ? process_folder(itemPath) : process_file(itemPath);
|
|
||||||
if (node === null) {
|
|
||||||
console.error(`The ${itemPath} directory does not have a README/index file! ignoring...`)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_index_file) {
|
|
||||||
tree.index = node;
|
|
||||||
} else {
|
|
||||||
tree.nodes.push(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tree.index === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// `numeric: true` because we want to be able to specify
|
|
||||||
// the order if necessary by prepending a number to the file name.
|
|
||||||
tree.nodes.sort(
|
|
||||||
(a, b) => get_slug_of_node(a).localeCompare(get_slug_of_node(b), "en", { numeric: true })
|
|
||||||
);
|
|
||||||
|
|
||||||
return tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the document tree.
|
|
||||||
export function index_content(): DocsTree {
|
|
||||||
const tree = process_folder(docs_folder);
|
|
||||||
if (tree === null) {
|
|
||||||
throw new Error("Root must have index (README) file.")
|
|
||||||
}
|
|
||||||
return tree;
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
/// Types
|
|
||||||
|
|
||||||
export interface Document {
|
|
||||||
title: string;
|
|
||||||
// HTML
|
|
||||||
content: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DocumentInfo {
|
|
||||||
title: string;
|
|
||||||
slug: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A tree representing the `docs` folder.
|
|
||||||
export interface DocsTree {
|
|
||||||
// index.whatever
|
|
||||||
index: DocumentInfo;
|
|
||||||
// Everything except index.whatever
|
|
||||||
nodes: DocsTreeNode[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export type DocsTreeNode = DocsTree | DocumentInfo;
|
|
||||||
|
|
||||||
/// Functions
|
|
||||||
|
|
||||||
export function is_tree(node: DocsTreeNode) {
|
|
||||||
return node.hasOwnProperty('nodes');
|
|
||||||
}
|
|
@ -1,13 +1,16 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fly } from 'svelte/transition';
|
|
||||||
import { quintOut } from 'svelte/easing';
|
|
||||||
|
|
||||||
import LogoOption from '$lib/components/atoms/LogoOption.svelte';
|
import LogoOption from '$lib/components/atoms/LogoOption.svelte';
|
||||||
import Button from '$lib/components/atoms/Button.svelte';
|
import Button from '$lib/components/atoms/Button.svelte';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
let selected: Array<string> = [];
|
let selected: Array<string> = [];
|
||||||
let logos = [];
|
let logos = [];
|
||||||
|
let currentPage = 1;
|
||||||
|
let maxPages = 1;
|
||||||
|
let logoAmount = 4;
|
||||||
|
let min = 0;
|
||||||
|
let max = logoAmount;
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
const response = await fetch('https://poll.revanced.app/logos');
|
const response = await fetch('https://poll.revanced.app/logos');
|
||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
@ -17,38 +20,49 @@
|
|||||||
}
|
}
|
||||||
// update ui
|
// update ui
|
||||||
logos = logos;
|
logos = logos;
|
||||||
|
maxPages = Math.floor(logos.length / logoAmount);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function previousPage() {
|
||||||
|
min -= logoAmount;
|
||||||
|
max -= logoAmount;
|
||||||
|
currentPage--;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextPage() {
|
||||||
|
min += logoAmount;
|
||||||
|
max += logoAmount;
|
||||||
|
currentPage++;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>ReVanced | Contributors</title>
|
<title>ReVanced · Logo Poll</title>
|
||||||
<meta content="ReVanced | Contributors" name="og:title" />
|
<meta content="ReVanced · Logo Poll" name="og:title" />
|
||||||
<meta content="ReVanced | Contributors" name="twitter:title" />
|
<meta content="ReVanced · Logo Poll" name="twitter:title" />
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div class="top-container">
|
<div class="top-container">
|
||||||
<h1>ReVanced Logo Poll</h1>
|
<h1>ReVanced Logo Poll</h1>
|
||||||
<h2>{selected.length}/4 selected· Page 1/6</h2>
|
<h2>{selected.length}/4 selected· Page {currentPage}/{maxPages}</h2>
|
||||||
<div class="top-custom-button-container">
|
<div class="top-custom-button-container">
|
||||||
<button>Help</button>
|
<a href="https://hhh.com" target="_blank" rel="noreferrer"><button>Help</button></a>
|
||||||
<button>Website</button>
|
<a href="https://revanced.app" target="_blank" rel="noreferrer"><button>Website</button></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="options-grid">
|
<div class="options-grid">
|
||||||
{#if logos.length > 0}
|
{#each logos.slice(min, max) as { id, gdrive_direct_url, name, filename }}
|
||||||
<LogoOption bind:selected id={logos[0].id} logo={logos[0].gdrive_direct_url} name={logos[0].name} file={logos[0].filename}/>
|
{#key currentPage}
|
||||||
<LogoOption bind:selected id={logos[1].id} logo={logos[1].gdrive_direct_url} name={logos[1].name} file={logos[1].filename}/>
|
<LogoOption bind:selected clicked={selected.includes(id)} {id} logo={gdrive_direct_url} {name} {filename} />
|
||||||
<LogoOption bind:selected id={logos[2].id} logo={logos[2].gdrive_direct_url} name={logos[2].name} file={logos[2].filename}/>
|
{/key}
|
||||||
<LogoOption bind:selected id={logos[3].id} logo={logos[3].gdrive_direct_url} name={logos[3].name} file={logos[3].filename}/>
|
{/each}
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="buttons-container">
|
<div class="buttons-container">
|
||||||
<Button>Previous</Button>
|
<Button on:click={previousPage} unclickable={currentPage <= 1}>Previous</Button>
|
||||||
<Button kind="primary" href="https://next.com">Next</Button>
|
<Button kind="primary" on:click={nextPage} unclickable={currentPage >= maxPages}>Next</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
@ -69,7 +83,6 @@
|
|||||||
color: var(--grey-four);
|
color: var(--grey-four);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: var(--grey-three);
|
color: var(--grey-three);
|
||||||
@ -84,10 +97,9 @@
|
|||||||
float: bottom;
|
float: bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
button {
|
button {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border:none;
|
border: none;
|
||||||
border: 1px solid var(--grey-six);
|
border: 1px solid var(--grey-six);
|
||||||
color: var(--grey-four);
|
color: var(--grey-four);
|
||||||
padding: 0.5rem 1.25rem;
|
padding: 0.5rem 1.25rem;
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
# Prerequisites
|
|
||||||
##### docs/prerequisites
|
|
||||||
|
|
||||||
<br />
|
|
||||||
|
|
||||||
#### Requirements
|
|
||||||
|
|
||||||
- ADB
|
|
||||||
- x86/x86\_64 host architecture
|
|
||||||
- Zulu JDK 17
|
|
||||||
- Latest Android SDK if you plan to build the integrations from the source
|
|
||||||
- The APK file you want to patch (e.g. YouTube v17.36.37 or YouTube Music v5.23.50). If you want to mount patched applications as root, make sure the same version is installed on your device.
|
|
||||||
|
|
||||||
<br />
|
|
||||||
|
|
||||||
You can continue by either [building everything from source](https://github.com/revanced/revanced-documentation/wiki/Building-from-source) or [downloading the prebuilt packages](https://github.com/revanced/revanced-documentation/wiki/Downloading-prebuilt-packages).
|
|
@ -1,10 +0,0 @@
|
|||||||
= AsciiDoc Example
|
|
||||||
|
|
||||||
= Another title
|
|
||||||
|
|
||||||
*Bold text*
|
|
||||||
|
|
||||||
== Section 1
|
|
||||||
|
|
||||||
* Item 1
|
|
||||||
* Item 2
|
|
@ -1,4 +0,0 @@
|
|||||||
# Nesting sample
|
|
||||||
|
|
||||||
# First one
|
|
||||||
Text
|
|
@ -1,4 +0,0 @@
|
|||||||
# Another Page
|
|
||||||
|
|
||||||
# Hello
|
|
||||||
Content!
|
|
@ -1,4 +0,0 @@
|
|||||||
# Nesting sample
|
|
||||||
|
|
||||||
# Second one
|
|
||||||
Text
|
|
@ -1,4 +0,0 @@
|
|||||||
# Nesting sample
|
|
||||||
|
|
||||||
# Third one
|
|
||||||
Text
|
|
@ -1,4 +0,0 @@
|
|||||||
# Markdown Example
|
|
||||||
Text
|
|
||||||
|
|
||||||
**Bold text**
|
|
@ -1,9 +0,0 @@
|
|||||||
# Writing documentation
|
|
||||||
|
|
||||||
You can write documentation with markdown or asciidoc.
|
|
||||||
|
|
||||||
## Title
|
|
||||||
The first line must be the `h1` equivalent of the markup language.
|
|
||||||
For markdown, this would be `# <title>` and `= <title>` for asciidoc.
|
|
||||||
|
|
||||||
**The title part may or may not go through the markup processor depending on the language.** It is instead added by the website itself.
|
|
Loading…
x
Reference in New Issue
Block a user