diff --git a/assets/tailwind.config.js b/assets/tailwind.config.js index 234eb0db3..99441e3c4 100644 --- a/assets/tailwind.config.js +++ b/assets/tailwind.config.js @@ -14,6 +14,7 @@ module.exports = { "../lib/*_web.ex", "../lib/*_web/**/*.*ex", "./svelte/**/*.svelte", + "../priv/content/**/*.md", ], theme: { container: { diff --git a/config/config.exs b/config/config.exs index f472f3ed6..7555d7bdd 100644 --- a/config/config.exs +++ b/config/config.exs @@ -16,6 +16,7 @@ config :algora, redirects: [ {"/tv", "https://tv.algora.io"}, {"/discord", "https://discord.gg/9RXD2nqbnG"}, + {"/docs/bounties/payments", "/docs/payments"}, {"/sdk", "https://github.com/algora-io/sdk"}, {"/healthcare", "https://blog.algora.io/post/healthcare"}, {"/podcast", "https://www.youtube.com/@algora-io/podcasts"}, diff --git a/lib/algora/bot_templates/bot_templates.ex b/lib/algora/bot_templates/bot_templates.ex index bbd891d6c..c2c959c61 100644 --- a/lib/algora/bot_templates/bot_templates.ex +++ b/lib/algora/bot_templates/bot_templates.ex @@ -10,7 +10,7 @@ defmodule Algora.BotTemplates do ### Steps to solve: 1. **Start working**: Comment `/attempt #${ISSUE_NUMBER}` with your implementation plan 2. **Submit work**: Create a pull request including `/claim #${ISSUE_NUMBER}` in the PR body to claim the bounty - 3. **Receive payment**: 100% of the bounty is received 2-5 days post-reward. [Make sure you are eligible for payouts](https://docs.algora.io/bounties/payments#supported-countries-regions) + 3. **Receive payment**: 100% of the bounty is received 2-5 days post-reward. [Make sure you are eligible for payouts](https://algora.io/docs/payments#supported-countries-regions) Thank you for contributing to ${REPO_FULL_NAME}! ${ATTEMPTS} diff --git a/lib/algora/content.ex b/lib/algora/content.ex index a8d48d15f..254394432 100644 --- a/lib/algora/content.ex +++ b/lib/algora/content.ex @@ -5,7 +5,7 @@ defmodule Algora.Content do alias Algora.Markdown - defstruct [:slug, :title, :date, :tags, :authors, :content] + defstruct [:slug, :title, :date, :tags, :authors, :content, :path] defp base_path, do: Path.join([:code.priv_dir(:algora), "content"]) @@ -38,6 +38,57 @@ defmodule Algora.Content do |> Enum.sort_by(& &1.date, :desc) end + def list_content_rec(directory) do + list_content_rec_helper([base_path(), directory], directory) + end + + defp list_content_rec_helper(path, root_dir) do + case File.ls(Path.join(path)) do + {:ok, entries} -> + entries + |> Enum.reduce(%{files: [], dirs: %{}}, fn entry, acc -> + full_path = Path.join(path ++ [entry]) + + cond do + File.dir?(full_path) -> + nested_content = list_content_rec_helper(path ++ [entry], root_dir) + put_in(acc, [:dirs, entry], nested_content) + + String.ends_with?(entry, ".md") -> + # Get the path relative to base_path + relative_path = + full_path + |> Path.relative_to(base_path()) + |> Path.rootname(".md") + + path_segments = + relative_path + |> Path.split() + |> Enum.drop(1) + + directory = Path.dirname(relative_path) + slug = Path.basename(relative_path) + + case load_content(directory, slug) do + {:ok, content} -> + content_with_path = Map.put(content, :path, path_segments) + Map.update!(acc, :files, &[content_with_path | &1]) + + _ -> + acc + end + + true -> + acc + end + end) + |> Map.update!(:files, &Enum.sort_by(&1, fn file -> file.date end, :desc)) + + {:error, _} -> + %{files: [], dirs: %{}} + end + end + def format_date(date_string) when is_binary(date_string) do case Date.from_iso8601(date_string) do {:ok, date} -> Calendar.strftime(date, "%B %d, %Y") diff --git a/lib/algora_web/constants.ex b/lib/algora_web/constants.ex index f408c235a..20bf08d5f 100644 --- a/lib/algora_web/constants.ex +++ b/lib/algora_web/constants.ex @@ -15,14 +15,14 @@ defmodule AlgoraWeb.Constants do calendar_url: "https://cal.com/ioannisflo", github_repo_url: "https://github.com/algora-io/console", github_repo_api_url: "https://api.github.com/repos/algora-io/console", - docs_url: "https://docs.algora.io", - docs_supported_countries_url: "https://docs.algora.io/bounties/payments#supported-countries-regions", + docs_url: ~p"/docs", + docs_supported_countries_url: ~p"/docs/payments", demo_url: "https://www.youtube.com/watch?v=Ts5GhlEROrs", sdk_url: ~p"/sdk", privacy_url: ~p"/legal/privacy", terms_url: ~p"/legal/terms", blog_url: "https://blog.algora.io", - contact_url: "https://docs.algora.io/contact", + contact_url: ~p"/docs/contact", algora_tv_url: "https://algora.tv", tel_formatted: "+1 (650) 420-2207", tel: "+16504202207" diff --git a/lib/algora_web/endpoint.ex b/lib/algora_web/endpoint.ex index 1667d4d42..a8956f2dd 100644 --- a/lib/algora_web/endpoint.ex +++ b/lib/algora_web/endpoint.ex @@ -4,6 +4,8 @@ defmodule AlgoraWeb.Endpoint do # The session will be stored in the cookie and signed, # this means its contents can be read but not tampered with. # Set :encryption_salt if you would also like to encrypt it. + alias AlgoraWeb.Plugs.CanonicalHostPlug + @session_options [ store: :cookie, key: "_algora_key", @@ -60,13 +62,18 @@ defmodule AlgoraWeb.Endpoint do # Legacy tRPC endpoint defp canonical_host(%{path_info: ["api", "trpc" | _]} = conn, _opts), do: conn - defp canonical_host(conn, _opts) do + defp canonical_host(%{host: "docs.algora.io"} = conn, _opts), + do: redirect_to_canonical_host(conn, Path.join(["/docs", conn.request_path])) + + defp canonical_host(conn, _opts), do: redirect_to_canonical_host(conn, conn.request_path) + + defp redirect_to_canonical_host(conn, path) do :algora |> Application.get_env(:canonical_host) |> case do host when is_binary(host) -> - opts = PlugCanonicalHost.init(canonical_host: host) - PlugCanonicalHost.call(conn, opts) + opts = CanonicalHostPlug.init(canonical_host: host, path: path) + CanonicalHostPlug.call(conn, opts) _ -> conn diff --git a/lib/algora_web/live/docs_live.ex b/lib/algora_web/live/docs_live.ex new file mode 100644 index 000000000..16e0db8b0 --- /dev/null +++ b/lib/algora_web/live/docs_live.ex @@ -0,0 +1,764 @@ +defmodule AlgoraWeb.DocsLive do + @moduledoc false + use AlgoraWeb, :live_view + + defp nav do + [ + %{ + title: "Overview", + links: [ + %{title: "Introduction", href: "/docs"}, + %{title: "Slash commands", href: "/docs/commands"} + ] + }, + %{ + title: "GitHub bounties", + links: [ + %{title: "Create bounties in your repos", href: "/docs/bounties/in-your-own-repos"}, + %{title: "Fund issues anywhere on GitHub", href: "/docs/bounties/in-other-projects"} + ] + }, + %{ + title: "Algora bounties", + links: [ + %{title: "Exclusive", href: "/docs/bounties/exclusive"}, + %{title: "Custom", href: "/docs/bounties/custom"} + ] + }, + %{ + title: "Tips", + links: [ + %{title: "Send a tip", href: "/docs/tips/send"} + ] + }, + %{ + title: "Contracts", + links: [ + %{title: "Offer a contract", href: "/docs/contracts/offer-contract"} + ] + }, + %{ + title: "Marketplace", + links: [ + %{title: "Matches", href: "/docs/marketplace/matches"} + ] + }, + %{ + title: "Workspace", + links: [ + %{title: "Bounty board", href: "/docs/workspace/bounty-board"}, + %{title: "Leaderboard", href: "/docs/workspace/leaderboard"}, + %{title: "Transactions", href: "/docs/workspace/transactions"}, + %{title: "Autopay on merge", href: "/docs/workspace/autopay"}, + %{title: "Custom bot messages", href: "/docs/workspace/custom-bot-messages"} + ] + }, + %{ + title: "Embed", + links: [ + %{title: "SDK", href: "/docs/embed/sdk"}, + %{title: "Shields", href: "/docs/embed/shields"}, + %{title: "Socials", href: "/docs/embed/socials"} + ] + }, + %{ + title: "Payments", + links: [ + %{title: "Payments", href: "/docs/payments"}, + %{title: "Reporting", href: "/docs/payments/reporting"} + ] + } + ] + end + + @impl true + def mount(%{"path" => []}, _session, socket) do + docs = Algora.Content.list_content_rec("docs") + {:ok, assign(socket, docs: docs, page_title: "Docs", path: [])} + end + + @impl true + def mount(%{"path" => path}, _session, socket) do + slug = List.last(path) + dir = Path.join("docs", Enum.drop(path, -1)) + + case Algora.Content.load_content(dir, slug) do + {:ok, content} -> + {:ok, assign(socket, content: content, page_title: content.title, path: path)} + + {:error, _reason} -> + {:ok, push_navigate(socket, to: ~p"/docs")} + end + end + + defp active?(current_path, href), do: Path.join(["/docs" | current_path]) == href + + defp render_navigation_section(assigns) do + ~H""" +
+ Discover GitHub bounties, contract work and jobs. Hire the top 1% open source developers. +
++ Add USD rewards on issues and pay on-merge +
++ Collaborate flexibly, hourly or fixed rate +
++ Collaborate with Algora experts +
++ Embed Algora in your website, readme, docs, etc. +
+Receive payments directly to your bank account from all around the world <.link - href="https://docs.algora.io/bounties/payments#supported-countries-regions" + href="https://algora.io/docs/payments#supported-countries-regions" class="font-medium text-foreground" > ({ConnectCountries.count()} countries/regions supported) diff --git a/lib/algora_web/plugs/canonical_host_plug.ex b/lib/algora_web/plugs/canonical_host_plug.ex new file mode 100644 index 000000000..b1d5a6d20 --- /dev/null +++ b/lib/algora_web/plugs/canonical_host_plug.ex @@ -0,0 +1,99 @@ +defmodule AlgoraWeb.Plugs.CanonicalHostPlug do + @moduledoc """ + A Plug for ensuring that all requests are served by a single canonical host + Adapted from https://github.com/remi/plug_canonical_host + """ + @behaviour Plug + + # Imports + import Plug.Conn + + # Aliases + alias Plug.Conn + + # Behaviours + + # Constants + @location_header "location" + @forwarded_port_header "x-forwarded-port" + @forwarded_proto_header "x-forwarded-proto" + @status_code 301 + @html_template """ + + +
The document has moved here.
+ + + """ + + # Types + @type opts :: binary | tuple | atom | integer | float | [opts] | %{opts => opts} + + @doc """ + Initialize this plug with a canonical host option. + """ + @spec init(opts) :: opts + def init(opts) do + [ + canonical_host: Keyword.fetch!(opts, :canonical_host), + path: Keyword.fetch!(opts, :path) + ] + end + + @doc """ + Call the plug. + """ + @spec call(%Conn{}, opts) :: Conn.t() + def call(%Conn{host: host} = conn, canonical_host: canonical_host, path: path) + when is_nil(canonical_host) == false and canonical_host !== "" and host !== canonical_host do + location = redirect_location(conn, canonical_host, path) + + conn + |> put_resp_header(@location_header, location) + |> send_resp(@status_code, String.replace(@html_template, "%s", location)) + |> halt() + end + + def call(conn, _), do: conn + + @spec redirect_location(%Conn{}, String.t(), String.t()) :: String.t() + defp redirect_location(conn, canonical_host, path) do + conn + |> request_uri(path) + |> URI.parse() + |> sanitize_empty_query() + |> Map.put(:host, canonical_host) + |> Map.put(:path, path) + |> URI.to_string() + end + + @spec request_uri(%Conn{}, String.t()) :: String.t() + defp request_uri(%Conn{host: host, query_string: query_string} = conn, path) do + "#{canonical_scheme(conn)}://#{host}:#{canonical_port(conn)}#{path}?#{query_string}" + end + + @spec canonical_port(%Conn{}) :: binary | integer + defp canonical_port(%Conn{port: port} = conn) do + case {get_req_header(conn, @forwarded_port_header), get_req_header(conn, @forwarded_proto_header)} do + {[forwarded_port], _} -> forwarded_port + {[], ["http"]} -> 80 + {[], ["https"]} -> 443 + {[], []} -> port + end + end + + @spec canonical_scheme(%Conn{}) :: binary + defp canonical_scheme(%Conn{scheme: scheme} = conn) do + case get_req_header(conn, @forwarded_proto_header) do + [forwarded_proto] -> forwarded_proto + [] -> scheme + end + end + + @spec sanitize_empty_query(%URI{}) :: %URI{} + defp sanitize_empty_query(%URI{query: ""} = uri), do: Map.put(uri, :query, nil) + defp sanitize_empty_query(uri), do: uri +end diff --git a/lib/algora_web/plugs/rewrite_docs_plug.ex b/lib/algora_web/plugs/rewrite_docs_plug.ex deleted file mode 100644 index 6e8a395d8..000000000 --- a/lib/algora_web/plugs/rewrite_docs_plug.ex +++ /dev/null @@ -1,24 +0,0 @@ -defmodule AlgoraWeb.Plugs.RewriteDocsPlug do - @moduledoc false - def init(options), do: options - - def call(%Plug.Conn{} = conn, _ \\ []) do - conn - |> Plug.Conn.register_before_send(&transform_body/1) - |> Plug.Conn.update_req_header("accept-encoding", "identity", fn _ -> "identity" end) - end - - def transform_body(%Plug.Conn{} = conn) do - proxy_url = "https://docs.algora.io" - - body = - if conn.resp_body do - conn.resp_body - |> String.replace("src=\"/", "src=\"#{proxy_url}/") - |> String.replace("href=\"/", "href=\"#{proxy_url}/") - |> String.replace("#{proxy_url}", AlgoraWeb.Endpoint.url()) - end - - %Plug.Conn{conn | resp_body: body} - end -end diff --git a/lib/algora_web/router.ex b/lib/algora_web/router.ex index b1a4c4440..c22a49ec0 100644 --- a/lib/algora_web/router.ex +++ b/lib/algora_web/router.ex @@ -40,10 +40,6 @@ defmodule AlgoraWeb.Router do forward "/ingest", AlgoraWeb.Plugs.RewriteIngestPlug, upstream: :ingest_url forward "/observe/script.js", AlgoraWeb.Plugs.RewriteObserveJSPlug, upstream: "https://plausible.io/js/script.js" forward "/observe/event", AlgoraWeb.Plugs.RewriteObserveEventPlug, upstream: "https://plausible.io/api/event" - - # forward "/docs", AlgoraWeb.Plugs.RewriteDocsPlug, - # upstream: "https://docs.algora.io", - # response_mode: :buffer end scope "/admin", AlgoraWeb do @@ -134,6 +130,7 @@ defmodule AlgoraWeb.Router do live "/blog", BlogLive, :index live "/changelog/:slug", ChangelogLive, :show live "/changelog", ChangelogLive, :index + live "/docs/*path", DocsLive, :show live "/case-studies/:slug", CaseStudyLive, :show live "/case-studies", CaseStudyLive, :index end diff --git a/mix.exs b/mix.exs index bace7e6eb..cf6d74e0f 100644 --- a/mix.exs +++ b/mix.exs @@ -93,7 +93,6 @@ defmodule Algora.MixProject do {:mdex, "~> 0.2"}, {:reverse_proxy_plug, "~> 3.0"}, {:cors_plug, "~> 2.0"}, - {:plug_canonical_host, "~> 2.0"}, {:timex, "~> 3.7"}, {:yaml_elixir, "~> 2.9"}, {:hammer, "~> 7.0"}, diff --git a/mix.lock b/mix.lock index 5fbd04fb0..875b44bfc 100644 --- a/mix.lock +++ b/mix.lock @@ -73,7 +73,6 @@ "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, "plug": {:hex, :plug, "1.17.0", "a0832e7af4ae0f4819e0c08dd2e7482364937aea6a8a997a679f2cbb7e026b2e", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f6692046652a69a00a5a21d0b7e11fcf401064839d59d6b8787f23af55b1e6bc"}, - "plug_canonical_host": {:hex, :plug_canonical_host, "2.0.3", "3d96c3340cc8a434eb6758a4a34de6c152bd781be96bb8439545da2d17ecf576", [:make, :mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "aca98ac6d0036391b84d5a40af6f946c839fb0d588bf0064029a2e8931431ea6"}, "plug_cowboy": {:hex, :plug_cowboy, "2.7.3", "1304d36752e8bdde213cea59ef424ca932910a91a07ef9f3874be709c4ddb94b", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "77c95524b2aa5364b247fa17089029e73b951ebc1adeef429361eab0bb55819d"}, "plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"}, "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"}, diff --git a/priv/content/docs/bounties/custom.md b/priv/content/docs/bounties/custom.md new file mode 100644 index 000000000..b366e8531 --- /dev/null +++ b/priv/content/docs/bounties/custom.md @@ -0,0 +1,27 @@ +--- +title: "Custom bounties" +--- + +# Custom bounties + +You can create custom bounties on Algora for tasks that are recurring and/or not connected to any single ticket. + + + +## View your bounty + +Once created, you'll land on a unique page where you can manage your bounty. + + + +## Share your bounty + +You can share the link with anyone or give exclusive to certain GitHub user(s). + + + +## Pay your bounty + +When the task is completed, you can pay your bounty by clicking the Reward button. + + diff --git a/priv/content/docs/bounties/exclusive.md b/priv/content/docs/bounties/exclusive.md new file mode 100644 index 000000000..d2b41875b --- /dev/null +++ b/priv/content/docs/bounties/exclusive.md @@ -0,0 +1,17 @@ +--- +title: "Exclusive bounties" +--- + +# Exclusive bounties + +You can share bounty exclusives with developers and add a deadline for completion. + +Replace **github.com** with **algora.io** in your issue URL to generate a unique bounty page. + +Then click the **Add exclusive** button. + + + +Alternatively, you can share an exclusive by clicking **Bounty** button next to a contributor on your dashboard. + + diff --git a/priv/content/docs/bounties/in-other-projects.md b/priv/content/docs/bounties/in-other-projects.md new file mode 100644 index 000000000..98e26e6da --- /dev/null +++ b/priv/content/docs/bounties/in-other-projects.md @@ -0,0 +1,17 @@ +--- +title: "Fund issues anywhere on GitHub" +--- + +# Fund issues anywhere on GitHub + +First connect your GitHub account to Algora. + +Then, either use the form on your dashboard or comment `/bounty $1000` on any public GitHub issue or pull request. + + + +## Confirmation + +Algora will post a comment on the issue or pull request with a link to the bounty. Others can add funds to the bounty pool, too! + +
diff --git a/priv/content/docs/bounties/in-your-own-repos.md b/priv/content/docs/bounties/in-your-own-repos.md
new file mode 100644
index 000000000..5e51f9ede
--- /dev/null
+++ b/priv/content/docs/bounties/in-your-own-repos.md
@@ -0,0 +1,35 @@
+---
+title: "Create bounties in your repos"
+---
+
+# Create bounties in your repos
+
+Install the Algora app from your org dashboard or settings.
+
+
+
+## Complete installation
+
+
+
+## Create your first bounty
+
+
+
+## Receive solutions
+
+The Algora app will track all pull requests that claim the bounty.
+
+
+
+## Reward bounty
+
+Once you're satisfied with a solution, you can click **Reward** link in the table to proceed with the checkout.
+
+
+
+## Payout confirmation
+
+The Algora bot will comment on the issue when the contributor receives the payment.
+
+
diff --git a/priv/content/docs/commands.md b/priv/content/docs/commands.md
new file mode 100644
index 000000000..80433e875
--- /dev/null
+++ b/priv/content/docs/commands.md
@@ -0,0 +1,162 @@
+---
+title: Slash commands reference
+---
+
+# Slash commands reference
+
+
diff --git a/priv/content/docs/contact.md b/priv/content/docs/contact.md
new file mode 100644
index 000000000..29536a78f
--- /dev/null
+++ b/priv/content/docs/contact.md
@@ -0,0 +1,11 @@
+---
+title: Get in touch
+---
+
+# Get in touch
+
+We’re happy to hear from you! You can reach the Algora founders directly at:
+
+- 📧 ioannis@algora.io & zafer@algora.io
+- 📞 +1 (650) 420-2207, +30 6973184144
+- 🗓️ [schedule a call](https://cal.com/ioannisflo)
diff --git a/priv/content/docs/contracts/offer-contract.md b/priv/content/docs/contracts/offer-contract.md
new file mode 100644
index 000000000..aca03694f
--- /dev/null
+++ b/priv/content/docs/contracts/offer-contract.md
@@ -0,0 +1,11 @@
+---
+title: "Offer a contract"
+---
+
+# Offer a contract
+
+
+
+## Manage contract
+
+
diff --git a/priv/content/docs/embed/sdk.md b/priv/content/docs/embed/sdk.md
new file mode 100644
index 000000000..e7eb7f874
--- /dev/null
+++ b/priv/content/docs/embed/sdk.md
@@ -0,0 +1,543 @@
+---
+title: "SDK"
+---
+
+# Algora Typescript SDK
+
+[](https://www.npmjs.com/package/@algora/sdk)
+
+## Showcase
+
+### [Cal.com Jobs](https://cal.com/jobs)
+
+
+
+### [Remotion Docs](https://www.remotion.dev/docs/contributing/bounty) via [remotion-dev/remotion#2949](https://github.com/remotion-dev/remotion/pull/2949)
+
+
+
+### [Tembo Blog](https://tembo.io/blog/algora-code-bounties) via [tembo-io/website#678](https://github.com/tembo-io/website/pull/678)
+
+
+
+### [Million.js Blog](https://old.million.dev/blog/million-v2.5.1) via [aidenybai/million#492](https://github.com/aidenybai/million/pull/492)
+
+
+
+## Installation
+
+### Option 1: Package manager
+
+Install the SDK with the package manager of your choice (npm, yarn, pnpm...)
+
+```bash
+npm install @algora/sdk
+```
+
+```ts
+import { algora } from "@algora/sdk";
+const { items, next_cursor } = await algora.bounty.list.query({ org: "acme" });
+```
+
+### Option 2: CDN
+
+Alternatively, you can use the CDN bundle by adding these tags to your HTML:
+
+```html
+
+
+
+
+```
+
+## Quickstart
+
++ We're actively looking for and paying{" "} + contributors. Check out our{" "} + + active bounties + (opens in a new tab) + +
+
+
+# Send a tip on Algora
+
+Click the **Tip** button next to a contributor's name on your dashboard.
+
+
+
+## Proceed to checkout
+
+Enter the details and finalize the payment on Stripe.
+
+
diff --git a/priv/content/docs/workspace/autopay.md b/priv/content/docs/workspace/autopay.md
new file mode 100644
index 000000000..68069acaa
--- /dev/null
+++ b/priv/content/docs/workspace/autopay.md
@@ -0,0 +1,9 @@
+---
+title: "Autopay on merge"
+---
+
+# Autopay on merge
+
+Navigate to your settings and save a payment method with Stripe to automatically pay out bounties when they are merged.
+
+
diff --git a/priv/content/docs/workspace/bounty-board.md b/priv/content/docs/workspace/bounty-board.md
new file mode 100644
index 000000000..5b9a01bc7
--- /dev/null
+++ b/priv/content/docs/workspace/bounty-board.md
@@ -0,0 +1,7 @@
+---
+title: "Bounty board"
+---
+
+# Bounty board
+
+
diff --git a/priv/content/docs/workspace/custom-bot-messages.md b/priv/content/docs/workspace/custom-bot-messages.md
new file mode 100644
index 000000000..1b6d3b72b
--- /dev/null
+++ b/priv/content/docs/workspace/custom-bot-messages.md
@@ -0,0 +1,9 @@
+---
+title: "Custom bot messages"
+---
+
+# Custom bot messages
+
+You can customize the bot messages as you wish!
+
+
diff --git a/priv/content/docs/workspace/leaderboard.md b/priv/content/docs/workspace/leaderboard.md
new file mode 100644
index 000000000..634d61eb3
--- /dev/null
+++ b/priv/content/docs/workspace/leaderboard.md
@@ -0,0 +1,9 @@
+---
+title: "Leaderboard"
+---
+
+# Leaderboard
+
+View top contributors ranked by earnings from bounties, tips, and contracts
+
+
diff --git a/priv/content/docs/workspace/transactions.md b/priv/content/docs/workspace/transactions.md
new file mode 100644
index 000000000..7fa522c87
--- /dev/null
+++ b/priv/content/docs/workspace/transactions.md
@@ -0,0 +1,9 @@
+---
+title: "Transactions"
+---
+
+# Transactions
+
+View all payments and export summaries
+
+
diff --git a/priv/static/images/docs/add-exclusive.png b/priv/static/images/docs/add-exclusive.png
new file mode 100644
index 000000000..4f8ecc445
Binary files /dev/null and b/priv/static/images/docs/add-exclusive.png differ
diff --git a/priv/static/images/docs/autopay.png b/priv/static/images/docs/autopay.png
new file mode 100644
index 000000000..cd404a8d1
Binary files /dev/null and b/priv/static/images/docs/autopay.png differ
diff --git a/priv/static/images/docs/claim-page.png b/priv/static/images/docs/claim-page.png
new file mode 100644
index 000000000..2e0be3b42
Binary files /dev/null and b/priv/static/images/docs/claim-page.png differ
diff --git a/priv/static/images/docs/community-bounty-response.png b/priv/static/images/docs/community-bounty-response.png
new file mode 100644
index 000000000..3c1eb8dfc
Binary files /dev/null and b/priv/static/images/docs/community-bounty-response.png differ
diff --git a/priv/static/images/docs/create-bounty-on-github.png b/priv/static/images/docs/create-bounty-on-github.png
new file mode 100644
index 000000000..f174f3e2b
Binary files /dev/null and b/priv/static/images/docs/create-bounty-on-github.png differ
diff --git a/priv/static/images/docs/create-community-bounty.png b/priv/static/images/docs/create-community-bounty.png
new file mode 100644
index 000000000..fc6b49a4e
Binary files /dev/null and b/priv/static/images/docs/create-community-bounty.png differ
diff --git a/priv/static/images/docs/create-custom-bounty.png b/priv/static/images/docs/create-custom-bounty.png
new file mode 100644
index 000000000..92fde03f8
Binary files /dev/null and b/priv/static/images/docs/create-custom-bounty.png differ
diff --git a/priv/static/images/docs/create-tip-on-algora-1.png b/priv/static/images/docs/create-tip-on-algora-1.png
new file mode 100644
index 000000000..02e0b0732
Binary files /dev/null and b/priv/static/images/docs/create-tip-on-algora-1.png differ
diff --git a/priv/static/images/docs/create-tip-on-algora-2.png b/priv/static/images/docs/create-tip-on-algora-2.png
new file mode 100644
index 000000000..fb828a977
Binary files /dev/null and b/priv/static/images/docs/create-tip-on-algora-2.png differ
diff --git a/priv/static/images/docs/custom-bot-messages.png b/priv/static/images/docs/custom-bot-messages.png
new file mode 100644
index 000000000..0041a94ec
Binary files /dev/null and b/priv/static/images/docs/custom-bot-messages.png differ
diff --git a/priv/static/images/docs/dashboard-pending-payments.png b/priv/static/images/docs/dashboard-pending-payments.png
new file mode 100644
index 000000000..c60f2e868
Binary files /dev/null and b/priv/static/images/docs/dashboard-pending-payments.png differ
diff --git a/priv/static/images/docs/install-algora-app-prompt.png b/priv/static/images/docs/install-algora-app-prompt.png
new file mode 100644
index 000000000..d6f3bb617
Binary files /dev/null and b/priv/static/images/docs/install-algora-app-prompt.png differ
diff --git a/priv/static/images/docs/install-algora-app.png b/priv/static/images/docs/install-algora-app.png
new file mode 100644
index 000000000..020bf4711
Binary files /dev/null and b/priv/static/images/docs/install-algora-app.png differ
diff --git a/priv/static/images/docs/leaderboard.png b/priv/static/images/docs/leaderboard.png
new file mode 100644
index 000000000..62be1d334
Binary files /dev/null and b/priv/static/images/docs/leaderboard.png differ
diff --git a/priv/static/images/docs/payout-confirmation.png b/priv/static/images/docs/payout-confirmation.png
new file mode 100644
index 000000000..3fe853d01
Binary files /dev/null and b/priv/static/images/docs/payout-confirmation.png differ
diff --git a/priv/static/images/docs/reward-bounty-prompt.png b/priv/static/images/docs/reward-bounty-prompt.png
new file mode 100644
index 000000000..492458c5d
Binary files /dev/null and b/priv/static/images/docs/reward-bounty-prompt.png differ
diff --git a/priv/static/images/docs/reward-bounty.png b/priv/static/images/docs/reward-bounty.png
new file mode 100644
index 000000000..dc39263f4
Binary files /dev/null and b/priv/static/images/docs/reward-bounty.png differ
diff --git a/priv/static/images/docs/view-custom-bounty.png b/priv/static/images/docs/view-custom-bounty.png
new file mode 100644
index 000000000..f3ab8a9a0
Binary files /dev/null and b/priv/static/images/docs/view-custom-bounty.png differ
diff --git a/priv/static/images/docs/view-exclusive.png b/priv/static/images/docs/view-exclusive.png
new file mode 100644
index 000000000..94e54cec5
Binary files /dev/null and b/priv/static/images/docs/view-exclusive.png differ
diff --git a/priv/static/images/screenshots/share-bounty-private.png b/priv/static/images/screenshots/share-bounty-private.png
index 973a0628b..130598c29 100644
Binary files a/priv/static/images/screenshots/share-bounty-private.png and b/priv/static/images/screenshots/share-bounty-private.png differ
diff --git a/test/algora/bounties_test.exs b/test/algora/bounties_test.exs
index 08f2435a5..1555faaaf 100644
--- a/test/algora/bounties_test.exs
+++ b/test/algora/bounties_test.exs
@@ -292,7 +292,7 @@ defmodule Algora.BountiesTest do
### Steps to solve:
1. **Start working**: Comment `/attempt #${ISSUE_NUMBER}` with your implementation plan
2. **Submit work**: Create a pull request including `/claim #${ISSUE_NUMBER}` in the PR body to claim the bounty
- 3. **Receive payment**: 100% of the bounty is received 2-5 days post-reward. [Make sure you are eligible for payouts](https://docs.algora.io/bounties/payments#supported-countries-regions)
+ 3. **Receive payment**: 100% of the bounty is received 2-5 days post-reward. [Make sure you are eligible for payouts](https://algora.io/docs/payments#supported-countries-regions)
### ❗ Important guidelines:
- To claim a bounty, you need to **provide a short demo video** of your changes in your pull request
@@ -323,7 +323,7 @@ defmodule Algora.BountiesTest do
### Steps to solve:
1. **Start working**: Comment `/attempt #100` with your implementation plan
2. **Submit work**: Create a pull request including `/claim #100` in the PR body to claim the bounty
- 3. **Receive payment**: 100% of the bounty is received 2-5 days post-reward. [Make sure you are eligible for payouts](https://docs.algora.io/bounties/payments#supported-countries-regions)
+ 3. **Receive payment**: 100% of the bounty is received 2-5 days post-reward. [Make sure you are eligible for payouts](https://algora.io/docs/payments#supported-countries-regions)
### ❗ Important guidelines:
- To claim a bounty, you need to **provide a short demo video** of your changes in your pull request
@@ -429,7 +429,7 @@ defmodule Algora.BountiesTest do
### Steps to solve:
1. **Start working**: Comment `/attempt #100` with your implementation plan
2. **Submit work**: Create a pull request including `/claim #100` in the PR body to claim the bounty
- 3. **Receive payment**: 100% of the bounty is received 2-5 days post-reward. [Make sure you are eligible for payouts](https://docs.algora.io/bounties/payments#supported-countries-regions)
+ 3. **Receive payment**: 100% of the bounty is received 2-5 days post-reward. [Make sure you are eligible for payouts](https://algora.io/docs/payments#supported-countries-regions)
Thank you for contributing to repo_owner/test_repo!
@@ -483,7 +483,7 @@ defmodule Algora.BountiesTest do
### Steps to solve:
1. **Start working**: Comment `/attempt #100` with your implementation plan
2. **Submit work**: Create a pull request including `/claim #100` in the PR body to claim the bounty
- 3. **Receive payment**: 100% of the bounty is received 2-5 days post-reward. [Make sure you are eligible for payouts](https://docs.algora.io/bounties/payments#supported-countries-regions)
+ 3. **Receive payment**: 100% of the bounty is received 2-5 days post-reward. [Make sure you are eligible for payouts](https://algora.io/docs/payments#supported-countries-regions)
Thank you for contributing to repo_owner/test_repo!
"""