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""" +
  • +

    + {section.title} +

    +
    +
    + +
    +
  • + """ + end + + @impl true + def render(assigns) do + ~H""" +
    +
    + + +
    +
    +
    + +
    + <.wordmark class="h-6 w-auto text-foreground" /> + +
    +
    + + + +
    +
    + +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    + <%= if assigns[:content] do %> + {raw(@content.content)} + <% else %> + <.overview /> + <% end %> +
    +
    + +
    +
    + """ + end + + def overview(assigns) do + ~H""" +

    Algora

    +

    + Discover GitHub bounties, contract work and jobs. Hire the top 1% open source developers. +

    +
    + + Get started + +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + <.icon + name="tabler-diamond" + class="h-5 w-5 fill-white/10 text-gray-400 transition-colors duration-300 group-hover:fill-emerald-300/10 group-hover:text-emerald-400 light:fill-gray-700/10 light:text-gray-700 light:group-hover:text-gray-900" + /> +
    +

    + <.link navigate="/docs/bounties/in-your-own-repos"> + Bounties + +

    +

    + Add USD rewards on issues and pay on-merge +

    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + <.icon + name="tabler-contract" + class="h-5 w-5 fill-white/10 text-gray-400 transition-colors duration-300 group-hover:fill-emerald-300/10 group-hover:text-emerald-400 light:fill-gray-700/10 light:text-gray-700 light:group-hover:text-gray-900" + /> +
    +

    + <.link navigate="/docs/contracts/offer-contract"> + Contract work + +

    +

    + Collaborate flexibly, hourly or fixed rate +

    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + <.icon + name="tabler-user-star" + class="h-5 w-5 fill-white/10 text-gray-400 transition-colors duration-300 group-hover:fill-emerald-300/10 group-hover:text-emerald-400 light:fill-gray-700/10 light:text-gray-700 light:group-hover:text-gray-900" + /> +
    +

    + <.link navigate="/docs/marketplace/matches"> + Marketplace + +

    +

    + Collaborate with Algora experts +

    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + <.icon + name="tabler-image-in-picture" + class="h-5 w-5 fill-white/10 text-gray-400 transition-colors duration-300 group-hover:fill-emerald-300/10 group-hover:text-emerald-400 light:fill-gray-700/10 light:text-gray-700 light:group-hover:text-gray-900" + /> +
    +

    + <.link navigate="/docs/embed/sdk"> + Embed + +

    +

    + Embed Algora in your website, readme, docs, etc. +

    +
    +
    +
    +
    + """ + end +end diff --git a/lib/algora_web/live/pricing_live.ex b/lib/algora_web/live/pricing_live.ex index 3d740440f..dcfabe62a 100644 --- a/lib/algora_web/live/pricing_live.ex +++ b/lib/algora_web/live/pricing_live.ex @@ -387,7 +387,7 @@ defmodule AlgoraWeb.PricingLive do id: "payment-methods", question: "What payment methods do you support?", answer: - ~s(We support payments via Stripe for funding bounties. Contributors can receive payments directly to their bank accounts in #{ConnectCountries.count()} countries/regions worldwide.) + ~s(We support payments via Stripe for funding bounties. Contributors can receive payments directly to their bank accounts in #{ConnectCountries.count()} countries/regions worldwide.) }, %FaqItem{ id: "payment-process", @@ -429,7 +429,7 @@ defmodule AlgoraWeb.PricingLive do id: "supported-countries", question: "Which countries are supported for contributors?", answer: - ~s(We support contributors from #{ConnectCountries.count()} countries/regions worldwide. You can receive payments regardless of your location as long as you have a bank account in one of our supported countries. See the full list of supported countries.) + ~s(We support contributors from #{ConnectCountries.count()} countries/regions worldwide. You can receive payments regardless of your location as long as you have a bank account in one of our supported countries. See the full list of supported countries.) } ] end @@ -608,7 +608,7 @@ defmodule AlgoraWeb.PricingLive do

    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 """ + + + 301 Moved Permanently + +

    Moved Permanently

    +

    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. + +![Create custom bounty](/images/docs/create-custom-bounty.png) + +## View your bounty + +Once created, you'll land on a unique page where you can manage your bounty. + +![View custom bounty](/images/docs/view-custom-bounty.png) + +## Share your bounty + +You can share the link with anyone or give exclusive to certain GitHub user(s). + +![Add exclusives](/images/docs/add-exclusive.png) + +## Pay your bounty + +When the task is completed, you can pay your bounty by clicking the Reward button. + +![Reward bounty](/images/docs/reward-bounty.png) 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. + +![Add exclusives](/images/docs/add-exclusive.png) + +Alternatively, you can share an exclusive by clicking **Bounty** button next to a contributor on your dashboard. + +![Share bounty](/images/screenshots/share-bounty-private.png) 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. + +![Create community bounty](/images/docs/create-community-bounty.png) + +## 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! + +Community bounty response 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. + +![Install Algora app prompt](/images/docs/install-algora-app-prompt.png) + +## Complete installation + +Install Algora app + +## Create your first bounty + +Create your first bounty + +## Receive solutions + +The Algora app will track all pull requests that claim the bounty. + +Create your first bounty + +## Reward bounty + +Once you're satisfied with a solution, you can click **Reward** link in the table to proceed with the checkout. + +Claim page + +## Payout confirmation + +The Algora bot will comment on the issue when the contributor receives the payment. + +Payout confirmation 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 + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Command + + Description + + Where +
    +
    + /bounty $500 +
    +
    +
    + Create a $500 bounty +
    +
    +
    + Issue/PR comment +
    +
    +
    + /bounty +
    +
    +
    + Create a biddable bounty +
    +
    +
    + Issue/PR comment +
    +
    +
    + /tip $100 +
    +
    +
    + Tip the author $100 +
    +
    +
    + Issue/PR comment +
    +
    +
    + /tip $100 @jsmith +
    +
    +
    + Tip the Github user with jsmith handle $100 +
    +
    +
    + Issue/PR comment +
    +
    +
    + /attempt #137 +
    +
    +
    + Declare that you started working on the issue #137 +
    +
    +
    + Issue comment +
    +
    +
    + /claim #137 +
    +
    +
    + Submit an individual claim for the bounty of the issue #137 +
    +
    +
    PR body
    +
    +
    + /claim #137
    /split @jsmith
    /split @jdoe +
    +
    +
    + Submit a joint claim for the bounty of the issue #137
    In this example, the award would be split evenly into 3 +
    +
    +
    PR body
    +
    +
    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 + +![Offer a contract](/images/screenshots/share-contract.png) + +## Manage contract + +![Manage contract](/images/screenshots/contract.png) 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 + +[![npm (scoped)](https://img.shields.io/npm/v/@algora/sdk)](https://www.npmjs.com/package/@algora/sdk) + +## Showcase + +### [Cal.com Jobs](https://cal.com/jobs) + +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) + +Remotion Docs + +### [Tembo Blog](https://tembo.io/blog/algora-code-bounties) via [tembo-io/website#678](https://github.com/tembo-io/website/pull/678) + +Tembo Blog + +### [Million.js Blog](https://old.million.dev/blog/million-v2.5.1) via [aidenybai/million#492](https://github.com/aidenybai/million/pull/492) + +Million.js Blog + +## 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 + +
    +
    HTML & CSS
    + +Add these tags to the `` of your HTML: + +```html + + +``` + +Add a container for the bounty board to the `` of your HTML: + +```html +
    +``` + +Customize the styling as you like: + +```css +.bounty-board { + max-width: 800px; + font-family: "Inter"; + --line-clamp: 2; + --accent-50: 226, 100%, 97%; + --accent-100: 226, 100%, 94%; + --accent-200: 228, 96%, 89%; + --accent-300: 230, 94%, 82%; + --accent-400: 234, 89%, 74%; + --accent-500: 239, 84%, 67%; + --accent-600: 243, 75%, 59%; + --accent-700: 245, 58%, 51%; + --accent-800: 244, 55%, 41%; + --accent-900: 242, 47%, 34%; + --accent-950: 244, 47%, 20%; +} +``` + +
    + +
    +
    React & Tailwind
    + +```tsx +import { useEffect, useState } from "react"; +import { algora, type AlgoraOutput } from "@algora/sdk"; +import Link from "next/link"; + +// TODO: Use your own Algora handle +const org = "acme"; +const limit = 3; + +type RemoteData = + | { _tag: "loading" } + | { _tag: "failure"; error: Error } + | { _tag: "success"; data: T }; + +type Bounty = AlgoraOutput["bounty"]["list"]["items"][number]; + +export function Bounties() { + const [bounties, setBounties] = useState>({ + _tag: "loading", + }); + + useEffect(() => { + const ac = new AbortController(); + + algora.bounty.list + .query({ org, limit, status: "active" }, { signal: ac.signal }) + .then(({ items: data }) => setBounties({ _tag: "success", data })) + .catch((error) => setBounties({ _tag: "failure", error })); + + return () => ac.abort(); + }, []); + + return ( +
    + +
      + {bounties._tag === "success" && + bounties.data.map((bounty) => ( +
    • + +
    • + ))} + {bounties._tag === "loading" && + [...Array(limit)].map((_, i) => ( +
    • + +
    • + ))} +
    +
    + ); +} + +function BountyCard(props: { bounty: Bounty }) { + return ( + +
    +
    + {props.bounty.reward_formatted} +
    +
    + {props.bounty.task.repo_name}#{props.bounty.task.number} +
    +
    + {props.bounty.task.title} +
    +
    + + ); +} + +function BountyCardSkeleton() { + return ( +
    +
    +
    +
    +
    +
    +
    + ); +} + +function Callout() { + return ( +
    +
    + 💸 +
    +
    +

    + We're actively looking for and paying{" "} + contributors. Check out our{" "} + + active bounties + (opens in a new tab) + +

    +
    +
    + ); +} +``` + +
    + +
    +
    React & CSS
    + +```tsx +import { algora, type AlgoraOutput } from "@algora/sdk"; +import React, { useEffect, useState } from "react"; + +// TODO: Use your own color mode hook +import { useColorMode } from "@docusaurus/theme-common"; + +import "./bounties.css"; + +// TODO: Use your own Algora handle +const org = "acme"; +const limit = 3; + +type RemoteData = + | { _tag: "loading" } + | { _tag: "failure"; error: Error } + | { _tag: "success"; data: T }; + +type Bounty = AlgoraOutput["bounty"]["list"]["items"][number]; + +export const Bounties = () => { + const { colorMode } = useColorMode(); + + const [bounties, setBounties] = useState>({ + _tag: "loading", + }); + + useEffect(() => { + const ac = new AbortController(); + + algora.bounty.list + .query({ org, limit, status: "active" }, { signal: ac.signal }) + .then(({ items: data }) => setBounties({ _tag: "success", data })) + .catch((error) => setBounties({ _tag: "failure", error })); + + return () => ac.abort(); + }, []); + + return ( +
    + {bounties._tag === "success" && + bounties.data.map((bounty) => ( +
    + +
    + ))} + {bounties._tag === "loading" && + [...Array(limit).keys()].map((i) => ( +
    + +
    + ))} +
    + ); +}; + +const BountyCard = (props: { bounty: Bounty }) => ( + +
    +
    {props.bounty.reward_formatted}
    +
    + {props.bounty.task.repo_name}#{props.bounty.task.number} +
    +
    {props.bounty.task.title}
    +
    +
    +); + +const BountyCardSkeleton = () => ( +
    +
    +
    +
    +
    +
    +
    +); +``` + +```css +/* bounties.css */ + +.bounty-board { + --gray-50: 210, 40%, 98%; + --gray-100: 210, 40%, 96%; + --gray-200: 214, 32%, 91%; + --gray-300: 213, 27%, 84%; + --gray-400: 215, 20%, 65%; + --gray-500: 215, 16%, 47%; + --gray-600: 215, 19%, 35%; + --gray-700: 215, 25%, 27%; + --gray-800: 217, 33%, 17%; + --gray-900: 222, 47%, 11%; + --gray-950: 229, 84%, 5%; + + --accent-50: 226, 100%, 97%; + --accent-100: 226, 100%, 94%; + --accent-200: 228, 96%, 89%; + --accent-300: 230, 94%, 82%; + --accent-400: 234, 89%, 74%; + --accent-500: 239, 84%, 67%; + --accent-600: 243, 75%, 59%; + --accent-700: 245, 58%, 51%; + --accent-800: 244, 55%, 41%; + --accent-900: 242, 47%, 34%; + --accent-950: 244, 47%, 20%; + + --green-50: 152, 81%, 96%; + --green-100: 149, 80%, 90%; + --green-200: 152, 76%, 80%; + --green-300: 156, 72%, 67%; + --green-400: 158, 64%, 52%; + --green-500: 160, 84%, 39%; + --green-600: 161, 94%, 30%; + --green-700: 163, 94%, 24%; + --green-800: 163, 88%, 20%; + --green-900: 164, 86%, 16%; + --green-950: 166, 91%, 9%; +} + +.bounty-board { + display: grid; + gap: 0.5rem; + width: 100%; +} + +@media (min-width: 640px) { + .bounty-board { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} + +@keyframes bounty-pulse { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } +} + +.bounty-board { + --gradient-to: hsla(var(--accent-400), 0.4); + --gradient-from: hsla(var(--accent-400), 0.2); + --gradient-stops: var(--gradient-from), hsla(var(--accent-400), 0.3), var(--gradient-to); +} + +.bounty-board.dark { + --gradient-to: hsla(var(--accent-600), 0.2); + --gradient-from: hsla(var(--accent-600), 0.3); + --gradient-stops: var(--gradient-from), hsla(var(--accent-600), 0.4), var(--gradient-to); +} + +.bounty-board .bounty-card { + text-decoration-line: none; + display: block; + position: relative; + border-radius: 0.5rem; + border-width: 1px; + height: 100%; + background-image: linear-gradient(to bottom right, var(--gradient-stops)); +} + +.bounty-board .bounty-card *, +.bounty-board .bounty-skeleton * { + transition-property: background-color, color, border-color; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 300ms; +} + +.bounty-board .bounty-card:hover { + border-color: hsl(var(--gray-400)); +} + +.bounty-board .bounty-card .bounty-content { + position: relative; + padding: 1rem; + height: 100%; +} + +.bounty-board .bounty-card .bounty-reward { + font-size: 1.5rem; + line-height: 2rem; + font-weight: 700; + color: hsl(var(--green-500)); +} + +.bounty-board .bounty-card .bounty-issue { + margin-top: 0.125rem; + font-size: 0.875rem; + line-height: 1.25rem; + color: hsl(var(--gray-700)); +} + +.bounty-board .bounty-card .bounty-title { + margin-top: 0.75rem; + font-size: 1.125rem; + line-height: 1.75rem; + font-weight: 500; + line-height: 1.25; + color: hsl(var(--gray-800)); + overflow-wrap: break-word; + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: var(--line-clamp); +} + +.bounty-board.dark .bounty-card .bounty-reward { + color: hsl(var(--green-400)); +} + +.bounty-board.dark .bounty-card .bounty-issue { + color: hsl(var(--accent-200)); +} + +.bounty-board.dark .bounty-card .bounty-title { + color: hsl(var(--accent-50)); +} + +.bounty-board .bounty-card:hover { + background-color: hsla(var(--gray-300), 0.1); + border-color: hsl(var(--gray-400)); +} + +.bounty-board .bounty-card:hover .bounty-reward { + color: hsl(var(--green-600)); +} + +.bounty-board .bounty-card:hover .bounty-issue { + color: hsl(var(--gray-800)); +} + +.bounty-board .bounty-card:hover .bounty-title { + color: hsl(var(--gray-900)); +} + +.bounty-board.dark .bounty-card:hover { + background-color: hsla(var(--gray-600), 0.05); + border-color: hsl(var(--accent-500)); +} + +.bounty-board.dark .bounty-card:hover .bounty-reward { + color: hsl(var(--green-300)); +} + +.bounty-board.dark .bounty-card:hover .bounty-issue { + color: hsl(var(--accent-100)); +} + +.bounty-board.dark .bounty-card:hover .bounty-title { + color: white; +} + +.bounty-board .bounty-skeleton { + border-radius: 0.5rem; + background-color: hsl(var(--gray-200)); + animation: bounty-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; + height: 122px; +} + +.bounty-board.dark .bounty-skeleton { + background-color: hsl(var(--gray-800)); +} + +.bounty-board .bounty-skeleton .bounty-content { + position: relative; + padding: 1rem; + height: 100%; +} + +.bounty-board .bounty-skeleton .bounty-reward { + margin-top: 0.25rem; + border-radius: 0.375rem; + height: 25px; + width: 59px; + background-color: hsl(var(--gray-300)); +} + +.bounty-board .bounty-skeleton .bounty-issue { + margin-top: 0.625rem; + border-radius: 0.375rem; + height: 14px; + width: 86px; + background-color: hsl(var(--gray-300)); +} + +.bounty-board .bounty-skeleton .bounty-title { + margin-top: 1rem; + border-radius: 0.375rem; + height: 20px; + background-color: hsl(var(--gray-300)); +} + +.bounty-board.dark .bounty-skeleton .bounty-reward { + background-color: hsl(var(--gray-700)); +} + +.bounty-board.dark .bounty-skeleton .bounty-issue { + background-color: hsl(var(--gray-700)); +} + +.bounty-board.dark .bounty-skeleton .bounty-title { + background-color: hsl(var(--gray-700)); +} +``` diff --git a/priv/content/docs/embed/shields.md b/priv/content/docs/embed/shields.md new file mode 100644 index 000000000..6326dd95f --- /dev/null +++ b/priv/content/docs/embed/shields.md @@ -0,0 +1,63 @@ +--- +title: "Shields" +--- + +# Shields + +Use these snippets to display your Algora stats on your website, readme etc. + +## Examples + + + Bounty Issues + + +as seen in [Coolify README](https://github.com/coollabsio/coolify) + +```html + + Bounty Issues + +``` + + + Open Bounties + + +as seen in [Cal.com README](https://github.com/calcom/cal.com) + +```html + + Open Bounties + +``` + + + Rewarded Bounties + + +as seen in [Cal.com README](https://github.com/calcom/cal.com) + +```html + + Rewarded Bounties + +``` diff --git a/priv/content/docs/embed/socials.md b/priv/content/docs/embed/socials.md new file mode 100644 index 000000000..3cf1d2819 --- /dev/null +++ b/priv/content/docs/embed/socials.md @@ -0,0 +1,43 @@ +--- +title: "Socials" +--- + +# Socials + +Share your Algora pages on X, Discord, LinkedIn, Bluesky, Reddit, etc. + +## Bounty board + +**Example:** [algora.io/cal/home](https://algora.io/cal/home) + + + Bounty Issues + + +## Profile + +**Example:** [algora.io/neo773/profile](https://algora.io/neo773/profile) + + +Bounty Issues + + +## Crowdfund + +**Example:** [algora.io/coollabsio/bounties/new](https://algora.io/coollabsio/bounties/new) + + + Bounty Issues + diff --git a/priv/content/docs/marketplace/matches.md b/priv/content/docs/marketplace/matches.md new file mode 100644 index 000000000..388cd2800 --- /dev/null +++ b/priv/content/docs/marketplace/matches.md @@ -0,0 +1,7 @@ +--- +title: "Algora matches" +--- + +# Algora matches + +![Algora matches](/images/screenshots/org-matches.png) diff --git a/priv/content/docs/payments.md b/priv/content/docs/payments.md new file mode 100644 index 000000000..48d420f07 --- /dev/null +++ b/priv/content/docs/payments.md @@ -0,0 +1,3266 @@ +--- +title: "Payments" +--- + +# Payments + +## Stripe integration + +Algora partners with Stripe to help you pay collaborators around the world fast & securely. +Payment methods include debit/credit card, ACH & SEPA Direct Debit. +Contributors receive payouts typically 1-3 business days after a payment is completed. + +

    Supported countries/regions

    + +Through Stripe Connect, Algora offers the most comprehensive country coverage available. + +In some countries, such as India & UAE, receiving international payments is limited to sole proprietors, limited liability partnerships and companies (e.g. not available to individuals). + +Payouts to the following countries/regions are supported: + +
    +
    + Albania +
    +
    + Algeria +
    +
    + Angola +
    +
    + Antigua & Barbuda +
    +
    + Argentina +
    +
    + Armenia +
    +
    + Australia +
    +
    + Austria +
    +
    + Azerbaijan +
    +
    + Bahamas +
    +
    + Bahrain +
    +
    + Bangladesh +
    +
    + Belgium +
    +
    + Benin +
    +
    + Bhutan +
    +
    + Bolivia +
    +
    + Bosnia & Herzegovina +
    +
    + Botswana +
    +
    + Brunei +
    +
    + Bulgaria +
    +
    + Cambodia +
    +
    + Canada +
    +
    + Chile +
    +
    + Colombia +
    +
    + Costa Rica +
    +
    + Côte d’Ivoire +
    +
    + Croatia +
    +
    + Cyprus +
    +
    + Czech Republic +
    +
    + Denmark +
    +
    + Dominican Republic +
    +
    + Ecuador +
    +
    + Egypt +
    +
    + El Salvador +
    +
    + Estonia +
    +
    + Ethiopia +
    +
    + Finland +
    +
    + France +
    +
    + Gabon +
    +
    + Gambia +
    +
    + Germany +
    +
    + Ghana +
    +
    + Greece +
    +
    + Guatemala +
    +
    + Guyana +
    +
    + Hong Kong +
    +
    + Hungary +
    +
    + Iceland +
    +
    + India +
    +
    + Indonesia +
    +
    + Ireland +
    +
    + Israel +
    +
    + Italy +
    +
    + Jamaica +
    +
    + Japan +
    +
    + Jordan +
    +
    + Kazakhstan +
    +
    + Kenya +
    +
    + Kuwait +
    +
    + Laos +
    +
    + Latvia +
    +
    + Liechtenstein +
    +
    + Lithuania +
    +
    + Luxembourg +
    +
    + Macao SAR China +
    +
    + Madagascar +
    +
    + Malaysia +
    +
    + Malta +
    +
    + Mauritius +
    +
    + Mexico +
    +
    + Moldova +
    +
    + Monaco +
    +
    + Mongolia +
    +
    + Morocco +
    +
    + Mozambique +
    +
    + Namibia +
    +
    + Netherlands +
    +
    + New Zealand +
    +
    + Niger +
    +
    + Nigeria +
    +
    + North Macedonia +
    +
    + Norway +
    +
    + Oman +
    +
    + Pakistan +
    +
    + Panama +
    +
    + Paraguay +
    +
    + Peru +
    +
    + Philippines +
    +
    + Poland +
    +
    + Portugal +
    +
    + Qatar +
    +
    + Romania +
    +
    + Rwanda +
    +
    + San Marino +
    +
    + Saudi Arabia +
    +
    + Senegal +
    +
    + Serbia +
    +
    + Singapore +
    +
    + Slovakia +
    +
    + Slovenia +
    +
    + South Africa +
    +
    + South Korea +
    +
    + Spain +
    +
    + Sri Lanka +
    +
    + St. Lucia +
    +
    + Sweden +
    +
    + Switzerland +
    +
    + Taiwan +
    +
    + Tanzania +
    +
    + Thailand +
    +
    + Trinidad & Tobago +
    +
    + Tunisia +
    +
    + Turkey +
    +
    + United Arab Emirates +
    +
    + United Kingdom +
    +
    + United States +
    +
    + Uruguay +
    +
    + Uzbekistan +
    +
    + Vietnam +
    +
    + +## Compliance + +Using Stripe, Algora ensures that all international laws & regulations are followed when you pay your collaborators. That means that you are legally covered every time you make a payment. + +If a contributor does not have all the necessary credentials and authorizations required to receive international payments in their country, Stripe will not process payments to them and Algora will notify those individuals accordingly during their onboarding. diff --git a/priv/content/docs/payments/reporting.md b/priv/content/docs/payments/reporting.md new file mode 100644 index 000000000..16354381f --- /dev/null +++ b/priv/content/docs/payments/reporting.md @@ -0,0 +1,29 @@ +--- +title: "Reporting" +--- + +# Reporting + +## Bounty activity + +Your organization’s public page displays a record of all rewarded bounties. + +For example, here you can see the completed bounties of [Remotion.dev](https://console.algora.io/org/remotion/bounties?status=completed) & [Cal.com](https://console.algora.io/org/cal/bounties?status=completed) + +## Year-end filing + +Stripe helps us provide you with a comprehensive record of all your payments to simplify bookkeeping & financial reporting. + +You can view all your transactions and export a summary in your organization's workspace. [Email us](info@algora.io) for a custom report. + +## Work classification + +Bounties are classified as non-employee compensation (contract work / freelancing). + +For organizations and bounty solvers based in the United States, Algora Public Benefit Corporation submits 1099 forms to the IRS and the corresponding states. + +## 1099s + +If your US-based organization has awarded bounties to US-based developers, you are all set! Algora takes care of submitting 1099s, no further action is required on your end. + +If you are a US-based developer and have received bounty payouts, Algora makes an information disclosure to the IRS and your state about your earnings. All you have to do is report your earnings when filing your federal & state taxes. By the end of January every year you will be receiving a 1099-NEC Form from Algora summing up your earnings from last year. This is to help you report the exact amount you earned when filing your taxes. diff --git a/priv/content/docs/tips/send.md b/priv/content/docs/tips/send.md new file mode 100644 index 000000000..eb28d01e3 --- /dev/null +++ b/priv/content/docs/tips/send.md @@ -0,0 +1,21 @@ +--- +title: "Send tips" +--- + +# Send a tip on GitHub + +Use the `/tip $100 @username` command to send a tip to any GitHub user. + +Send a tip on GitHub + +# Send a tip on Algora + +Click the **Tip** button next to a contributor's name on your dashboard. + +Send a tip on GitHub + +## Proceed to checkout + +Enter the details and finalize the payment on Stripe. + +Send a tip on GitHub 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. + +![Set up autopay](/images/docs/autopay.png) 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 + +![](/images/screenshots/org-home.png) 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! + +![Customize bot messages](/images/docs/custom-bot-messages.png) 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 + +![](/images/docs/leaderboard.png) 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 + +![](/images/screenshots/org-transactions.png) 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! """