diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000..3fd33642 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,16 @@ +FROM node:20-bookworm + +ENV LANG=C.UTF-8 +ENV LC_ALL=C.UTF-8 + +RUN apt-get update && apt-get install -y \ + foomatic-db-engine \ + foomatic-db-compressed-ppds \ + cups-filters \ + ghostscript \ + bsdmainutils \ + libxml2-utils \ + xsltproc \ + python3 \ + python3-pip \ + && rm -rf /var/lib/apt/lists/* diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..37c4d8d5 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,18 @@ +{ + "name": "openprinting-github-io", + "build": { + "dockerfile": "Dockerfile" + }, + "forwardPorts": [3000], + "postCreateCommand": "yarn install && yarn foomatic:data:generate", + "remoteUser": "node", + "customizations": { + "vscode": { + "extensions": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "bradlc.vscode-tailwindcss" + ] + } + } +} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..da3b067c --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,80 @@ +name: Build & Test Next.js site + +on: + pull_request: + types: [opened, synchronize, reopened] + + push: + branches: [master] + + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Detect package manager + id: pm + run: | + # Prefer pnpm, then yarn, otherwise npm + if [ -f pnpm-lock.yaml ]; then + echo "manager=pnpm" >> $GITHUB_OUTPUT + echo "install=install --frozen-lockfile" >> $GITHUB_OUTPUT + echo "runner=pnpm run" >> $GITHUB_OUTPUT + elif [ -f yarn.lock ]; then + echo "manager=yarn" >> $GITHUB_OUTPUT + echo "install=install --immutable" >> $GITHUB_OUTPUT + echo "runner=yarn" >> $GITHUB_OUTPUT + else + echo "manager=npm" >> $GITHUB_OUTPUT + echo "install=ci" >> $GITHUB_OUTPUT + echo "runner=npm run" >> $GITHUB_OUTPUT + fi + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + # Corepack must be enabled *after* setup-node so the Yarn 4 shim attaches + # to the Node that runs the build. (setup-node's built-in `cache: yarn` + # is intentionally omitted: its `yarn cache dir` probe runs the runner's + # Yarn 1, which aborts on the `packageManager: yarn@4` pin.) + - name: Enable Corepack + run: corepack enable + + - name: Install Foomatic system packages + run: | + sudo apt-get update + sudo apt-get install -y \ + foomatic-db-engine \ + foomatic-db-compressed-ppds \ + cups-filters \ + ghostscript \ + bsdmainutils \ + libxml2-utils \ + xsltproc \ + python3 \ + python3-pip + + - name: Install dependencies + run: ${{ steps.pm.outputs.manager }} ${{ steps.pm.outputs.install }} + + - name: Run linter + run: ${{ steps.pm.outputs.runner }} lint + + - name: Build Next.js + run: ${{ steps.pm.outputs.runner }} build diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000..52019076 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,93 @@ +name: Deploy Next.js site to Pages + +on: + push: + branches: [master] + + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Detect package manager + id: detect-package-manager + run: | + if [ -f "${{ github.workspace }}/yarn.lock" ]; then + echo "manager=yarn" >> $GITHUB_OUTPUT + echo "command=install --immutable" >> $GITHUB_OUTPUT + echo "runner=yarn" >> $GITHUB_OUTPUT + exit 0 + elif [ -f "${{ github.workspace }}/package.json" ]; then + echo "manager=npm" >> $GITHUB_OUTPUT + echo "command=ci" >> $GITHUB_OUTPUT + echo "runner=npx --no-install" >> $GITHUB_OUTPUT + exit 0 + else + echo "Unable to determine package manager" + exit 1 + fi + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "20" + # Enable Corepack after setup-node so the Yarn 4 shim attaches to the + # active Node. setup-node's `cache: yarn` is omitted because its + # `yarn cache dir` probe runs Yarn 1 and aborts on the packageManager pin. + - name: Enable Corepack + run: corepack enable + - name: Install Foomatic system packages + run: | + sudo apt-get update + sudo apt-get install -y \ + foomatic-db-engine \ + foomatic-db-compressed-ppds \ + cups-filters \ + ghostscript \ + bsdmainutils \ + libxml2-utils \ + xsltproc \ + python3 \ + python3-pip + - name: Setup Pages + uses: actions/configure-pages@v5 + with: + static_site_generator: next + - name: Restore cache + uses: actions/cache@v4 + with: + path: | + .next/cache + key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }} + restore-keys: | + ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}- + - name: Install dependencies + run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }} + - name: Build with Next.js + run: ${{ steps.detect-package-manager.outputs.runner }} build + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./out + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 17692e16..0ccac6c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,32 +1,45 @@ -# General +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc .DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -_site/ -.sass-cache/ -.jekyll-cache/ -.jekyll-metadata -Gemfile.lock +*.pem +/cache +/public/foomatic-db +/public/ppds +/public/feed.xml + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 8770f1f9..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,203 +0,0 @@ -{ - "cSpell.words": [ - "Aaditya", - "Aakarsh", - "Aaryan", - "Abelardo", - "Abhishek", - "Abrar", - "Aditya", - "Adlair", - "Aishwarya", - "Aizat", - "Akash", - "Akhtar", - "Alteholz", - "Andreia", - "Anmol", - "Ansh", - "Arjun", - "Arora", - "autotest", - "autotests", - "Aveek", - "Ayhens", - "Ayush", - "Bandlish", - "Basu", - "Benzies", - "bhaiyaa", - "Bhaktapur", - "Bhat", - "Bhatt", - "Bhattacharya", - "Bhattarai", - "Bhavani", - "Brodie", - "Cerecedo", - "CFFI", - "Chakraborty", - "Chaudhary", - "Chelliah", - "Choo", - "Constantino", - "CWRU", - "Delite", - "Dests", - "Dhanabal", - "Didier", - "Diksha", - "Diogo", - "Diptangshu", - "displayer", - "distro", - "Divy", - "Dolan", - "Fediverse", - "fenris", - "FOSDEM", - "FOSS", - "functools", - "Gaikwad", - "Gaspari", - "Gauri", - "Ghai", - "Goel", - "gsoc", - "hackathon", - "Hanno", - "Hardik", - "Haro", - "Hergert", - "Hsiao", - "IITK", - "importability", - "Indico", - "ippeveprinter", - "ippusb", - "Jaffari", - "Jayanth", - "JECRC", - "Jinda", - "Kamarudzzaman", - "Kannan", - "Karki", - "Karlitschek", - "Karnad", - "Khairul", - "Khandelwal", - "Khusaini", - "Kondeti", - "Kraleti", - "Kshiitij", - "Kuriakose", - "Kyaw", - "Lakshay", - "Lexmark", - "Liang", - "libcuos", - "libpdfrip", - "libusb", - "Madon", - "maintainership", - "Manav", - "Manvith", - "Meixner", - "Mentorships", - "microcontroller", - "microcontrollers", - "Mopria", - "Moudgalya", - "Muhd", - "Mulcahy", - "Nagarkot", - "Nasir", - "Neeraj", - "Nextcloud", - "Nikitha", - "Novosyolov", - "Oliviera", - "OOSC", - "Owais", - "Paloma", - "Pande", - "PAPPL", - "Paritoshik", - "Parulekar", - "Pathak", - "Patil", - "pdfio", - "Pfeifle", - "Phatak", - "Poddar", - "Pokharel", - "Poot", - "Popey", - "Poppler", - "Prajwal", - "printsupport", - "Priya", - "Priyam", - "Programiz", - "QPDF", - "Raboud", - "Rashika", - "repost", - "reposts", - "represet", - "Ressington", - "Sagar", - "Sahil", - "Sailesh", - "Saiyam", - "sandboxable", - "Sandboxed", - "Sankaranarayanan", - "Saquib", - "Scaniverse", - "Schuchardt", - "Selphy", - "Shanthi", - "Shree", - "Shreya", - "Shrishti", - "Shuah", - "Siddharth", - "singledispatch", - "Sinha", - "Snapcrafters", - "Suman", - "Sumanto", - "Sundaray", - "Syazwan", - "Tabrez", - "Tarakiyee", - "Tatineni", - "Thamel", - "Thinzar", - "Thorsten", - "Tiwari", - "toolkits", - "Tunnell", - "Uddhav", - "Upadhyay", - "usbip", - "Utkarsh", - "Utsav", - "Varad", - "Varun", - "Vedika", - "Velasco", - "Vidushi", - "Viswanath", - "Völckers", - "Vovk", - "Yeonguk", - "Youngbin", - "Yuning", - "Yush", - "Zulla", - "ಅಣ್ಣ", - "ಧನ್ಯವಾದಗಳು" - ] -} \ No newline at end of file diff --git a/.yarnrc.yml b/.yarnrc.yml new file mode 100644 index 00000000..3186f3f0 --- /dev/null +++ b/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/404.html b/404.html deleted file mode 100644 index d580353a..00000000 --- a/404.html +++ /dev/null @@ -1,38 +0,0 @@ ---- -layout: default ---- - - - -
-

404

- -

Page not found :(

-

The requested page could not be found.

-
diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..8fc26a3d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,128 @@ +# AGENTS.md + +## Purpose + +This repository is the source for the OpenPrinting website. It is a Next.js App Router site that statically exports to GitHub Pages. + +When reviewing changes in this repo, optimize for: + +- behavioral regressions in page generation, routing, and content loading +- breakage specific to static export and GitHub Pages deployment +- content/rendering issues in Markdown-driven pages +- accidental edits to generated artifacts or vendored output + +## Repository Map + +- `app/`: route handlers and page entry points +- `components/`: shared UI, Markdown rendering, navigation, search UI +- `contents/`: source content in Markdown +- `data/`: structured data for authors, GSOC/GSOD pages, summaries +- `lib/`: shared helpers for content loading, image path handling, search runtime +- `scripts/search/`: build-time search index generation +- `public/`: static assets and generated search index output + +## Source Of Truth + +Treat these as source files: + +- `app/**` +- `components/**` +- `contents/**` +- `data/**` +- `lib/**` +- `scripts/**` +- config files such as `package.json`, `tsconfig.json`, `next.config.ts`, `eslint.config.mjs` + +Treat these as generated or build output and review them only when the change explicitly requires regeneration: + +- `.next/` +- `out/` +- `public/search/static-index.json` +- `node_modules/` + +If a PR changes generated output without changing the inputs that produce it, call that out. + +## Architecture Notes + +- Static export is enabled in [`next.config.ts`](/Users/rudra/Desktop/workspace/openprinting/openprinting.github.io/next.config.ts). `output: "export"` means features requiring a server runtime are risky by default. +- Production builds compute `basePath` and `assetPrefix` dynamically via `config/site.config.ts`. Absolute links, image paths, and asset references must continue to work correctly under this generated prefix. Do not hardcode strings like `/openprinting.github.io`. +- Search index generation runs in `prebuild` via `tsx scripts/search/build-index.ts`. Changes affecting content extraction, slugs, URLs, or searchable text often require regenerating `public/search/static-index.json`. +- A large part of the site is Markdown-driven. Review content pipeline changes for frontmatter assumptions, slug handling, excerpt/title sanitization, and image resolution. +- This repo uses Yarn as the expected package manager. Flag changes that introduce package-manager drift or inconsistent lockfile/package-manager usage unless the migration is intentional. + +## Configuration & Portability + +- **Single Source of Truth**: All deployment-specific values, such as GitHub organization / repository names, base paths, and external URLs (e.g., Giscus configs, CI pipelines), are centralized in `config/site.config.ts`. +- **Migration Guide**: When migrating the repository or deploying to a new location, update `config/site.config.ts`. Always import `siteConfig` from `"@/config/site.config"` rather than hardcoding. + +## Review Focus + +### Routing and content loading + +- Check that route params map to the right content directories. +- Watch for slug mismatches between file names, generated URLs, and redirects. +- For dynamic routes like `app/[...slug]`, `app/documentation/[doc]`, and `app/projects/[project]`, verify not-found and redirect behavior still makes sense for static export. + +### Static export constraints + +- Flag use of features that depend on request-time server execution unless the repo already supports them safely. +- Be suspicious of changes that assume root-relative assets without considering the production `basePath`. +- For images and links, prefer helpers already used by the repo such as `getImageSrc`. +- Check that asset `src` values are valid for both local development and production export. A change that appears to work locally but breaks under the production prefix should be treated as a bug. + +### UI and styling + +- UI changes should follow the current visual theme of the site rather than introducing a disconnected style. +- Verify layouts remain responsive across common mobile and desktop widths. +- Confirm UI changes remain compatible with both light mode and dark mode, including text contrast, borders, icons, and code/content surfaces. + +### Markdown rendering and content safety + +- Review changes to [`components/markdown-renderer.tsx`](/Users/rudra/Desktop/workspace/openprinting/openprinting.github.io/components/markdown-renderer.tsx) carefully. It uses `rehype-raw`, so rendering changes can have broad effects on embedded HTML in content. +- Confirm frontmatter fields remain optional where the content corpus is inconsistent. +- Check that teaser images, author metadata, and reading time logic still degrade gracefully for older posts. + +### Search + +- Review `scripts/search/*`, `lib/search/*`, and `public/search/static-index.json` together. +- If URL generation or content extraction changes, verify the search index schema and document URLs remain consistent with the app routes. + +### Content-heavy changes + +- When reviewing bulk Markdown edits, prioritize broken links, malformed frontmatter, invalid image paths, and dates/slugs that affect sorting or routing. +- For post metadata, note that date parsing affects ordering in helpers such as [`lib/get-latest-posts.ts`](/Users/rudra/Desktop/workspace/openprinting/openprinting.github.io/lib/get-latest-posts.ts). + +## Validation Commands + +Use the smallest relevant validation first, then escalate to a full build for routing/content pipeline changes. + +```bash +yarn lint +yarn build +``` + +What each command validates here: + +- `yarn lint`: code quality and some framework-level issues +- `yarn build`: static export viability and search index generation + +There does not appear to be a dedicated test suite in this repo. If you cannot run a command, say so explicitly in the review. + +## Review Output Expectations + +When reviewing a change, lead with findings, not a summary. Prioritize: + +1. broken routes or static export regressions +2. asset path and `basePath` mistakes +3. content parsing or Markdown rendering regressions +4. generated-file churn without corresponding source changes +5. missing validation for risky changes + +If no issues are found, say that explicitly and mention any residual risk, especially when a full `npm run build` was not run. + +## Editing Guidance For Agents + +- Avoid editing generated directories unless the task explicitly requires regeneration. +- Do not overwrite user changes in generated artifacts to "clean up" the diff. +- If content or search behavior changes, mention whether `public/search/static-index.json` should be regenerated. +- Keep new code compatible with static export unless the task clearly changes deployment assumptions. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index f88d0ae9..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,30 +0,0 @@ -## How to contribute - -Help from community is necessary to make any opensource project great. We want to keep it as easy as possible for community to contribute changes. There are a few guidelines that we need to follow so that it is easy for others to understand and change the codebase. - -### Getting Started -* Setup jekyll environment. You can follow [this link](https://jekyllrb.com/docs/). -* Now, you have a working jekyll environment. Clone the source code from [github](https://github.com/OpenPrinting/openprinting.github.io). -* Go to the directory and run: -``` -bundle exec jekyll serve -``` -* If you want to access website from some other device on local network, use: -``` -bundle exec jekyll serve --host=0.0.0.0 -``` -* Open ``` localhost:4000 ``` - -### Issues -* If you want to work on some issue, first comment on that issue that you want to work. -* If you want to open a new Issue. First make sure similiar issue is not present. -* In case of a bug, always mention browser you are using because different browsers may behave differently. -* In case of an Idea, please mention how it will change user experience and/or how it will enhance functionality of the website. - -### Pull Requests -* If you have made some changes in the codebase and want to generate a PR. First, pull latest version of code from [upstream](https://github.com/Esri/developer-support/wiki/Setting-the-upstream-for-a-fork). Remove all merge conflicts before generating PR. -* In the PR, try to add working link of your work and if that is not possible, add screenshots. - -### Making changes -* Whenever you are working on some major feature, always create a [new branch](https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging). -* Whenever you add something above trivial, please add comments. diff --git a/DEVELOPING.md b/DEVELOPING.md deleted file mode 100644 index 58d1f965..00000000 --- a/DEVELOPING.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: DEVELOPING ---- -## Adding Disqus to your page: - -Disqus uses page's title to keep comments on different pages seperate. So, always set ```title``` of a page. - -For adding comments section to any page simply add these lines to the page: -``` -
-{% if site.comments.provider and page.comments %} - {% include comments.html %} -{% endif %} -
-``` -You don't need to add above lines, if you are using ```single``` layout. - -Don't forget to turn on comments in yaml: -``` ---- -comments: true ---- -``` \ No newline at end of file diff --git a/Gemfile b/Gemfile deleted file mode 100644 index 53f90aba..00000000 --- a/Gemfile +++ /dev/null @@ -1,11 +0,0 @@ -source "https://rubygems.org" - -gem "github-pages", group: :jekyll_plugins -# gem "minimal-mistakes-jekyll" -group :jekyll_plugins do - gem "jekyll-include-cache" - gem 'jekyll-algolia' - #gem "jekyll-feed", "~> 0.6" -end - -gem "kramdown-parser-gfm" \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index e4f36a4c..00000000 --- a/Gemfile.lock +++ /dev/null @@ -1,317 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - activesupport (8.0.4.1) - base64 - benchmark (>= 0.3) - bigdecimal - concurrent-ruby (~> 1.0, >= 1.3.1) - connection_pool (>= 2.2.5) - drb - i18n (>= 1.6, < 2) - logger (>= 1.4.2) - minitest (>= 5.1, < 6) - securerandom (>= 0.3) - tzinfo (~> 2.0, >= 2.0.5) - uri (>= 0.13.1) - addressable (2.9.0) - public_suffix (>= 2.0.2, < 8.0) - algolia_html_extractor (2.6.4) - json (~> 2.0) - nokogiri (~> 1.10) - algoliasearch (1.27.5) - httpclient (~> 2.8, >= 2.8.3) - json (>= 1.5.1) - base64 (0.3.0) - benchmark (0.5.0) - bigdecimal (4.0.1) - coffee-script (2.4.1) - coffee-script-source - execjs - coffee-script-source (1.12.2) - colorator (1.1.0) - commonmarker (0.23.11) - concurrent-ruby (1.3.6) - connection_pool (3.0.2) - csv (3.3.2) - dnsruby (1.73.1) - base64 (>= 0.2) - logger (~> 1.6) - simpleidn (~> 0.2.1) - drb (2.2.3) - em-websocket (0.5.3) - eventmachine (>= 0.12.9) - http_parser.rb (~> 0) - ethon (0.16.0) - ffi (>= 1.15.0) - eventmachine (1.2.7) - execjs (2.10.0) - faraday (2.14.2) - faraday-net_http (>= 2.0, < 3.5) - json - logger - faraday-net_http (3.4.2) - net-http (~> 0.5) - ffi (1.17.1) - ffi (1.17.1-arm64-darwin) - ffi (1.17.1-x86_64-linux-gnu) - filesize (0.2.0) - forwardable-extended (2.6.0) - gemoji (4.1.0) - github-pages (232) - github-pages-health-check (= 1.18.2) - jekyll (= 3.10.0) - jekyll-avatar (= 0.8.0) - jekyll-coffeescript (= 1.2.2) - jekyll-commonmark-ghpages (= 0.5.1) - jekyll-default-layout (= 0.1.5) - jekyll-feed (= 0.17.0) - jekyll-gist (= 1.5.0) - jekyll-github-metadata (= 2.16.1) - jekyll-include-cache (= 0.2.1) - jekyll-mentions (= 1.6.0) - jekyll-optional-front-matter (= 0.3.2) - jekyll-paginate (= 1.1.0) - jekyll-readme-index (= 0.3.0) - jekyll-redirect-from (= 0.16.0) - jekyll-relative-links (= 0.6.1) - jekyll-remote-theme (= 0.4.3) - jekyll-sass-converter (= 1.5.2) - jekyll-seo-tag (= 2.8.0) - jekyll-sitemap (= 1.4.0) - jekyll-swiss (= 1.0.0) - jekyll-theme-architect (= 0.2.0) - jekyll-theme-cayman (= 0.2.0) - jekyll-theme-dinky (= 0.2.0) - jekyll-theme-hacker (= 0.2.0) - jekyll-theme-leap-day (= 0.2.0) - jekyll-theme-merlot (= 0.2.0) - jekyll-theme-midnight (= 0.2.0) - jekyll-theme-minimal (= 0.2.0) - jekyll-theme-modernist (= 0.2.0) - jekyll-theme-primer (= 0.6.0) - jekyll-theme-slate (= 0.2.0) - jekyll-theme-tactile (= 0.2.0) - jekyll-theme-time-machine (= 0.2.0) - jekyll-titles-from-headings (= 0.5.3) - jemoji (= 0.13.0) - kramdown (= 2.4.0) - kramdown-parser-gfm (= 1.1.0) - liquid (= 4.0.4) - mercenary (~> 0.3) - minima (= 2.5.1) - nokogiri (>= 1.16.2, < 2.0) - rouge (= 3.30.0) - terminal-table (~> 1.4) - webrick (~> 1.8) - github-pages-health-check (1.18.2) - addressable (~> 2.3) - dnsruby (~> 1.60) - octokit (>= 4, < 8) - public_suffix (>= 3.0, < 6.0) - typhoeus (~> 1.3) - html-pipeline (2.14.3) - activesupport (>= 2) - nokogiri (>= 1.4) - http_parser.rb (0.8.0) - httpclient (2.9.0) - mutex_m - i18n (1.14.8) - concurrent-ruby (~> 1.0) - jekyll (3.10.0) - addressable (~> 2.4) - colorator (~> 1.0) - csv (~> 3.0) - em-websocket (~> 0.5) - i18n (>= 0.7, < 2) - jekyll-sass-converter (~> 1.0) - jekyll-watch (~> 2.0) - kramdown (>= 1.17, < 3) - liquid (~> 4.0) - mercenary (~> 0.3.3) - pathutil (~> 0.9) - rouge (>= 1.7, < 4) - safe_yaml (~> 1.0) - webrick (>= 1.0) - jekyll-algolia (1.7.1) - algolia_html_extractor (~> 2.6) - algoliasearch (~> 1.26) - filesize (~> 0.1) - jekyll (>= 3.6, < 5.0) - json (~> 2.0) - nokogiri (~> 1.6) - progressbar (~> 1.9) - verbal_expressions (~> 0.1.5) - jekyll-avatar (0.8.0) - jekyll (>= 3.0, < 5.0) - jekyll-coffeescript (1.2.2) - coffee-script (~> 2.2) - coffee-script-source (~> 1.12) - jekyll-commonmark (1.4.0) - commonmarker (~> 0.22) - jekyll-commonmark-ghpages (0.5.1) - commonmarker (>= 0.23.7, < 1.1.0) - jekyll (>= 3.9, < 4.0) - jekyll-commonmark (~> 1.4.0) - rouge (>= 2.0, < 5.0) - jekyll-default-layout (0.1.5) - jekyll (>= 3.0, < 5.0) - jekyll-feed (0.17.0) - jekyll (>= 3.7, < 5.0) - jekyll-gist (1.5.0) - octokit (~> 4.2) - jekyll-github-metadata (2.16.1) - jekyll (>= 3.4, < 5.0) - octokit (>= 4, < 7, != 4.4.0) - jekyll-include-cache (0.2.1) - jekyll (>= 3.7, < 5.0) - jekyll-mentions (1.6.0) - html-pipeline (~> 2.3) - jekyll (>= 3.7, < 5.0) - jekyll-optional-front-matter (0.3.2) - jekyll (>= 3.0, < 5.0) - jekyll-paginate (1.1.0) - jekyll-readme-index (0.3.0) - jekyll (>= 3.0, < 5.0) - jekyll-redirect-from (0.16.0) - jekyll (>= 3.3, < 5.0) - jekyll-relative-links (0.6.1) - jekyll (>= 3.3, < 5.0) - jekyll-remote-theme (0.4.3) - addressable (~> 2.0) - jekyll (>= 3.5, < 5.0) - jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) - rubyzip (>= 1.3.0, < 3.0) - jekyll-sass-converter (1.5.2) - sass (~> 3.4) - jekyll-seo-tag (2.8.0) - jekyll (>= 3.8, < 5.0) - jekyll-sitemap (1.4.0) - jekyll (>= 3.7, < 5.0) - jekyll-swiss (1.0.0) - jekyll-theme-architect (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-cayman (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-dinky (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-hacker (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-leap-day (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-merlot (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-midnight (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-minimal (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-modernist (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-primer (0.6.0) - jekyll (> 3.5, < 5.0) - jekyll-github-metadata (~> 2.9) - jekyll-seo-tag (~> 2.0) - jekyll-theme-slate (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-tactile (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-time-machine (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-titles-from-headings (0.5.3) - jekyll (>= 3.3, < 5.0) - jekyll-watch (2.2.1) - listen (~> 3.0) - jemoji (0.13.0) - gemoji (>= 3, < 5) - html-pipeline (~> 2.2) - jekyll (>= 3.0, < 5.0) - json (2.19.5) - kramdown (2.4.0) - rexml - kramdown-parser-gfm (1.1.0) - kramdown (~> 2.0) - liquid (4.0.4) - listen (3.9.0) - rb-fsevent (~> 0.10, >= 0.10.3) - rb-inotify (~> 0.9, >= 0.9.10) - logger (1.7.0) - mercenary (0.3.6) - mini_portile2 (2.8.9) - minima (2.5.1) - jekyll (>= 3.5, < 5.0) - jekyll-feed (~> 0.9) - jekyll-seo-tag (~> 2.1) - minitest (5.27.0) - mutex_m (0.3.0) - net-http (0.9.1) - uri (>= 0.11.1) - nokogiri (1.19.3) - mini_portile2 (~> 2.8.2) - racc (~> 1.4) - nokogiri (1.19.3-arm64-darwin) - racc (~> 1.4) - nokogiri (1.19.3-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.19.3-x86_64-linux-gnu) - racc (~> 1.4) - octokit (4.25.1) - faraday (>= 1, < 3) - sawyer (~> 0.9) - pathutil (0.16.2) - forwardable-extended (~> 2.6) - progressbar (1.13.0) - public_suffix (5.1.1) - racc (1.8.1) - rb-fsevent (0.11.2) - rb-inotify (0.11.1) - ffi (~> 1.0) - rexml (3.4.2) - rouge (3.30.0) - rubyzip (2.4.1) - safe_yaml (1.0.5) - sass (3.7.4) - sass-listen (~> 4.0.0) - sass-listen (4.0.0) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - sawyer (0.9.2) - addressable (>= 2.3.5) - faraday (>= 0.17.3, < 3) - securerandom (0.4.1) - simpleidn (0.2.3) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) - typhoeus (1.4.1) - ethon (>= 0.9.0) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unicode-display_width (1.8.0) - uri (1.1.1) - verbal_expressions (0.1.5) - webrick (1.9.1) - -PLATFORMS - ruby - universal-darwin-23 - x86_64-linux - -DEPENDENCIES - github-pages - jekyll-algolia - jekyll-include-cache - kramdown-parser-gfm - -BUNDLED WITH - 2.5.16 diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 916fc954..00000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2019 OpenPrinting - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 00000000..ff271a5c --- /dev/null +++ b/README.md @@ -0,0 +1,71 @@ +# OpenPrinting Website + +The official website for [OpenPrinting](https://openprinting.github.io/), built with Next.js, Tailwind CSS, and Framer Motion. + +OpenPrinting is a Linux Foundation workgroup that manages the printing architecture for Linux and UNIX-like operating systems. + +## Getting Started + +First, make sure you have [Node.js](https://nodejs.org/) installed, and then install the dependencies using Yarn: + +```bash +yarn install +``` + +Start the development server: + +```bash +yarn dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +## Project Structure + +- `app/` - Next.js App Router containing pages and layouts. +- `components/` - Reusable UI components. +- `contents/` - Markdown content representing news, blogs, and documentation. +- `lib/` - Utility functions and shared library code. +- `scripts/` - Build scripts, such as search index generation. +- `public/` - Static files and assets. + +## Contributing + +Contributions are welcome! Please open an issue or submit a pull request if you find a bug or want to propose an enhancement. + +When making UI changes, please follow the existing Tailwind CSS design patterns. + +## Deployment + +This project is meant to be deployed statically on GitHub Pages. Note that Next.js is configured for static export in this repository. + +To build the static export locally: + +```bash +yarn build +``` + +This will generate an `out/` directory containing the static HTML/CSS/JS files which are then hosted on GitHub Pages. + +## Migration Notes + +Deployment-owned values are centralized in [`config/site.config.ts`](./config/site.config.ts). When migrating this repository, update that file first for: + +- repository owner/name and base path behavior +- canonical site origin and RSS path +- GitHub, CUPS, drivers, and other deployment-owned external destinations +- brand metadata used by layout, cards, and social links +- Giscus discussion settings + +Generated outputs should only be committed when source changes require regeneration: + +- `public/feed.xml` +- `public/search/static-index.json` +- `public/search/foomatic-index.json` +- generated Foomatic data under `public/foomatic-db/` + +## Naming Conventions + +- Route files follow Next.js App Router conventions. +- Reusable React component filenames should converge on a single convention over time. +- In this pass, existing mixed naming is preserved unless a touched area needs cleanup to stay consistent. diff --git a/_config.yml b/_config.yml deleted file mode 100644 index 8240a6e4..00000000 --- a/_config.yml +++ /dev/null @@ -1,429 +0,0 @@ -# Copyright 2020 OpenPrinting - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at - -# http://www.apache.org/licenses/LICENSE-2.0 - -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Welcome to Jekyll! -# -# This config file is meant for settings that affect your entire site, values -# which you are expected to set up once and rarely need to edit after that. -# For technical reasons, this file is *NOT* reloaded automatically when you use -# `jekyll serve`. If you change this file, please restart the server process. - -remote_theme : "mmistakes/minimal-mistakes@4.20.1" -# theme: minimal-mistakes-jekyll -minimal_mistakes_skin : "air" # "air", "aqua", "contrast", "dark", "dirt", "neon", "mint", "plum", "sunrise" - -# Site Settings -locale : "en-US" -title : "OpenPrinting" -title_separator : "-" -name : "OpenPrinting" -description : "Making Printing Just Work." -url : https://openprinting.github.io # the base hostname & protocol for your site e.g. "https://mmistakes.github.io" -baseurl : # the subpath of your site, e.g. "/blog" -repository : "openprinting/openprinting.github.io" # GitHub username/repo-name e.g. "mmistakes/minimal-mistakes" -teaser : # path of fallback teaser image, e.g. "/assets/images/500x300.png" -# breadcrumbs : false # true, false (default) -words_per_minute : 200 -comments: - provider : "disqus" # false (default), "disqus", "discourse", "facebook", "google-plus", "staticman", "utterances", "custom" - disqus: - shortname : openprinting-org # https://help.disqus.com/customer/portal/articles/466208-what-s-a-shortname- - discourse: - server : # https://meta.discourse.org/t/embedding-discourse-comments-via-javascript/31963 , e.g.: meta.discourse.org - facebook: - # https://developers.facebook.com/docs/plugins/comments - appid : - num_posts : # 5 (default) - colorscheme : # "light" (default), "dark" - utterances: - theme : # "github-light" (default), "github-dark" -staticman: - allowedFields : ['name', 'email', 'url', 'message'] - branch : # "master", "gh-pages" - commitMessage : "New comment by {fields.name}" - filename : comment-{@timestamp} - format : "yml" - moderation : true - path : "_data/comments/{options.slug}" - requiredFields : ['name', 'email', 'message'] - transforms: - email : "md5" - generatedFields: - date: - type : "date" - options: - format : "iso8601" # "iso8601" (default), "timestamp-seconds", "timestamp-milliseconds" - endpoint : # URL of your own deployment with trailing slash, will fallback to the public instance -atom_feed: - path : # blank (default) uses feed.xml -search : true # true, false (default) -search_full_content : true # true, false (default) -search_provider : "algolia" -algolia: - application_id : "QB6HVGBSBA" - index_name : "dev_minimal-mistakes" - search_only_api_key : "9d5014e5bbc77372547bce778dfa5663" - powered_by : true - -# SEO Related -google_site_verification : -bing_site_verification : -yandex_site_verification : - -# Social Sharing -og_image : "/assets/images/bio-photo.jpg" -# For specifying social profiles -# - https://developers.google.com/structured-data/customize/social-profiles -social: - type : # Person or Organization (defaults to Person) - name : # If the user or organization name differs from the site's name - links: # An array of links to social media profiles - -# Analytics -analytics: - provider : false # false (default), "google", "google-universal", "custom" - google: - tracking_id : - - -# Site Author -author: - name : "OpenPrinting" - avatar : "/assets/images/logo.png" - bio : "Making Printing Just Work!" - location : "The Linux Foundation" - links: - - label: "Website" - icon: "fas fa-fw fa-link" - url: "https://www.openprinting.org/" - - label: "GitHub" - icon: "fab fa-fw fa-github" - url: "https://github.com/openprinting" - - label: "Mastodon" - icon: "fab fa-fw fa-mastodon" - url: "https://ubuntu.social/tags/OpenPrinting" - - label: "LinkedIn" - icon: "fab fa-fw fa-linkedin" - url: "https://www.linkedin.com/company/openprinting/posts/" - -# Site Footer -footer: - links: - - label: "GitHub" - icon: "fab fa-fw fa-github" - url: "https://github.com/openprinting" - - label: "Mastodon" - icon: "fab fa-fw fa-mastodon" - url: "https://ubuntu.social/tags/OpenPrinting" - - label: "LinkedIn" - icon: "fab fa-fw fa-linkedin" - url: "https://www.linkedin.com/company/openprinting/posts/" - - label: "Code of Conduct" - icon: "fas fa-file-contract" - url: "/codeofconduct/" - -# Reading Files -include: - - .htaccess - - _pages - - _docpages - - printers.html - - airprint.json -exclude: - - "*.sublime-project" - - "*.sublime-workspace" - - vendor - - .asset-cache - - .bundle - - .jekyll-assets-cache - - .sass-cache - - assets/js/plugins - - assets/js/_main.js - - assets/js/vendor - - Capfile - - CHANGELOG - - config - - Gemfile - - Gruntfile.js - - gulpfile.js - - LICENSE - - log - - node_modules - - package.json - - Rakefile - - README - - tmp -keep_files: - - .git - - .svn -encoding: "utf-8" -markdown_ext: "markdown,mkdown,mkdn,mkd,md" - -# Liquid -strict_front_matter: true -liquid: - error_mode: strict - -# Conversion -markdown: kramdown -highlighter: rouge -lsi: false -excerpt_separator: "\n\n" -incremental: false - - -# Markdown Processing -kramdown: - input: GFM - hard_wrap: false - auto_ids: true - footnote_nr: 1 - entity_output: as_char - toc_levels: 1..6 - smart_quotes: lsquo,rsquo,ldquo,rdquo - enable_coderay: false - - -# Sass/SCSS -sass: - sass_dir: _sass - style: compressed # http://sass-lang.com/documentation/file.SASS_REFERENCE.html#output_style - - -# Outputting -permalink: /:categories/:title/ -paginate: 5 # amount of posts to show -paginate_path: /page:num/ -timezone: # http://en.wikipedia.org/wiki/List_of_tz_database_time_zones - - -# Plugins (previously gems:) -plugins: - - jekyll-feed - - jekyll-include-cache - -# Collections -collections: - gsoc2020: - output: true - permalink: /:collection/:path/ - gsoc2021: - output: true - permalink: /:collection/:path/ - lfmp2020: - output: true - permalink: /:collection/:path/ - gsod2020: - output: true - permalink: /:collection/:path/ - gsoc2019: - output: true - permalink: /:collection/:path/ - driverless: - output: true - permalink: /:collection/:path/ - recipes: - output: true - permalink: /:collection/:path/ - pets: - output: true - permalink: /:collection/:path/ - portfolio: - output: true - permalink: /:collection/:path/ - projects: - output: true - permalink: /:collection/:path/ - upcoming-technologies: - output: true - permalink: /:collection/:path/ - documentation: - output: true - permalink: /:collection/:path/ - - -# Defaults -defaults: - # _posts - - scope: - path: "" - type: posts - values: - layout: single - author_profile: true - read_time: true - share: true - related: true - comments: true - # _pages - - scope: - path: "_pages" - type: pages - values: - layout: single - author_profile: true - # comments: true - # _docpages - - scope: - path: "_docpages" - type: pages - values: - layout: single - author_profile: true - # comments: true - - # _gsoc2021 - - scope: - path: "" - type: gsoc2021 - values: - layout: single - author_profile: false - share: false - excerpt: "" - toc: true - toc_label: "On This Page" - sidebar: - nav: "gsoc21" - # comments: true - - # _gsoc2020 - - scope: - path: "" - type: gsoc2020 - values: - layout: single - author_profile: false - share: false - excerpt: "" - toc: true - toc_label: "On This Page" - sidebar: - nav: "gsoc20" - # comments: true - - - scope: - path: "" - type: gsoc2019 - values: - layout: single - author_profile: false - share: false - excerpt: "" - toc: true - toc_label: "On This Page" - sidebar: - nav: "gsoc19" - # comments: true - - # _lfmp2020 - - scope: - path: "" - type: lfmp2020 - values: - layout: single - author_profile: false - share: false - excerpt: "" - toc: true - toc_label: "On This Page" - sidebar: - nav: "lfmp20" - # comments: true - - # _gsod2020 - - scope: - path: "" - type: gsod2020 - values: - layout: single - author_profile: false - share: false - excerpt: "" - toc: true - toc_label: "On This Page" - sidebar: - nav: "gsod20" - # comments: true - - #_driverless - - scope: - path: "" - type: driverless - values: - layout: single - author_profile: false - share: false - excerpt: "" - sidebar: - - image: /assets/images/logo _ipp.png - image_alt: "Driverless Printing" - nav: "driverless" - #upcoming-technologies - - scope: - path: "" - type: upcoming-technologies - values: - layout: single - author_profile: false - share: true - excerpt: "" - comments: true - #documentation - - scope: - path: "" - type: documentation - values: - layout: single - author_profile: true - share: true - excerpt: "" - comments: true - # _recipes - - scope: - path: "" - type: recipes - values: - layout: single - author_profile: true - share: true - # _pets - - scope: - path: "" - type: pets - values: - layout: single - author_profile: true - share: true - # _portfolio - - scope: - path: "" - type: portfolio - values: - layout: single - author_profile: false - share: true - # _projects - - scope: - path: "" - type: projects - values: - layout: single - author_profile: false - share: false - excerpt: "" - # comments: true - # toc: true - # sidebar: - # nav: "projects" diff --git a/_data/authors.yml b/_data/authors.yml deleted file mode 100644 index b7beaace..00000000 --- a/_data/authors.yml +++ /dev/null @@ -1,53 +0,0 @@ -Till: - name : "Till Kamppeter" - bio : "OpenPrinting Organization Lead" - avatar : "https://openprinting.github.io/assets/images/till-kamppeter.jpg" - email : "till.kamppeter@gmail.com" - github : "tillkamppeter" - location : "Vienna, Austria" -# -Mike: - name : "Michael Sweet" - bio : "Author of CUPS and PAPPL" - avatar : "https://openprinting.github.io/assets/images/michael-sweet.jpg" -# email : "msweet@msweet.org" - github : "michaelrsweet" - location : "Canada" -# -Aveek: - name : "Aveek Basu" - bio : "OpenPrinting Program Manager" -# avatar : "https://openprinting.github.io/assets/images/aveek-basu.jpg" - email : "basu.aveek@gmail.com" - github : "AveekBasu" - location : "Kolkata, India" -# stackoverflow: "" -# -Dheeraj: - name : "Dheeraj" - bio : "Sub Coordinator, Programming Club, IIT Mandi" - avatar : "https://avatars.githubusercontent.com/dheeraj135" - email : "dhirajyadav135@gmail.com" - facebook : "dheeraj.168" - github : "dheeraj135" - linkedin : "dheeraj-yadav-282330154" - uri : "https://dheeraj135.github.io" - location : "Mandi, 175001, India" -# stackoverflow: "" -# -Zdenek: - name : "Zdenek Dohnal" - bio : "Member of CUPS Release Managers group, RHEL/CentOS Stream/Fedora CUPS maintainer" -# avatar : "https://openprinting.github.io/assets/images/zdenek-dohnal.jpg" -# email : "zdohnal@redhat.com" - github : "zdohnal" - location: "Brno, Czech Republic" -# -CNihelton: - name : "Carlos Nihelton" - bio : "Software Engineer at Canonical's Ubuntu WSL Team" - avatar : "https://openprinting.github.io/assets/images/cnihelton.jpg" - email : "carlosnsoliveira@gmail.com" - github : "CarlosNihelton" - location: "Campinas, Brazil" -# diff --git a/_data/navigation.yml b/_data/navigation.yml deleted file mode 100644 index 77ae3f00..00000000 --- a/_data/navigation.yml +++ /dev/null @@ -1,184 +0,0 @@ -# Copyright 2019 OpenPrinting - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at - -# http://www.apache.org/licenses/LICENSE-2.0 - -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# main links links -main: - - title: "About Us" - url: /about-us/ - - title: "News and Events" - url: /news/ - - title: "Projects" - url: /projects/ - - title: "Downloads" - url: /downloads/ - - title: "Documentation" - url: /documentation/ - - title: "Upcoming Technologies" - url: /upcoming-technologies/ - - title: "Driverless Printing" - url: /driverless/ - - title: "Printers" - url: "https://openprinting.org/printers" - - title: "Printer Drivers" - url: "https://openprinting.org/drivers" - - title: "Legacy Printers under Windows" - url: "/wsl-printer-app" - - title: "Contact Us" - url: /contact/ - - title: "Donations" - url: /donations/ - -gsoc21: - - title: "GSOC 2021" - children: - - title: "GSOC 2021 Homepage" - url: /gsoc2021/ - - title: "Make All Filter Functions Work Well Even Without PPD Files." - url: /gsoc2021/01-Filter_withour-PPD/ - - title: "GUI for listing and managing available IPP services" - url: gsoc2021/02-GUI-for-IPP/ - - title: "Firmware and other file handling in PAPPL" - url: gsoc2021/03-File-Handling-in-PAPPL/ - - title: "Create a single universal CUPS filter to replace the chain of individual filters" - url: /gsoc2021/04-Single-universal-filter/ - - title: "CUPS Filters: Converting Filters to Filter Functions" - url: /gsoc2021/05-Filters-to-Filter// - -gsoc20: - - title: "GSOC 2020" - children: - - title: "GSOC 2020 Homepage" - url: /gsoc2020/ - - title: "Linux GUI application (can be part of GNOME printer tool) to admin MF devices using IPP System Service." - url: /gsoc2020/01-Linux-GUI-Application/ - - title: "Common Print Dialog Qt implementation" - url: gsoc2020/02-common-print-dialog/ - - title: "IPP scan (or virtual MF device) server (Scanner Application)" - url: gsoc2020/03-ipp-scan-application/ - - title: "SANE module for IPP driverless scanning" - url: /gsoc2020/04-sane-module/ - - title: "General Printer SDK" - url: /gsoc2020/05-general-printer-sdk/ - - title: "Make Printer Applications Configurable" - url: /gsoc2020/06-make-printer-application-configurable/ - - title: "Turn cups-browsed into printer application" - url: /gsoc2020/07-cups-browsed-printer-app/ - - title: "Speed/Scaling optimization of cups browsed" - url: /gsoc2020/08-optimization-cups-browsed/ - - title: "Wrapping Proprietary Drivers into Printer Applications" - url: /gsoc2020/09-wrapping-proprietary-drivers/ - - title: "Gutenprint Printer Application" - url: /gsoc2020/10-gutenprint-printer-application/ - - title: "Support for IPP Fax Out" - url: /gsoc2020/11-ipp-fax-out/ - - title: "Turn the scp-dbus-service methods - GetBestDrivers and MissingExecutables - of system-config-printer into C" - url: /gsoc2020/12-scp-dbus-service-into-c/ - - title: "Extract Raster data from PDFs for direct printing" - url: /gsoc2020/13-extract-raster-from-pdf/ - - title: "Real roll paper support in cups-filters" - url: /gsoc2020/14-roll-paper-support/ - - title: "Add Printer output backend to MuPDF" - url: /gsoc2020/15-printer-output-backendto-mupdf/ - - title: "Printing of files directly from the file manager" - url: /gsoc2020/16-print-files-directly-from-manager/ - - title: "Get the Cairo color management code upstream" - url: /gsoc2020/17-get-cairo-code-upstream/ - -gsoc19: - - title: "GSOC 2019" - children: - - title: "GSOC 2019 HomePage" - url: /gsoc2019/ - - title: "Generic Framework to turn legacy drivers consisting of CUPS filters and PPDs into Printer Applications" - url: /gsoc2019/01-legacy-drivers-to-printer-applications/ - - title: "IPP scan (or virtual MF device) server (Scanner Application)" - url: /gsoc2019/02-ipp-scan-server/ - - title: "SANE module for IPP driverless scanning" - url: /gsoc2019/03-sane-module/ - - title: "IPP - ipptool test suite for IPP System Service" - url: /gsoc2019/04-ipp-test-tool-for-ipp-system-service/ - - title: "IPP - ipptool test suite for IPP Errata Updates" - url: /gsoc2019/05-ipp-test-tool-for-ipp-errata-updates/ - - title: "Linux GUI application (can be part of GNOME printer tool) to admin MF devices using IPP System Service." - url: /gsoc2019/06-linux-gui-application/ - - title: "Improve the pdftoraster filter to not need copying Poppler source code or using unstable APIs" - url: /gsoc2019/07-pdftoraster-filter/ - - title: "Foomatic Generating CUPS PPD generator (/usr/share/cups/drv/*.drv files) from Foomatic data" - url: /gsoc2019/08-foomatic-generating-cups-ppd-generator/ - - title: "Add printer output backends to MuPDF" - url: /gsoc2019/09-add-printer-output-backends-to-mupdf/ - - title: "Common Print Dialog Qt implementation" - url: /gsoc2019/10-common-print-dialog/ - - title: "Turn the scp-dbus-service of system-config-printer into C" - url: /gsoc2019/11-scp-dbus-service-into-c/ - - title: "Google Cloud Print - Desktop-integrated solution for registering local CUPS printers" - url: /gsoc2019/12-gcp-desktop-solution-for-local-cups-printers/ - - title: "Printing of files directly from the file manager" - url: /gsoc2019/13-print-files-from-file-manager/ - - title: "Get the cairo color management code upstream" - url: /gsoc2019/14-cairo-color-management-code/ - -driverless: - - title: "Driverless Printing" - children: - - title: "Introduction to Driverless Printing" - url: /driverless/ - - title: "Standards And their PDLS" - url: /driverless/01-standards-and-their-pdls/ - - title: "Workflow of Driverless Printing" - url: /driverless/02-workflow/ -# sidebar navigation list sample -# sidebar-sample: -# - title: "Parent Page A" -# children: -# - title: "Child Page A1" -# url: /child-page-a1/ -# - title: "Child Page A2" -# url: /child-page-a2/ -# - title: "Child Page A3" -# url: /child-page-a3/ -# - title: "Child Page A4" -# url: /child-page-a4/ -# - title: "Parent Page B" -# children: -# - title: "Child Page B1" -# url: /child-page-b1/ -# - title: "Child Page B2" -# url: /child-page-b2/ -# - title: "Child Page B3" -# url: /child-page-b3/ -# - title: "Child Page B4" -# url: /child-page-b4/ -# - title: "Child Page B5" -# url: /child-page-b5/ -# - title: "Parent Page C" -# children: -# - title: "Child Page C1" -# url: /child-page-c1/ -# - title: "Child Page C2" -# url: /child-page-c2/ -# - title: "Child Page C3" -# url: /child-page-c3/ -# - title: "Child Page C4" -# url: /child-page-c4/ -# - title: "Child Page C5" -# url: /child-page-c5/ -# - title: "Parent Page D" -# children: -# - title: "Child Page D1" -# url: /child-page-d1/ -# - title: "Child Page D2" -# url: /child-page-d2/ -# - title: "Child Page D3 (External)" -# url: https://your-domain.com diff --git a/_driverless/00-introduction.md b/_driverless/00-introduction.md deleted file mode 100644 index 991aa1a5..00000000 --- a/_driverless/00-introduction.md +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/_driverless/01-standards-and-their-pdls.md b/_driverless/01-standards-and-their-pdls.md deleted file mode 100644 index e3b1979c..00000000 --- a/_driverless/01-standards-and-their-pdls.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: Driverless Printing Standards And their PDLS ---- -There are four driverless printing standards established, but they all are based on the printer advertising itself via DNS-SD in the network, communicating with clients via IPP, and supporting a selection out of four known Page Description Languages (PDLs). The difference is merely only which selection of PDLs is supported. - -Due to this we actually do not distinguish between the standards any more and simply call it "driverless IPP printing" or simply "driverless printing". - -Here are the four standards and their PDLs: - -1. [AirPrint™](https://support.apple.com/en-ca/HT201311): Apple Raster/URF, JPEG, and PDF. AirPrint is Apple's "standard" to print from iOS, iPadOS, and macOS, and is the most common and oldest driverless printing standard. -2. [IPP Everywhere™](https://www.pwg.org/ipp/everywhere.html): PWG Raster, JPEG, and PDF. IPP Everywhere is developed by the Printer Working Group (PWG) and is a completely open standard. -3. [Mopria®](https://www.mopria.org): PCLm, PWG Raster, and PDF. Mopria is a proprietary profile of IPP used for printing from Android and Microsoft Windows®. -4. [Wi-Fi Direct Print Services](https://www.wi-fi.org): PCLm, PWG Raster, and PDF. Wi-Fi Direct printers work as a Wi-Fi access point so that mobile devices can print without an existing Wi-Fi network. - - -Apple Raster ------------- - -Apple Raster (aka URF) is Apple's own raster format for printing with AirPrint. -It is similar to CUPS and PWG Raster but with much simpler page headers. Apple -Raster uses a modified PackBits compression algorithm that works on whole pixels -for non-bitmap graphics that is typically paired with GZIP compression during -transmission to the printer. - - -PCLm ----- - -PCLm is a raster-only subset of PDF that has nothing to do with the original HP -PCL. Since PCLm files are valid PDF files, you can view them using a standard -PDF file viewer or print them on a PDF printer. However, printers that support -PCLm can only accept PCLm files produced for a particular combination of band -height, color space, and resolution that is supported by the printer. - - -PWG Raster Format ------------------ - -The PWG Raster Format is a subset of CUPS raster that is documented in PWG -Candidate Standard 5102.4-2012. Like Apple Raster, it uses a modified PackBits -compression algorithm that works on whole pixels for non-bitmap graphics that is -typically paired with GZIP compression during transmission to the printer. diff --git a/_driverless/02-workflow.md b/_driverless/02-workflow.md deleted file mode 100644 index bc8111fb..00000000 --- a/_driverless/02-workflow.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: Workflow Of Driverless Printing ---- -

The workflow of driverless printing is always the same-:

- -
    -
  1. The printer advertises itself by DNS-SD, with a summary of its most important capability information (especially also its PDLs and a one-line-string super summary in case of AirPrint printers) in its DNS-SD record.

  2. -
  3. Clients find these printers via DNS-SD.
  4. -
  5. The client polls the full capabilities info from the printer sending a get-printer-attributes IPP request. The printer returns a long list of info, especially paper sizes and types, unprintable margins, resolutions, input trays, finishers, quality settings, all user-settable options etc..

  6. -
  7. CUPS or cups-browsed on the client generate PPD files from this info and create print queues for each printer.

  8. -
  9. The print dialogs of the applications show the printers and allow access to all the user-settable options.

  10. -
  11. The user prints a job. The PDF from the application is turned into one of the PDLs which the printer supports by cups-filters. The settings selected by the user are passed along with the job as IPP attributes.

  12. -
  13. The printer prints the job and thanks to IPP the status can be observed, toner levels and any errors can get reported to the client.

  14. -
  15. If the printer is shut down, its queue will get automatically removed. So no clutter of print queues as souvenir of all the networks you have visited.

  16. -
diff --git a/_gsoc2019/02-ipp-scan-server.md b/_gsoc2019/02-ipp-scan-server.md deleted file mode 100644 index a8d82477..00000000 --- a/_gsoc2019/02-ipp-scan-server.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: IPP scan (or virtual MF device) server (Scanner Application) ---- - -### Introduction - -

-The Internet Printing Protocol (IPP) does not only support printing, but also scanning, as there are many printers which also have a scanner (multi-function (MF) devices). Both CUPS and the developer tool ippserver emulate IPP network printers but not IPP scanners and so they cannot serve as a server to share a local scanner. -

- -### Student Tasks - -

-This task is about adding the scan server functionality. If you have a scanner connected locally (and it scans via SANE), share it as an IPP scanner, advertising itself and accepting jobs using the IPP driverless scanning standard. In contrary to SANE-based network scanning clients with any operating system, also phones or IoT devices can scan on your shared scanner. -

- -

-Also old hardware can be recycled to a modern MF device, and we have a sample implementation to motivate manufacturers to adopt IPP scanning. -

- -

-This server software will be a so-called Scanner Application, a sample implementation of the future form of scanner drivers, easily packageable in sandboxed, distribution-independent package formats like Snap. -

- -### Mentors - -

-Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), SANE upstream developers TBD -

- -### Desired Knowledge -

-C programming, DNS-SD, IPP -

- -### Code License -

-Apache 2.0 -

- diff --git a/_gsoc2019/03-sane-module.md b/_gsoc2019/03-sane-module.md deleted file mode 100644 index 88693bad..00000000 --- a/_gsoc2019/03-sane-module.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: SANE module for IPP driverless scanning ---- - -### Introduction - -

-Version 2.0 and newer of the Internet Printing Protocol (IPP) support polling the full set of capabilities of a printer and if the printer supports a known Page Description Language (PDL), like PWG Raster, Apple Raster, PCLm, or PDF, it is possible to print without printer-model-specific software (driver) or data (PPD file), so-called “driverless” printing. This concept was introduced for printing from smartphones and IoT devices which do not hold a large collection of printer drivers. Driverless printing is already fully supported under Linux. Standards following this scheme are IPP Everwhere, Apple AirPrint, Mopria, and Wi-Fi Direct Print. -

- -

-As there are many multi-function devices (printer/scanner/copier all-in-one) which use the IPP, the Printing Working Group (PWG) has also worked out a standard for IPP-based scanning, “driverless” scanning, to also allow scanning from a wide range of client devices, independent of which operating systems they are running. -

- -

-Conventional scanners are supported under Linux via the SANE (Scanner Access Now Easy) system and require drivers specific to the different scanner models. Most of them are written based on reverse-engineering due to lack of support by the scanner manufacturers. To get driverless scanning working with the software the users are used to the best solution is to write a SANE module for driverless IPP scanning. This module will then automatically support all IPP scanners, thousands of scanners where many of them do not yet exist. -

- -

-Even if there are no driverless IPP scanners on the market yet, this module can be used for accessing scanners with their driver provided as Scanner Application (see previous project in this list). -

- -### Student Tasks - -

-The student's task is to write this SANE module for IPP driverless scanning and so make Linux ready for the future of driverless devices. -

- -### Mentors -

-Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), SANE upstream developers TBD -

- -### Desired Knowledge -

-C programming, DNS-SD, IPP -

- -### Code License -

-GPL 2+ -

diff --git a/_gsoc2019/06-linux-gui-application.md b/_gsoc2019/06-linux-gui-application.md deleted file mode 100644 index 5218c196..00000000 --- a/_gsoc2019/06-linux-gui-application.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Linux GUI application (can be part of GNOME printer tool) to admin MF devices using IPP System Service. ---- - -### Introduction - -

-Most network printers have a web interface which allows to configure the printer from any computer in the network using a web browser. Advantage is that no printer-model-specific software needs to be installed on the computer in order to configure a printer, and one has no dependency on certain supported operating systems. One can even configure printers using a smartphone. -

- -

-Disadvantage is that every manufacturer does its web interface differently which makes administration of many printers of different brands awkward. In addition, automated printer administration with scripts requires different interfaces for each printer. And for setting local print queues you open your printer setup tool but for printer administration you have to open your browser. -

- -

-To make this easier the Printing Working Group (PWG) has introduced the IPP System Service standard. This is an interface made up of standardized IPP requests to poll printer capabilities and configure the printer as needed. Every printer from every manufacturer uses the same requests and so a common printer configuration interface can be added to printer setup tools or automated administration with scripts is possible. -

- -### Student Tasks -

-The student's task will be to create an appropriate printer configuration interface for system-config-printer or for the GNOME Control Center. -

- -### Mentors -

-Upstream developers of GNOME/GTK or system-config-printer TBD. -

- -### Desired Knowledge -

-C and/or Python programming, GTK -

- -### Code License -

-GPL 2+ or LGPL 2+ -

diff --git a/_gsoc2019/08-foomatic-generating-cups-ppd-generator.md b/_gsoc2019/08-foomatic-generating-cups-ppd-generator.md deleted file mode 100644 index af235b1c..00000000 --- a/_gsoc2019/08-foomatic-generating-cups-ppd-generator.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Foomatic Generating CUPS PPD generator (/usr/share/cups/drv/\*.drv files) from Foomatic data ---- - -### Introduction - -

-CUPS has two mechanisms for on-the-fly-PPD generation to avoid the wasting of disk space by thousands of uncompressed (or slightly compressed) PPD files. One is to put an executable file into the /usr/lib/cups/driver/ directory which lists and generates PPD files on request, the other is using *.drv files in /usr/share/cups/drv, which contain the data for the PPDs in a simpler and more compact format. -

- -

-The former method is deprecated upstream and can be removed in a future release of CUPS, especially also because the executables can get slow in some cases. -

- -

-The latter is not yet supported by Foomatic and letting Foomatic support it is subject of this project idea. -

- -### Student Tasks -

-The student's task is to create a utility which generates *.drv files from the whole database and/or from selected, printers, manufacturers, drivers, groups, …, depending on what the user requests. -

- -### Mentor -

-Till Kamppeter, Project Leader OpenPrinting (till at linux dot com) -

- -### Desired Knowledge -

-Perl programming, perhaps also MySQL -

- -### Code License -

-GPL -

diff --git a/_gsoc2019/09-add-printer-output-backends-to-mupdf.md b/_gsoc2019/09-add-printer-output-backends-to-mupdf.md deleted file mode 100644 index 31e54447..00000000 --- a/_gsoc2019/09-add-printer-output-backends-to-mupdf.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: Add printer output backends to MuPDF ---- - -### Introduction -

-MuPDF is a lightweight PDF renderer made by Artifex, the company behind Ghostscript. In contrary to Ghostscript, MuPDF is a pure PDF renderer. It does not contain a PostScript interpreter nor parts of it are written in PostScript. This makes it smaller, faster, and less resource-consuming, the ideal solution for mobile devices like tablets or smartphones. -

- -

-On mobile devices printing will not be done with having tons of printer-model-specific drivers on the system. Once, they consume the limited mass storage space, and second, one uses the mobile device in several different local networks with different printers: At home, in the office, in a copy shop, … and one wants to use the printers which are available there, without installing drivers and setting up queues. -

- -

-Therefore we want to have a system which automatically detects network printers and makes them available for local apps. To do so we restrict ourselves to printers with known, common languages: IPP Everywhere/AirPrint/Mopria/W-Fi Direct (driverless printing standards, using PWG Raster, Apple Raster, PCLm, and PDF) and PostScript, PDF, PCL 5c/e/6/XL (legacy standards). So MuPDF has to generate raster output for these languages, meaning raster embedded in the specifics of the language, and to avoid exhausting printer resources raster in small bands and no high-level output, even if the printer language is high-level. -

- -

-Artifex will also work on this, but to get additional man power we are also opening this project for students. -

- -

-Note that you have to assign copyright on your code to Artifex, as otherwise the code cannot be integrated in MuPDF. -

- -

-This project can be split to be worked on by more than one student. -

- -### Mentors -

-MuPDF developers TBD, Till Kamppeter, Project Leader OpenPrinting (till at linux dot com) -

- -### Desired Knowledge -

-C and/or C++ programming -

- -### Code License -

-GPL -

diff --git a/_gsoc2019/10-common-print-dialog.md b/_gsoc2019/10-common-print-dialog.md deleted file mode 100644 index 91c75f9c..00000000 --- a/_gsoc2019/10-common-print-dialog.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Common Print Dialog Qt implementation ---- - -### Introduction - -

-The Qt Print Support framework should be updated with the CPD support. The goal is to provide the CPD GUI features and d-bus communications with the CPD backend support for printing from Qt5 applications on support platforms. -

- -### Student Tasks -

-Based on the GSoC work of the previous year, one example of Qt CPD implementation outside of Qt Print Support can be found at: https://github.com/rithvikp1998/CPDv2. For this task, the implementation is expected to start with QPrintDialog instead. -

- -### Mentors -

-Dongxu Li (dongxuli2011 at gmail dot com), Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), TBD -

- -### Desired Knowledge -

-C++ programming, Qt, CUPS -

- -### License -

-Qt Contribution Agreement -

\ No newline at end of file diff --git a/_gsoc2019/11-scp-dbus-service-into-c.md b/_gsoc2019/11-scp-dbus-service-into-c.md deleted file mode 100644 index b170d7a5..00000000 --- a/_gsoc2019/11-scp-dbus-service-into-c.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Turn the scp-dbus-service of system-config-printer into C ---- - -### Introduction - -

-system-config-printer was the default printer setup tool in Red Hat/Fedora Linux for a lot of time and also got adopted by Ubuntu around ten years ago. During this time it received a lot of development work, especially on the algorithms for finding the best driver for a printer and for identifying whether printer discovery results from the CUPS backends actually come from the same physical printer. -

- -

-To make these algorithms available for other printer setup tools (both interactive GUI tools and programs which fully automatically create print queues without user interaction) they got moved into a D-Bus service, scp-dbus-service. Now every other program can simply call the needed function via a D-Bus API. The printer setup tool in the GNOME Control Center for example works this way. -

- -

-system-config-printer was written in Python and therefore scp-dbus-service is also written in Python. This makes it depending on Python and also makes it loading the needed Python libraries into memory when started. This can cause delays during boot when a utility to auto-setup print queues is used.Also most printer setup tools are written in C, Therefore it makes sense to convert the D-Bus service into the C language. -

- -### Student Tasks -

-The student's task is to turn the scp-dbus-service of system-config-printer into C, either as D-Bus service (would work out-of-the-box with many GUIs) or as a C library with API (simpler), ideally both. This will make it easier to write printer setup tools in practically any programming language. -

- -### Mentors -

-Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), system-config-printer upstream developers TBD -

- -### Desired Knowledge -

-Desired knowledge: C/C++ programming, Python programming -

- -### Code License -

-GPL 2+ or MIT -

diff --git a/_gsoc2019/12-gcp-desktop-solution-for-local-cups-printers.md b/_gsoc2019/12-gcp-desktop-solution-for-local-cups-printers.md deleted file mode 100644 index b969d733..00000000 --- a/_gsoc2019/12-gcp-desktop-solution-for-local-cups-printers.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: Google Cloud Print - Desktop-integrated solution for registering local CUPS printers ---- - -### Introduction -

-Google Cloud Print is a service from Google which allows to print from anywhere with internet access to anywhere else with internet access, for example from a mobile phone to printer at home or in the office. -

- -

-To do so, one needs a Google account and there one registers one's printers so that they can accept jobs sent into the print facility of this Google account. -

- -

-On Linux there is already a way to share the local CUPS printers into Cloud Print: The Chrome/Chromium Browser. In its settings you can activate Google Cloud Print and the local queues get registered. The Browser even leaves a user daemon running when one closes it to continue keeping the printers available for Cloud Print. -

- -

-The disadvantage of this is that the functionality is bound to a web browser, so it is awkward for people who use Firefox for example. -

- -

-Do not suggest now to make the CUPS daemon (daemon which handles the print jobs) or cups-browsed (daemon which browses the network for printers and automatically creates local queues for them) registering the printers, as they are system-wide services and Google Cloud Print is based on the user's Google account, and so something which belongs to a single user. -

- -### Student Tasks -

-What is needed is a user daemon which starts when logging in and stops when logging out, running with the rights of the user, connecting to the user's Google account registering the local CUPS printers the user is allowed to print on. It will need integration with the desktop for starting and stopping the daemon and for configuration in the desktop's settings utility. -

- -

-Ideally it should work with the GNOME desktop using GNOME Online Accounts and the GNOME settings manager. -

- -

-Google documentation for printer registration. -

- -### Mentors -

-Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), Ubuntu/GNOME GUI developers TBD -

- -### Desired Knowledge -

-C/C++ programming, GUI programming, GTK -

diff --git a/_gsoc2019/13-print-files-from-file-manager.md b/_gsoc2019/13-print-files-from-file-manager.md deleted file mode 100644 index a7720bbc..00000000 --- a/_gsoc2019/13-print-files-from-file-manager.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Printing of files directly from the file manager ---- - -### Introduction - -

-Sometimes you browse through your files and see some files which you want to print, files in completely different formats: PDFs, photos, LibreOffice files, … It is awkward to double-click each file, one-by-one, to get it opened in its application, and then click “Print” in each application. It would be much easier to mark all these files, right-click and then click “Print” in the context menu. -

- -### Student Tasks -

-Here the student's task is to add this functionality to a popular file manager, for example the one of GNOME. -

- -### Mentors -

-Aveek Basu (basu dot aveek at gmail dot com), upstream developers of GNOME/GTK TBD. -

- -### Desired Knowledge -

-C programming, GTK -

- -### Code License -

-LGPL 2+ -

diff --git a/_gsoc2019/14-cairo-color-management-code.md b/_gsoc2019/14-cairo-color-management-code.md deleted file mode 100644 index 4582dcbd..00000000 --- a/_gsoc2019/14-cairo-color-management-code.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: Get the cairo color management code upstream ---- - -### Introduction - -

-Adrian Johnson did a lot of the work needed to make cairo color managed. Finishing this work and getting the code upstream would allow us to simplify a lot of applications that use cairo. See http://cgit.freedesktop.org/~ajohnson/cairo/log/?h=color-space for the branch. Adrian has also patched Inkscape to use the new features, and that needs cleaning up and pushing upstream http://cgit.freedesktop.org/~ajohnson/inkscape/log/?h=color-space Also see http://lists.cairographics.org/archives/cairo/2012-July/023353.html and https://mail.gnome.org/archives/gimp-developer-list/2012-August/msg00084.html for more details. -

- -### Expectations -

-Expectations: The cairo and inskcape code is pushed upstream with any required modifications. Ideally someone familiar with the cairo community would take this on, as Adrian found it hard to get the code approved upstream. -

- -### Skills -

-Understanding of basic color management, basic use of bzr and git, proficient in C. -

- -### Mentors -

-Richard Hughes (hughsient at gmail dot com) -

diff --git a/_gsoc2020/02-common-print-dialog.md b/_gsoc2020/02-common-print-dialog.md deleted file mode 100644 index a3364611..00000000 --- a/_gsoc2020/02-common-print-dialog.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: "Common Print Dialog Backends (CPDB) Qt implementation" ---- - -### Introduction -

-The Qt Print Support framework should be updated with the CPD support. The goal is to provide the CPD GUI features and d-bus communications with the CPD backend support for printing from Qt5 applications on support platforms. -

- -

-Based on the GSoC work of the previous year, one example of Qt CPD implementation outside of Qt Print Support can be found at: https://github.com/rithvikp1998/CPDv2. For this task, the implementation is expected to start with QPrintDialog instead. -

- -### Mentors -

-Dongxu Li (dongxuli2011 at gmail dot com), Nilanjana Lodh, first implementor of the CPDB (nilanjanalodh at gmail dot com), Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), TBD -

- -### Desired Knowledge -

-C++ programming, Qt, CUPS -

- -### License -

-Qt Contribution Agreement -

diff --git a/_gsoc2020/03-ipp-scan-application.md b/_gsoc2020/03-ipp-scan-application.md deleted file mode 100644 index 232e3234..00000000 --- a/_gsoc2020/03-ipp-scan-application.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: "IPP scan (or virtual MF device) server (Scanner Application)" ---- -### Introduction -

-The Internet Printing Protocol (IPP) does not only support printing, but also scanning, as there are many printers which also have a scanner (multi-function (MF) devices). Both CUPS and the developer tool ippserver emulate IPP network printers but not IPP scanners and so they cannot serve as a server to share a local scanner. -

- -

-This task is about adding the scan server functionality. If you have a scanner connected locally (and it scans via SANE), share it as an IPP scanner, advertising itself and accepting jobs using the IPP driverless scanning standard. In contrary to SANE-based network scanning clients with any operating system, also phones or IoT devices can scan on your shared scanner. -

- -

-Also old hardware can be recycled to a modern MF device, and we have a sample implementation to motivate manufacturers to adopt IPP scanning. -

- -

-This server software will be a so-called Scanner Application, a sample implementation of the future form of scanner drivers, easily packageable in sandboxed, distribution-independent package formats like Snap. -

- -### Mentors -

-Alexander Pevzner, “airscan” SANE backend author (pzz at apevzner dot com), Thierry Hucahrd, “escl” SANE backend author (thierry at ordissimo dot com), Michael Sweet, author of CUPS (msweet at msweet dot org), Ira McDonald, OpenPrinting (blueroofmusic at gmail dot com), Smith Kennedy, HP (smith kennedy at hp dot com, Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), SANE upstream developers TBD -

- -### Desired Knowledge -

-C programming, DNS-SD, IPP -

- -### Code License -

-Apache 2.0 -

diff --git a/_gsoc2020/04-sane-module.md b/_gsoc2020/04-sane-module.md deleted file mode 100644 index bfd6eb1a..00000000 --- a/_gsoc2020/04-sane-module.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: "SANE module for IPP driverless scanning" ---- - -### Introduction -

-Version 2.0 and newer of the Internet Printing Protocol (IPP) support polling the full set of capabilities of a printer and if the printer supports a known Page Description Language (PDL), like PWG Raster, Apple Raster, PCLm, or PDF, it is possible to print without printer-model-specific software (driver) or data (PPD file), so-called “driverless” printing. This concept was introduced for printing from smartphones and IoT devices which do not hold a large collection of printer drivers. Driverless printing is already fully supported under Linux. Standards following this scheme are IPP Everwhere, Apple AirPrint, Mopria, and Wi-Fi Direct Print. -

- -

-As there are many multi-function devices (printer/scanner/copier all-in-one) which use the IPP, the Printing Working Group (PWG) has also worked out a standard for IPP-based scanning, “driverless” scanning, to also allow scanning from a wide range of client devices, independent of which operating systems they are running. -

- -

-Conventional scanners are supported under Linux via the SANE (Scanner Access Now Easy) system and require drivers specific to the different scanner models. Most of them are written based on reverse-engineering due to lack of support by the scanner manufacturers. To get driverless scanning working with the software the users are used to the best solution is to write a SANE module for driverless IPP scanning. This module will then automatically support all IPP scanners, thousands of scanners where many of them do not yet exist. -

- -

-Even if there are no driverless IPP scanners on the market yet, this module can be used for accessing scanners with their driver provided as Scanner Application (see previous project in this list). -

- -

-The student's task is to write this SANE module for IPP driverless scanning and so make Linux ready for the future of driverless devices. -

- -### Mentors -

-Alexander Pevzner, “airscan” SANE backend author (pzz at apevzner dot com), Thierry Hucahrd, “escl” SANE backend author (thierry at ordissimo dot com), Michael Sweet, author of CUPS (msweet at msweet dot org), Ira McDonald, OpenPrinting (blueroofmusic at gmail dot com), Smith Kennedy, HP (smith kennedy at hp dot com, Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), SANE upstream developers TBD -

- -### Desired Knowledge -

-C programming, DNS-SD, IPP -

- -### Code License -

-GPL 2+ -

\ No newline at end of file diff --git a/_gsoc2020/07-cups-browsed-printer-app.md b/_gsoc2020/07-cups-browsed-printer-app.md deleted file mode 100644 index 3e46853e..00000000 --- a/_gsoc2020/07-cups-browsed-printer-app.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: "Turn cups-browsed into printer application" ---- - -### Introduction -

-cups-browsed is a daemon which discovers remote printers, mainly IPP but also legacy CUPS browsing, and makes them locally available. It gives a lot of possibilities for configuration, like clustering printers so that the most suitable for a job is automatically selected, allowing access to printers from legacy servers, showing only the relevant printers from thousands of printers available on the network, … -

- -

-Currently it makes printers locally available by creating a queue on the locally running CUPS, and generating a PPD file for this queue. As PPD files in CUPS are deprecated and the support for them will soon go away, cups-browsed will have to follow, and the best way to do so, is to make a Printer Application from it. Instead of creating CUPS queues it will emulate IPP printers then, which get picked up automatically by CUPS. -

- -

-The student's task here is to add IPP server functionality (icluding DNS-SD advertising) to cups-browsed. cups-browsed is already a Glib-based multi-function daemon, so adding a service should not be that much difficult. Nothing of the existing functionality should be removed, the user should be able to select between local queue creation or IPP server by the configuration file. -

- -

-A plus, when there is time left, would be a configuration interface, ideally using IPP System Service. -

- -### Mentors -

-Deepak Patankar (patankardeepak04 at gmail dot com), Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), TBD -

- -### Desired Knowledge -

-C programming, IPP, CUPS -

- -### Code License -

-LGPL-2.1+ -

diff --git a/_gsoc2020/09-wrapping-proprietary-drivers.md b/_gsoc2020/09-wrapping-proprietary-drivers.md deleted file mode 100644 index 4b940b99..00000000 --- a/_gsoc2020/09-wrapping-proprietary-drivers.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: "Wrapping Proprietary Drivers into Printer Applications" ---- - -### Introduction -

-With sandboxed packaging, Linux distributions appear which do not use classic RPM or DEB packages any more, like the all-Snap Ubuntu Core. And also standard desktop and server distributions, like Ubuntu Desktop/Server, will convert more and more to Snaps. Especially CUPS will also be moved from a classic package to a snap. Then CUPS will not work with classic PPD/filter-based printer drivers any more but requires all drivers being provided as Printer Applications. -

- -

-Free software printer drivers can easily get converted, starting from rebuilding them to live inside a Snap, where everything is in other directories than in a usual system up to integrating its printer capability infoand filter algorithms directly into the IPP server daemon. -

- -

-Proprietary, closed-source printer drivers come as binary RPM or DEB files, or tarballs, or even self-extracting. They require a certain, in classic systems usually available, file system structure to put their files in during installation, and they also need some libraries which are common in classic systems. In a snap you do not have this “standard” file system structure and the binaries with hard-coded paths in them choke on that. -

- -

-A solution is to take the Printer Application framework and add a chroot to it. The proprietary driver will get installed in that chroot then. -

- -

-The student's task is to add this functionality to the Printer Application framework and create an easy way for users to install proprietary printer drivers into that chroot-equipped Printer Application. -

- -### Mentors -

-Dheeraj Yadav (dhirajyadav135 at gmail dot com), Michael Sweet, author of CUPS (msweet at msweet dot org), Ira McDonald, OpenPrinting (blueroofmusic at gmail dot com), Smith Kennedy, HP (smith kennedy at hp dot com), Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), TBD -

- -### Desired knowledge -

-C programming, IPP -

- -### Code license -

-(L)GPL 2+, Apache 2.0, MIT -

diff --git a/_gsoc2020/10-gutenprint-printer-application.md b/_gsoc2020/10-gutenprint-printer-application.md deleted file mode 100644 index c9315b78..00000000 --- a/_gsoc2020/10-gutenprint-printer-application.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: "Gutenprint Printer Application" ---- - -### Introduction -

-Gutenprint is a printer driver for high-quality inkjet printing which is under continuous development for many years already and supports hundreds of printers. It is popular under users of both Linux and Mac OS X. -

- -

-Currently, it supports printing either the classic CUPS way, by a PPD generator and a filter or by a plug-in for the GIMP. It should be rather easy to add more ways of using the core driver functionality, as this functionality is in a library, all capability information of the supported printers, dithering and color correction algorithms, … -

- -

-The new mode of using this library should be a new Printer Application which will be the student´s task to create. The Gutenprint printer application should wrap the Gutenprint library and so support all the printers the library supports. The basic structure can be like the Printer Application framework but here we do not want to create the (deprecated) PPD files but instead, let the IPP server link directly with the library and serve out the printer capability information on client's get-printer-attributes requests. Also see Michael Sweet's work on PAPPL. -

- -### Mentors -

-Dheeraj Yadav (dhirajyadav135 at gmail dot com), Michael Sweet, author of CUPS/LPrint/PAPPL and original creator of Gutenprint (msweet at msweet dot org), Ira McDonald, OpenPrinting (blueroofmusic at gmail dot com), Smith Kennedy, HP (smith kennedy at hp dot com), Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), Gutenprint developers, TBD -

- -### Desired knowledge -

-C programming, IPP -

- -### Code license -

-(L)GPL 2+, Apache 2.0, MIT -

\ No newline at end of file diff --git a/_gsoc2020/11-ipp-fax-out.md b/_gsoc2020/11-ipp-fax-out.md deleted file mode 100644 index a4d55e54..00000000 --- a/_gsoc2020/11-ipp-fax-out.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: "Support for IPP Fax Out" ---- - -### Introduction -

-Modern network multi-function devices (printer, scanner, fax) provide driverless operation (meaning no device/model-specific software or data is needed to use them). The device advertises itself on the network via DNS-SD providing a summary of its features and capabilities. Then a client can access the device using standard HTTP and IPP protocols to poll detailed capability info to be able to use the device and do the actual operation with the same communication protocols and standardized data formats for the images scanned or to be printed. -

- -

-Current Linux distributions already support the printing part via IPP and there is also already upstream code for scanning via AirScan (eSCL) to appear in the distributions soon and the open IPP Scan standard is subject of another project in this GSoC. Also the standard for device configuration (IPP System Service) is subject of other projects in this GSoC list. -

- -

-What is missing is IPP Fax out. This is a standard, very similar to driverless IPP printing for sending faxes. Principally sending a fax can be done by printing a file to a special destination in the device, accompanied with a phone number (required) and some fax-specific options (like how to proceed on failure or cover sheets, …) as IPP attributes. -

- -

-One can easily determine whether a device supports this and poll all needed capabilities. The DNS-SD record of the device's printing part (“_ipp._tcp”) does not report only the URI extension for printing (“rp=ipp/print”) but also for fax (“rfo=ipp/faxout”, no extra DNS-SD record!). If there is such an entry one can poll the URI “ipp://host:port/ipp/faxout” with a get-printer-attributes IPP request as it was a printer, and one gets the capabilities for the device-internal fax destination. The “driverless” utility of cups-filters happily generates a PPD from this, but naturally without fax-specific options, and if you create a CUPS queue with this URI and PPD and print a file with “lp -d queue -o phone=0012345678 file” the device will fax the file to the given number. The feature is commonly available in modern devices and I have actually tested it as described here. -

- -

-The student's task here is to make this functionality easily accessible for users of common desktop Linux distributions. Like printers, faxes should automatically appear on the system and get available in print dialogs and if one prints to a fax, fax-specific options should also appear in the print dialog and the user should be able to pick phone numbers also from contacts. -

- -

-This can be done by expanding existing resources and creating new ones in the printing stack. Especially one should think here abour the Common Print Dialog Backends (CPDB), but also other projects, like cups-filters would perhaps need changes. -

- -### Mentors -

-Nilanjana Lodh, first implementor of the CPDB (nilanjanalodh at gmail dot com), Dongxu Li (dongxuli2011 at gmail dot com), Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), TBD -

- -### Desired knowledge -

-C/C++ programming, CUPS, IPP -

- -### Licenses -

-MIT, Apache, GPL 2+ -

\ No newline at end of file diff --git a/_gsoc2020/12-scp-dbus-service-into-c.md b/_gsoc2020/12-scp-dbus-service-into-c.md deleted file mode 100644 index 55d781c7..00000000 --- a/_gsoc2020/12-scp-dbus-service-into-c.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: "Turn the scp-dbus-service methods - GetBestDrivers and MissingExecutables - of system-config-printer into C" ---- - -### Introduction -

-system-config-printer was the default printer setup tool in Red Hat/Fedora Linux for a lot of time and also got adopted by Ubuntu around ten years ago. During this time it received a lot of development work, especially on the algorithms for finding the best driver for a printer and for identifying whether printer discovery results from the CUPS backends actually come from the same physical printer. -

- -

-To make these algorithms available for other printer setup tools (both interactive GUI tools and programs which fully automatically create print queues without user interaction) they got moved into a D-Bus service, scp-dbus-service. Now every other program can simply call the needed function via a D-Bus API. The printer setup tool in the GNOME Control Center for example works this way. -

- -

-GNOME Control Center uses two methods - GetBestDrivers and MissingExecutables - for its printer setup. The GetBestDrivers method is used for finding the right printer drivers from ones which are available on the system. The MissingExecutables method is checking method, which is run after finding the best driver and checks if any additional software is needed for getting the printer functional. -

- -

-system-config-printer was written in Python and therefore scp-dbus-service is also written in Python. This makes it depending on Python and also makes it loading the needed Python libraries into memory when started. Also most printer setup tools are written in C, Therefore it makes sense to convert the D-Bus service into the C language. -

- -

-The student's task is to turn the two mentioned methods of system-config-printer into C, first as a C library with API, then as a D-Bus service (would - work out-of-the-box with many GUIs) if the C library will be finished. This will make it easier to use those methods in other print tools in practically any programming language. -

- -### Mentors -

-Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), system-config-printer upstream developer Zdenek Dohnal (zdohnal at redhat dot com) -

- -### Desired knowledge -

-C/C++ programming, Python programming, autoconf/automake(creating configure and Makefile), basic testing -

- -### Code license -

-GPL 2+ or MIT -

diff --git a/_gsoc2020/14-roll-paper-support.md b/_gsoc2020/14-roll-paper-support.md deleted file mode 100644 index a30865e8..00000000 --- a/_gsoc2020/14-roll-paper-support.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: "Real roll paper support in cups-filters" ---- - -### Introduction -

-Currently, most probably due to the fact that once most printers use paper in cut sheet and also PPD (PostScript Printer Description, now deprecated) files only support paper in cut sheet, roll paper as used in large-format and also some specialty prrinters is not actually supported. -

- -

-The difference of roll paper against sheet paper is that only its width is defined, the height of the printing area can be selected individually for each print job. -

- -

-What the user expects to happen is that the paper is cut right after the page so that nothing is wasted and the user has minimum work with manual cutting. He also would like pages to be rotated by 90 degrees if they fit better this way, for example if the page height fits into the roll's width. This saves paper and allows pages which are too wide for the roll to be printed. An option to activate this (auto), never rotate, or always rotate should be added. -

- -

-Also some way to manage paper consumption and preventing a page being started which does not fit into the remaining paper is desired. -

- -

-The student's task is to add this functionality into the current print workflow. -

- -

-He should at first study the IPP (Internet Printing Protocol) standard for its roll paper support. Then he should check where changes are needed: in CUPS, cups-filters, print dialogs … Also it has to be investigated whether this can be completely implemented in the current (deprecated) PPD-based printing workflow or whether the new Printer-Application-based model is required. -

- -### Mentors -

-Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), TBD -

- -### Desired knowledge -

-C programming, IPP -

- -### Code license -

-(L)GPL 2+, Apache 2.0, MIT -

diff --git a/_gsoc2020/15-printer-output-backendto-mupdf.md b/_gsoc2020/15-printer-output-backendto-mupdf.md deleted file mode 100644 index 1b272aee..00000000 --- a/_gsoc2020/15-printer-output-backendto-mupdf.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: "Add Printer output backend to MuPDF" ---- - -### Introduction -

-MuPDF is a lightweight PDF renderer made by Artifex, the company behind Ghostscript. In contrary to Ghostscript, MuPDF is a pure PDF renderer. It does not contain a PostScript interpreter nor parts of it are written in PostScript. This makes it smaller, faster, and less resource-consuming, the ideal solution for mobile devices like tablets or smartphones. -

- -

-On mobile devices printing will not be done with having tons of printer-model-specific drivers on the system. Once, they consume the limited mass storage space, and second, one uses the mobile device in several different local networks with different printers: At home, in the office, in a copy shop, … and one wants to use the printers which are available there, without installing drivers and setting up queues. -

- -

-Therefore we want to have a system which automatically detects network printers and makes them available for local apps. To do so we restrict ourselves to printers with known, common languages: IPP Everywhere/AirPrint/Mopria/W-Fi Direct (driverless printing standards, using PWG Raster, Apple Raster, PCLm, and PDF) and PostScript, PDF, PCL 5c/e/6/XL (legacy standards). So MuPDF has to generate raster output for these languages, meaning raster embedded in the specifics of the language, and to avoid exhausting printer resources raster in small bands and no high-level output, even if the printer language is high-level. -

- -

-Artifex will also work on this, but to get additional man power we are also opening this project for students. -

- -

-Note that you have to assign copyright on your code to Artifex, as otherwise the code cannot be integrated in MuPDF. -

- -

-This project can be split to be worked on by more than one student. -

- -### Mentors -

-MuPDF developers TBD, Till Kamppeter, Project Leader OpenPrinting (till at linux dot com) -

- -### Desired knowledge -

-C and/or C++ programming -

- -### Code License -

-GPL -

diff --git a/_gsoc2020/16-print-files-directly-from-manager.md b/_gsoc2020/16-print-files-directly-from-manager.md deleted file mode 100644 index fb59bb9b..00000000 --- a/_gsoc2020/16-print-files-directly-from-manager.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: "Printing of files directly from the file manager" ---- - -### Introduction -

-Sometimes you browse through your files and see some files which you want to print, files in completely different formats: PDFs, photos, LibreOffice files, … It is awkward to double-click each file, one-by-one, to get it opened in its application, and then click “Print” in each application. It would be much easier to mark all these files, right-click and then click “Print” in the context menu. -

- -

-Here the student's task is to add this functionality to a popular file manager, for example the one of GNOME. -

- -### Mentors -

-Aveek Basu (basu dot aveek at gmail dot com), upstream developers of GNOME/GTK TBD. -

- -### Desired knowledge -

-C programming, GTK -

- -### Code License -

-LGPL 2+ -

diff --git a/_gsoc2020/17-get-cairo-code-upstream.md b/_gsoc2020/17-get-cairo-code-upstream.md deleted file mode 100644 index 57260bfe..00000000 --- a/_gsoc2020/17-get-cairo-code-upstream.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: "Get the Cairo color management code upstream" ---- - -### Introduction -

-Adrian Johnson did a lot of the work needed to make cairo color managed. Finishing this work and getting the code upstream would allow us to simplify a lot of applications that use cairo. See http://cgit.freedesktop.org/~ajohnson/cairo/log/?h=color-space for the branch. Adrian has also patched Inkscape to use the new features, and that needs cleaning up and pushing upstream http://cgit.freedesktop.org/~ajohnson/inkscape/log/?h=color-space Also see http://lists.cairographics.org/archives/cairo/2012-July/023353.html and https://mail.gnome.org/archives/gimp-developer-list/2012-August/msg00084.html for more details. -

- -### Expectations -

-The cairo and inskcape code is pushed upstream with any required modifications. Ideally someone familiar with the cairo community would take this on, as Adrian found it hard to get the code approved upstream. -

- -### Required Skills -

-Understanding of basic color management, basic use of bzr and git, proficient in C. -

- -### Contact -

-Richard Hughes (hughsient at gmail dot com) -

diff --git a/_includes/archive-single-post.html b/_includes/archive-single-post.html deleted file mode 100644 index 51cdace0..00000000 --- a/_includes/archive-single-post.html +++ /dev/null @@ -1,44 +0,0 @@ -{% if post.header.teaser %} - {% capture teaser %}{{ post.header.teaser }}{% endcapture %} -{% else %} - {% assign teaser = site.teaser %} -{% endif %} - -{% if post.id %} - {% assign title = post.title | markdownify | remove: "

" | remove: "

" %} -{% else %} - {% assign title = post.title %} -{% endif %} - -
-
- {% if include.type == "grid" and teaser %} -
- -
- {% endif %} -

- {% if post.link %} - {{ title }} Permalink - {% else %} - {{ title }} - {% endif %} -

- {% include post__meta.html type=include.type %} - {% comment %} {% if post.read_time %} -

{% include read-time.html %} -       - Author: {{post.author}} -     - Date: {{post.date | date: '%B %d, %Y'}} -

- {% endif %} {% endcomment %} - {% if post.excerpt %}

{{ post.excerpt | markdownify | strip_html | truncate: 160 }}

{% endif %} -
-
\ No newline at end of file diff --git a/_includes/head/custom.html b/_includes/head/custom.html deleted file mode 100644 index 5efeba56..00000000 --- a/_includes/head/custom.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/_includes/masthead.html b/_includes/masthead.html deleted file mode 100644 index 4f76a952..00000000 --- a/_includes/masthead.html +++ /dev/null @@ -1,37 +0,0 @@ -
-
-
- -
-
-
diff --git a/_includes/nav_list b/_includes/nav_list deleted file mode 100644 index e2beab50..00000000 --- a/_includes/nav_list +++ /dev/null @@ -1,50 +0,0 @@ -{% assign navigation = site.data.navigation[include.nav] %} - - \ No newline at end of file diff --git a/_layouts/archive.html b/_layouts/archive.html deleted file mode 100644 index 7c584c2e..00000000 --- a/_layouts/archive.html +++ /dev/null @@ -1,41 +0,0 @@ ---- -layout: default ---- - - -{% if page.header.overlay_color or page.header.overlay_image or page.header.image %} - {% include page__hero.html %} -{% elsif page.header.video.id and page.header.video.provider %} - {% include page__hero_video.html %} -{% endif %} - -{% if page.url != "/" and site.breadcrumbs %} - {% unless paginator %} - {% include breadcrumbs.html %} - {% endunless %} -{% endif %} - -
- {% include sidebar.html %} - -
- {% unless page.header.overlay_color or page.header.overlay_image %} -

{{ page.title }}

- {% endunless %} - {{ content }} -
-
\ No newline at end of file diff --git a/_layouts/collection.html b/_layouts/collection.html deleted file mode 100644 index 36d025e0..00000000 --- a/_layouts/collection.html +++ /dev/null @@ -1,22 +0,0 @@ ---- -layout: archive ---- - - -{{ content }} -
-
- {% include documents-collection.html collection=page.collection sort_by=page.sort_by sort_order=page.sort_order type=page.entries_layout %} -
-
diff --git a/_layouts/default.html b/_layouts/default.html deleted file mode 100644 index 1391a437..00000000 --- a/_layouts/default.html +++ /dev/null @@ -1,56 +0,0 @@ ---- ---- - - - - - {% include head.html %} - {% include head/custom.html %} - - - - - - {% include_cached browser-upgrade.html %} - {% include_cached masthead.html %} - -
- {{ content }} -
- - {% if site.search == true %} -
- {% include_cached search/search_form.html %} -
- {% endif %} - - - - {% include scripts.html %} - - - diff --git a/_layouts/posts.html b/_layouts/posts.html deleted file mode 100644 index 9081af0b..00000000 --- a/_layouts/posts.html +++ /dev/null @@ -1,31 +0,0 @@ ---- -layout: archive ---- - -{{ content }} - - - -{% assign postsByYear = site.posts | group_by_exp: 'post', 'post.date | date: "%Y"' %} -{% for year in postsByYear %} -
-

{{ year.name }}

-
- {% for post in year.items %} -
- {% include archive-single-post.html type=page.entries_layout %} -
- {% endfor %} -
- {{ site.data.ui-text[site.locale].back_to_top | default: 'Back to Top' }} ↑ -
-{% endfor %} diff --git a/_layouts/redirect.html b/_layouts/redirect.html deleted file mode 100644 index f30e53f9..00000000 --- a/_layouts/redirect.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - Page Redirection - - -If you are not redirected automatically, follow this link. - - \ No newline at end of file diff --git a/_layouts/single.html b/_layouts/single.html deleted file mode 100644 index 95be749b..00000000 --- a/_layouts/single.html +++ /dev/null @@ -1,105 +0,0 @@ ---- -layout: default ---- - -{% if page.header.overlay_color or page.header.overlay_image or page.header.image %} - {% include page__hero.html %} -{% elsif page.header.video.id and page.header.video.provider %} - {% include page__hero_video.html %} -{% endif %} - -{% if page.url != "/" and site.breadcrumbs %} - {% unless paginator %} - {% include breadcrumbs.html %} - {% endunless %} -{% endif %} - -
- {% include sidebar.html %} - -
- {% if page.title %}{% endif %} - {% if page.excerpt %}{% endif %} - {% if page.date %}{% endif %} - {% if page.last_modified_at %}{% endif %} - -
- {% unless page.header.overlay_color or page.header.overlay_image %} -
- {% if page.title %}

{{ page.title | markdownify | remove: "

" | remove: "

" }}

{% endif %} - {% include post__meta.html %} -
- {% endunless %} - -
- {% if page.toc %} - - {% endif %} - {{ content }} - {% if page.link %}
{{ site.data.ui-text[site.locale].ext_link_label | default: "Direct Link" }}
{% endif %} -
- -
- {% if site.data.ui-text[site.locale].meta_label %} -

{{ site.data.ui-text[site.locale].meta_label }}

- {% endif %} - {% include page__taxonomy.html %} - {% include page__date.html %} -
- - {% if jekyll.environment == 'production' and site.comments.provider and page.comments %} - {% include comments.html %} - {% endif %} - - {% if page.share %}{% include social-share.html %}{% endif %} - - {% include post_pagination.html %} -
- -
- - {% comment %}{% endcomment %} - {% if page.id and page.related and site.related_posts.size > 0 %} - - {% comment %}{% endcomment %} - {% elsif page.id and page.related %} - - {% endif %} -
diff --git a/_lfmp2020/01-Wrapping-proprietary-printer-drivers-into-a-Printer-Application.md b/_lfmp2020/01-Wrapping-proprietary-printer-drivers-into-a-Printer-Application.md deleted file mode 100644 index a205b2ec..00000000 --- a/_lfmp2020/01-Wrapping-proprietary-printer-drivers-into-a-Printer-Application.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: "Wrapping proprietary printer drivers into a Printer Application" ---- - -### Introduction -

-With sandboxed packaging, Linux distributions appear which do not use classic RPM or DEB packages any more, like the all-Snap Ubuntu Core. As a result CUPS will not work with classic PPD/filter-based printer drivers any more but requires all drivers being provided as Printer Applications. The student's task is to add this functionality to the Printer Application framework and create an easy way for users to install proprietary printer drivers into that chroot-equipped Printer Application. -

- -### Mentors -

-Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), Aveek Basu, Project Manager (basu dot aveek at gmail dot com) -

- -### Desired Knowledge -

-C programming, C++ programming, Python Programming -

- -### Code License -

-GPL 2+ or LGPL 2+ -

diff --git a/_lfmp2020/02-Support-IPP-Fax-Out.md b/_lfmp2020/02-Support-IPP-Fax-Out.md deleted file mode 100644 index 2d3418bc..00000000 --- a/_lfmp2020/02-Support-IPP-Fax-Out.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: "Support for IPP Fax Out" ---- - -### Introduction -

-IPP Fax out is a feature which is currently missing in Linux unlike Print and Scan. The student's task here is to make this functionality easily accessible for users of common desktop Linux distributions. Like printers, faxes should automatically appear on the system and get available in print dialogs and if one prints to a fax, fax-specific options should also appear in the print dialog and the user should be able to pick phone numbers also from contacts. -

- -### Mentors -

-Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), Aveek Basu, Project Manager (basu dot aveek at gmail dot com) -

- -### Desired Knowledge -

-C++ programming, Qt, CUPS -

- -### License -

-Qt Contribution Agreement -

diff --git a/_lfmp2020/03-ipp-scan-application.md b/_lfmp2020/03-ipp-scan-application.md deleted file mode 100644 index 0908c0a2..00000000 --- a/_lfmp2020/03-ipp-scan-application.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: "IPP scan (or virtual MF device) server (Scanner Application)" ---- -### Introduction -

-The Internet Printing Protocol (IPP) does not only support printing, but also scanning, as there are many printers which also have a scanner (multi-function (MF) devices). Both CUPS and the developer tool ippserver emulate IPP network printers but not IPP scanners and so they cannot serve as a server to share a local scanner. -

- -

-This task is about adding the scan server functionality. If you have a scanner connected locally (and it scans via SANE), share it as an IPP scanner, advertising itself and accepting jobs using the IPP driverless scanning standard. In contrary to SANE-based network scanning clients with any operating system, also phones or IoT devices can scan on your shared scanner. -

- -

-Also old hardware can be recycled to a modern MF device. -

- -

-This server software will be a so-called Scanner Application, a sample implementation of the future form of scanner drivers, easily packageable in sandboxed, distribution-independent package formats like Snap. -

- -### Mentors -

-Alexander Pevzner, “airscan” SANE backend author (pzz at apevzner dot com), Michael Sweet, author of CUPS (msweet at msweet dot org), Till Kamppeter, Project Leader OpenPrinting (till at linux dot com), Aveek Basu, Project Manager (basu dot aveek at gmail dot com) -

- -### Desired Knowledge -

-C programming, C++ programming, Printing -

- -### Code License -

-Apache 2.0 -

diff --git a/_pages/contact.md b/_pages/contact.md deleted file mode 100644 index 71624e96..00000000 --- a/_pages/contact.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: "Contact Us" -permalink: /contact/ -layout: collection -header: - overlay_color: "#000" - overlay_filter: "0.5" - overlay_image: /assets/images/contact_us.jpeg -excerpt: "Feel Free To Contact Us!" -author_profile: false ---- -## Our Mailing lists -We protect the e-mail addresses of our mailing lists against spam bots. Please replace all occurrences of “ at ” and “ dot ” by “@” and “.” resp. - -- **Development:** printing-architecture AT lists DOT linux DOT dev ([Archive](https://lore.kernel.org/printing-architecture/)) -- **Users:** printing-users AT lists DOT linux DOT dev ([Archive](https://lore.kernel.org/printing-users/)) - -Subscribing/Unsubscribing [instructions](https://subspace.kernel.org/subscribing.html) - -## Telegram -- Main chat room: [OpenPrinting](https://t.me/+RizBbjXz4uU2ZWM1) - -## Mastodon -- [#OpenPrinting](https://ubuntu.social/tags/OpenPrinting) -- [@till@ubuntu.social](https://ubuntu.social/@till) - -## LinkedIn -- [@OpenPrinting](https://www.linkedin.com/company/openprinting/posts/) diff --git a/_pages/driverless.md b/_pages/driverless.md deleted file mode 100644 index 4a0d9ab7..00000000 --- a/_pages/driverless.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -layout: collection -title: "Driverless Printing" -permalink: /driverless/ -author_profile: false -sidebar: - - image: /assets/images/logo _ipp.png - image_alt: "Driverless Printing" - nav: "driverless" ---- -

Introduction-:

-

Driverless Printing means that to be able to print on a given printer no software or data specific to that printer model needs to be installed on the client. The client should even be able to print on printers which did not exist yet when the client's software was released. The printer must use known page description languages and must inform the client about its capabilities on request.

-

There exist a variety of methods for a client to submit a job to a printing system and print driverlessly-:

- - -

Importance-:

-

Driverless printing is especially important for Linux and similar operating systems as they are often not explicitly supported by the manufacturers supplying drivers for them. Originally the driverless printing standards were created to allow smartphones, tablets, and similar mobile devices to print, as these come with several different and new operating systems. Even very cheap printers do driverless printing (people want to print from phones), so it is easy to get a printer for Linux nowadays.

diff --git a/_pages/gsoc-2020-students.html b/_pages/gsoc-2020-students.html deleted file mode 100644 index 78e823bb..00000000 --- a/_pages/gsoc-2020-students.html +++ /dev/null @@ -1,56 +0,0 @@ ---- -layout: default -title: GSOC 2020 Students -header: - overlay_color: "#616161" -layout: splash -permalink: /gsoc-2020-students/ ---- - -
- -
- Aakash Lahoti -

Aakash Lahoti

-

IPP scan server (Scanner Application)

-
- -
- Priydarshi Singh -

Priydarshi Singh

-

CPDB Qt implementation

-
- -
- Jai Luthra -

Jai Luthra

-

General Printer Application SDK

-
- -
- Sambhav Dusad -

Sambhav Dusad

-

Make Printer Applications configurable

-
- - -
- Mohit Mohan -

Mohit Mohan

-

Speed/scaling optimization of cups-browsed

-
- -
- Lakshay Bandlish -

Lakshay Bandlish

-

Linux GUI Application to admin MF devices using IPP System Service

-
- -
- Vikrant Malik -

Vikrant Malik

-

Extract raster data from PDFs for direct printing

-
- - -
diff --git a/_pages/gsoc-2021-students.html b/_pages/gsoc-2021-students.html deleted file mode 100644 index 08f40fc9..00000000 --- a/_pages/gsoc-2021-students.html +++ /dev/null @@ -1,44 +0,0 @@ ---- -layout: default -title: GSOC 2021 Students -header: - overlay_color: "#616161" -layout: splash -permalink: /gsoc-2021-students/ ---- - -
- -
- Suraj Kulriya -

Suraj Kulriya

-

Make All Filter Functions Work Well Even Without PPD Files

-
- -
- Divyasheel -

Divyasheel

-

GUI for listing and managing available IPP services

-
- -
- Bhavna Kosta -

Bhavna Kosta

-

Firmware and other file handling in PAPPL

-
- -
- Pranshu Kharkwal -

Pranshu Kharkwal

-

Create a single universal CUPS filter to replace the chain of individual filters

-
- - -
- Pratyush Ranjan -

Pratyush Ranjan

-

CUPS Filters: Converting Filters to Filter Functions

-
- - -
diff --git a/_pages/gsoc.md b/_pages/gsoc.md deleted file mode 100644 index 7ee0d534..00000000 --- a/_pages/gsoc.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: "GSoC - OpenPrinting" -permalink: /gsoc/ ---- - -## Year-Wise GSoC Project List - -### 1. [GSOC 2021](/gsoc2021/) - -### 2. [GSOC 2020](/gsoc2020/) - -### 3. [GSOC 2019](/gsoc2019/) - -## Year-Wise GSoC Students - -### 1. [GSOC 2021](/gsoc-2021-students/) - -### 2. [GSOC 2020](/gsoc-2020-students/) \ No newline at end of file diff --git a/_pages/gsoc2020.md b/_pages/gsoc2020.md deleted file mode 100644 index bbbf5ebf..00000000 --- a/_pages/gsoc2020.md +++ /dev/null @@ -1,460 +0,0 @@ ---- -layout: collection -title: "GSoC 2020 Projects" -# collection: gsoc2020 -permalink: /gsoc2020/ -author_profile: false -sidebar: - nav: "gsoc20" ---- -
- -

-Main GSoC Linux Foundation page: How to apply, deadlines, other workgroups, ... -

- -
- -

Contact

-
- -

-Important: We protect the e-mail addresses of our mentors and mailing lists against spam bots. Please replace all occurrences of “ at ” and “ dot ” by “@” and “.” resp. -

- -

-Mailing list: printing-architecture at lists dot linux-foundation dot org -

- -

-IRC: #openprinting on Freenode -

- -

-OpenPrinting GitHub -

- -

-Code License: See project descriptions -

- -
- -

Organization Administrators

-
- -

-The participation of the Linux Foundation in the Google Summer of Code is organized by Till Kamppeter (till at linux dot com) and Aveek Basu (basu dot aveek at gmail dot com). -

- -
- -

-Please see the plans for our near future work to get an overview of our development direction and architecture changes. -

- -

Project Ideas

-
- - - - - - -
- -
- - - - -
- -
- - - - -
- -
- - - - -
- -
- - - - -
- -
- - - - -
- -
- - - - -
- -
- - - - -
- -
- - - - -
- -
- - - - -
- -
- - - - -
- -
- - - - -
- -
- - - - -
- -
- - - - -
- -
- - - - -
- -
- - - - -
- -
- - - - -
- -
- -
- - - -
-

Results

-
-

1. Extract raster data from PDFs for direct printing

-

Student: Vikrant Malik
Mentors: Sahil Arora, Till Kamppeter
- Work Product
-

PASSED

-

- -

2. General Printer Application SDK

-

Student: Jai Luthra
Mentors: Mentors: Michael Sweet, Till Kamppeter
- Work Product
-

PASSED

- Jai has principally worked on PAPPL but also done an HP PCL sample Printer Application. In the end he has also worked on converting filters of cups-filters into filter functions. -

- -

3. Linux GUI application to admin MF devices using IPP System Service

-

Student: Lakshay Bandlish
Mentor: Michael Sweet
- Work Product
-

PASSED

-

- -

4. Make Printer Applications Configurable

-

Student: Sambhav Dusad
Mentor: Michael Sweet
- Work Product
-

PASSED

- - Sambhav has also started to create a Gutenprint Printer Application. - - -

- - -

5. Speed/Scaling Optimisation of cups-browsed

-

Student: Mohit Mohan
Mentors: Deepak Patankar, Till Kamppeter
- Work Product
-

PASSED

-

- -

6. Common Print Dialog Backends (CPDB) Qt ImplementationPermalink

-

Student: Priydarshi Singh
Mentor: Dongxu Li
- Work Product -

FAILED(final evaluation)

- We are looking into finishing up CPDB after GSoC. -

- -

7. IPP Scan (or virtual MF device) server (Scanner Application)Permalink

-

Student: Aakash Lahoti
Mentors: Michael Sweet, Alexander Pevzner
-
- WITHDRAWN (shortly after first evaluation) -
- We have replaced this project by a 2-student LFMP project (see here). -

- - -
diff --git a/_pages/gsod-2020-students.html b/_pages/gsod-2020-students.html deleted file mode 100644 index a5dfd195..00000000 --- a/_pages/gsod-2020-students.html +++ /dev/null @@ -1,18 +0,0 @@ ---- -layout: default -title: GSoD 2020 Students -header: - overlay_color: "#616161" -layout: splash -permalink: /gsod-2020-students/ ---- - -
- -
- Piyush Goyal -

Piyush Goyal

-

Tutorial and Design Guidelines for Printer/Scanner drivers in Printer Applications

-
- -
diff --git a/_pages/lfmp-2020-students.html b/_pages/lfmp-2020-students.html deleted file mode 100644 index 81c44701..00000000 --- a/_pages/lfmp-2020-students.html +++ /dev/null @@ -1,36 +0,0 @@ ---- -layout: default -title: LFMP 2020 Students -header: - overlay_color: "#616161" -layout: splash -permalink: /lfmp-2020-students/ ---- - -
- -
- Nidhi Jain -

Nidhi Jain

-

Support for IPP Fax Out

-
- -
- Dipanshu Verma -

Dipanshu Verma

-

Wrapping proprietary printer drivers into a Printer Application

-
- -
- Abhik Chakraborty -

Abhik Chakraborty

-

IPP scan (or virtual MF device) server (Scanner Application)

-
- -
- Rishabh Arya -

Rishabh Arya

-

IPP scan (or virtual MF device) server (Scanner Application)

-
- -
diff --git a/_pages/news.html b/_pages/news.html deleted file mode 100644 index d18219e2..00000000 --- a/_pages/news.html +++ /dev/null @@ -1,11 +0,0 @@ ---- -layout: posts -title: News and Events -permalink: /news/ ---- - -
- - Monthly Call Minutes - -
diff --git a/_posts/2025-08-27-OpenPrinting News - Opportunity Open Source 3.0 - Schedules and contributions published.md b/_posts/2025-08-27-OpenPrinting News - Opportunity Open Source 3.0 - Schedules and contributions published.md deleted file mode 100644 index cbbb6d1f..00000000 --- a/_posts/2025-08-27-OpenPrinting News - Opportunity Open Source 3.0 - Schedules and contributions published.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: OpenPrinting News - Opportunity Open Source 3.0 - Schedules and contributions published -layout: single -toc: false -toc_sticky: true -author: Till -excerpt: Have a look into the amazing presentations and workshops, plan your participation! ---- -Only 10 days left to the [Opportunity Open Source 3.0](https://oosc3ubucon.netlify.app/) in the IIT Kanpur in India! Now we got all the session proposals which got promised to us and so we have scheduled the contributions now and published everything. - -Here are the [full schedules](https://events.canonical.com/event/134/timetable/?layout=room#all.detailed) and the [list of contributions](https://events.canonical.com/event/134/contributions/). Click on the entries to read the abstracts and get more details about each session. - -Note that the schedules are subject to change, as for example remote speakers are perhaps not able to give their presentation at the scheduled time. - -Also watch out for further info on our site, about the location, about remote attending, and speakers could add slides, preparation instructions and exercise repositories for workshops, ... - -See you all in Kanpur ... - -- [Event web site](https://oosc3ubucon.netlify.app/) -- [Practical info: Location, remote attending/speaking, ...](https://events.canonical.com/event/134/) -- [Full schedules](https://events.canonical.com/event/134/timetable/?layout=room#all.detailed) -- [List of contributions](https://events.canonical.com/event/134/contributions/) -- Mastodon: [#OpportunityOpenSource](https://ubuntu.social/tags/OpportunityOpenSource) -- LinkedIn: [@opportunity-open-source](https://www.linkedin.com/company/opportunity-open-source/) - - -**And as usual: Stay updated on Mastodon: [#OpenPrinting](https://ubuntu.social/tags/OpenPrinting) and [@till@ubuntu.social](https://ubuntu.social/@till) and on LinkedIn: [@OpenPrinting](https://www.linkedin.com/company/openprinting/).** - -**Or discuss on our mailing lists:** -- **Development:** printing-architecture AT lists DOT linux DOT dev ([Archive](https://lore.kernel.org/printing-architecture/)) -- **Users:** printing-users AT lists DOT linux DOT dev ([Archive](https://lore.kernel.org/printing-users/)) - -Subscribing/Unsubscribing [instructions](https://subspace.kernel.org/subscribing.html) - -**Or on the Telegram [OpenPrinting chat](https://t.me/+RizBbjXz4uU2ZWM1)** - diff --git a/_projects/03-ippusbxd.md b/_projects/03-ippusbxd.md deleted file mode 100644 index 37db9fea..00000000 --- a/_projects/03-ippusbxd.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: "IPPUSBXD" ---- -IPPUSBXD is a userland driver for IPP-over-USB class USB devices. It has been -designed for Linux but uses a cross platform usb library allowing eventual -porting to Windows and other non-POSIX platforms. - -The IPP-over-USB standard was ratified by the USB forum in 2012. As of -2014 Mac OS X implemented this standard and with the addition of -ippusbxd Linux shall as well. - -IPPUSBXD depends on POSIX threads, POSIX networking, and libusb as -developed by the community at libusb.info - -IPPUSBXD has the following advantages: - -1. At runtime links only with libc, pthreads, libusb, and -libavahi*. On a typical system these libraries will already be in -RAM. This gives ippusbxd a minimal ram footprint. -2. Requires no read access to any files. -3. Ships with a strict AppArmor profile. -3. Runs warning & leak free in valgrind -4. Compiles warning free in clang -5. Analyzed warning free in Coverity -6. Can be installed anywhere -7. Near zero CPU usage while idle -8. Low CPU usage while working - -### Project Links - -* - GitHub - diff --git a/app/[...slug]/page.tsx b/app/[...slug]/page.tsx new file mode 100644 index 00000000..1a610627 --- /dev/null +++ b/app/[...slug]/page.tsx @@ -0,0 +1,352 @@ +import fs from "fs/promises"; +import path from "path"; +import matter from "gray-matter"; +import type { Metadata } from "next"; +import { redirect, notFound } from "next/navigation"; +import Link from "next/link"; +import Image from "next/image"; +import { ArrowRight, ChevronLeft, ChevronRight } from "lucide-react"; +import { MarkdownRenderer } from "@/components/markdown-renderer"; +import { TableOfContents } from "@/components/table-of-contents"; +import GiscusComments from "@/components/giscus-comment"; +import AuthorCard from "@/components/AuthorCard"; +import authors from "@/data/authors"; +import { getAuthorImageSrc, getImageSrc } from "@/lib/utils"; +import { getTeaserImage } from "@/lib/get-latest-posts"; +import { getAllPostRecords } from "@/lib/posts"; +import { getLegacyRedirect, legacyRedirectParams } from "@/lib/legacy-redirects"; +import { siteConfig } from "@/config/site.config"; +import { getSiteUrl } from "@/lib/site"; + +const defaultOgImageUrl = getSiteUrl(siteConfig.brand.defaultOgImagePath); + +const POSTS_DIR = path.join(process.cwd(), "contents", "post"); + +async function getPost(slug: string) { + const decodedSlug = decodeURIComponent(slug); + const filePath = path.join(POSTS_DIR, `${decodedSlug}.md`); + const raw = await fs.readFile(filePath, "utf8"); + const { data, content } = matter(raw); + return { + frontmatter: data as Record, + content: content ?? "", + }; +} + +async function getAllPostsMetadata() { + const posts = getAllPostRecords().map((record) => ({ + slug: record.slug, + title: record.title, + date: record.date, + author: record.author, + excerpt: record.excerpt, + previousSlugs: record.aliases, + })); + + posts.sort((a, b) => { + const da = a.date ? new Date(a.date).getTime() : 0; + const db = b.date ? new Date(b.date).getTime() : 0; + return db - da; + }); + + return posts; +} + +export async function generateMetadata({ + params, +}: { + params: Promise<{ slug: string }>; +}): Promise { + const { slug } = await params; + const decodedSlug = decodeURIComponent(slug); + + if (decodedSlug === "cups") { + return { + title: "CUPS", + alternates: { + canonical: siteConfig.destinations.cups, + }, + }; + } + + const allPosts = await getAllPostsMetadata(); + const directMatch = allPosts.find((post) => post.slug === decodedSlug); + const redirectMatch = directMatch + ? null + : allPosts.find((post) => post.previousSlugs.includes(decodedSlug)); + + const matchedPost = directMatch ?? redirectMatch; + if (!matchedPost) return {}; + + const resolvedSlug = matchedPost.slug; + const { frontmatter, content } = await getPost(resolvedSlug); + + const title = + typeof frontmatter.title === "string" && frontmatter.title.trim() !== "" + ? frontmatter.title.trim() + : matchedPost.title; + const description = + typeof frontmatter.excerpt === "string" && frontmatter.excerpt.trim() !== "" + ? frontmatter.excerpt.trim() + : matchedPost.excerpt; + const teaserImage = getTeaserImage(frontmatter, content); + const resolvedTeaserImage = teaserImage + ? getImageSrc(teaserImage) + : undefined; + const imageUrl = resolvedTeaserImage + ? /^https?:\/\//.test(resolvedTeaserImage) + ? resolvedTeaserImage + : getSiteUrl(resolvedTeaserImage) + : defaultOgImageUrl; + const canonicalPath = resolvedSlug === decodedSlug ? `/${resolvedSlug}` : `/${decodedSlug}`; + const canonicalUrl = getSiteUrl(canonicalPath); + + return { + title, + description, + alternates: { + canonical: canonicalUrl, + }, + openGraph: { + title, + description, + url: canonicalUrl, + type: "article", + images: imageUrl ? [{ url: imageUrl, alt: title }] : undefined, + }, + twitter: { + card: "summary_large_image", + title, + description, + images: [imageUrl], + }, + }; +} + +export async function generateStaticParams() { + const params: { slug: string[] }[] = []; + + for (const record of getAllPostRecords()) { + params.push({ slug: [record.slug] }); + for (const alias of record.aliases) { + params.push({ slug: [alias] }); + } + } + + params.push({ slug: ["cups"] }); + + for (const legacy of legacyRedirectParams()) { + params.push(legacy); + } + + return params; +} + +export default async function PostPage({ + params, +}: { + params: Promise<{ slug: string[] }>; +}) { + const { slug } = await params; + + const slugString = Array.isArray(slug) ? slug.join("/") : slug; + const decodedSlug = decodeURIComponent(slugString); + + if (decodedSlug === "cups") { + redirect(siteConfig.destinations.cups); + } + + const legacyTarget = getLegacyRedirect(decodedSlug); + if (legacyTarget) { + redirect(legacyTarget); + } + + const allPosts = await getAllPostsMetadata(); + + const directMatch = allPosts.find((post) => post.slug === decodedSlug); + + if (!directMatch) { + const redirectMatch = allPosts.find((post) => + post.previousSlugs.includes(decodedSlug) + ); + + if (redirectMatch) { + redirect(`/${redirectMatch.slug}`); + } + + notFound(); + } + + const currentIndex = allPosts.findIndex((post) => post.slug === decodedSlug); + const newerPost = currentIndex > 0 ? allPosts[currentIndex - 1] : null; + const olderPost = currentIndex < allPosts.length - 1 ? allPosts[currentIndex + 1] : null; + const relatedPosts = allPosts + .filter((post) => post.slug !== decodedSlug) + .slice(0, 3); + + const { frontmatter, content: markdownContent } = await getPost(decodedSlug); + + const rawAuthor = + typeof frontmatter.author === "string" ? frontmatter.author.trim() : ""; + const authorKey = rawAuthor !== "" ? rawAuthor : undefined; + + const title = + typeof frontmatter.title === "string" && frontmatter.title.trim() !== "" + ? frontmatter.title.trim().replace(/\\/g,"") + : "Untitled Article"; + + let formattedDate = ""; + if (typeof frontmatter.date === "string" && frontmatter.date.trim() !== "") { + const parsedDate = new Date(frontmatter.date); + formattedDate = parsedDate.toLocaleDateString("en-US", { + year: "numeric", + month: "long", + day: "numeric", + }); + } + + const readTime = + typeof frontmatter.readTime === "string" && + frontmatter.readTime.trim() !== "" + ? frontmatter.readTime.trim() + : ""; + + const showToc = + !!frontmatter && + (frontmatter.toc === true || String(frontmatter.toc) === "true"); + + return ( +
+
+
+ {authorKey && ( + + )} + +
+
+

+ {title} +

+ {formattedDate && ( +
+ {formattedDate} +
+ )} + {readTime && ( +
+ + + + + {readTime} +
+ )} +
+
+ + {showToc && (
+ +
)} + +
+
+ +
+ +
+ +
+ + + + {relatedPosts.length > 0 && ( +
+

You may also enjoy

+
+ {relatedPosts.map((post) => { + const postAuthor = post.author ? authors.find((a) => a.key === post.author) : null; + const imgSrc = getAuthorImageSrc(postAuthor?.image); + return ( + +
+

{post.title}

+ + {postAuthor && ( +
+
+ {postAuthor.name} +
+ {postAuthor.name} +
+ )} + + {post.date && ( +
+ + {new Date(post.date).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" })} +
+ )} + + {post.excerpt && ( +

{post.excerpt}

+ )} + +
+ Read more + +
+
+ + ); + })} +
+
+ )} +
+
+ + {showToc && ()} +
+
+
+ ); +} diff --git a/app/about-us/page.tsx b/app/about-us/page.tsx new file mode 100644 index 00000000..50666992 --- /dev/null +++ b/app/about-us/page.tsx @@ -0,0 +1,27 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import { MarkdownRenderer } from "@/components/markdown-renderer" +import { PageHero } from "@/components/page-hero" + +const FILE_PATH = path.join(process.cwd(), "contents", "pages", "about-us.md") + +export default async function AboutUsPage() { + const raw = await fs.readFile(FILE_PATH, "utf8") + const { data, content } = matter(raw) + + const title = + typeof data.title === "string" ? data.title : "About Us" + + return ( + <> + + +
+
+ +
+
+ + ) +} diff --git a/app/achievements/page.tsx b/app/achievements/page.tsx new file mode 100644 index 00000000..b784f90e --- /dev/null +++ b/app/achievements/page.tsx @@ -0,0 +1,27 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import { MarkdownRenderer } from "@/components/markdown-renderer" +import { PageHero } from "@/components/page-hero" + +const FILE_PATH = path.join(process.cwd(), "contents", "pages", "achievements.md") + +export default async function AchievementsPage() { + const raw = await fs.readFile(FILE_PATH, "utf8") + const { data, content } = matter(raw) + + const title = + typeof data.title === "string" ? data.title : "Achievements" + + return ( + <> + + +
+
+ +
+
+ + ) +} diff --git a/app/codeofconduct/page.tsx b/app/codeofconduct/page.tsx new file mode 100644 index 00000000..01edd312 --- /dev/null +++ b/app/codeofconduct/page.tsx @@ -0,0 +1,30 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import { MarkdownRenderer } from "@/components/markdown-renderer" +import { PageHero } from "@/components/page-hero" + +const FILE_PATH = path.join(process.cwd(), "contents", "pages", "codeofconduct.md") + +export default async function CodeOfConductPage() { + const raw = await fs.readFile(FILE_PATH, "utf8") + const { data, content } = matter(raw) + + const title = + typeof data.title === "string" ? data.title : "Code of Conduct" + + return ( + <> + + +
+
+ +
+
+ + ) +} diff --git a/app/contact/page.tsx b/app/contact/page.tsx new file mode 100644 index 00000000..2a8bbea8 --- /dev/null +++ b/app/contact/page.tsx @@ -0,0 +1,35 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import { MarkdownRenderer } from "@/components/markdown-renderer" +import { PageHero } from "@/components/page-hero" + +const FILE_PATH = path.join( + process.cwd(), + "contents", + "pages", + "contact.md" +) + +export default async function ContactPage() { + const raw = await fs.readFile(FILE_PATH, "utf8") + const { data, content } = matter(raw) + + const title = + typeof data.title === "string" ? data.title : "Contact" + + return ( + <> + + +
+
+ +
+
+ + ) +} diff --git a/app/contribute-website/page.tsx b/app/contribute-website/page.tsx new file mode 100644 index 00000000..58c33591 --- /dev/null +++ b/app/contribute-website/page.tsx @@ -0,0 +1,26 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import { MarkdownRenderer } from "@/components/markdown-renderer" +import { PageHero } from "@/components/page-hero" + +const FILE_PATH = path.join(process.cwd(), "contents", "pages", "contribute-website.md") + +export default async function ContributeWebsitePage() { + const raw = await fs.readFile(FILE_PATH, "utf8") + const { data, content } = matter(raw) + + const title = + typeof data.title === "string" ? data.title : "Contribute to OpenPrinting Website" + + return ( + <> + +
+
+ +
+
+ + ) +} diff --git a/app/contribute/page.tsx b/app/contribute/page.tsx new file mode 100644 index 00000000..5a33e76a --- /dev/null +++ b/app/contribute/page.tsx @@ -0,0 +1,35 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import { MarkdownRenderer } from "@/components/markdown-renderer" +import { PageHero } from "@/components/page-hero" + +const FILE_PATH = path.join( + process.cwd(), + "contents", + "pages", + "contribute.md" +) + +export default async function ContributePage() { + const raw = await fs.readFile(FILE_PATH, "utf8") + const { data, content } = matter(raw) + + const title = + typeof data.title === "string" ? data.title : "Contribute" + + return ( + <> + + +
+
+ +
+
+ + ) +} diff --git a/app/current/page.tsx b/app/current/page.tsx new file mode 100644 index 00000000..df15ce1f --- /dev/null +++ b/app/current/page.tsx @@ -0,0 +1,27 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import { MarkdownRenderer } from "@/components/markdown-renderer" +import { PageHero } from "@/components/page-hero" + +const FILE_PATH = path.join(process.cwd(), "contents", "pages", "current.md") + +export default async function CurrentPage() { + const raw = await fs.readFile(FILE_PATH, "utf8") + const { data, content } = matter(raw) + + const title = + typeof data.title === "string" ? data.title : "Current Work" + + return ( + <> + + +
+
+ +
+
+ + ) +} diff --git a/app/databaseintro/page.tsx b/app/databaseintro/page.tsx new file mode 100644 index 00000000..304ac8fe --- /dev/null +++ b/app/databaseintro/page.tsx @@ -0,0 +1,26 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import { MarkdownRenderer } from "@/components/markdown-renderer" +import { PageHero } from "@/components/page-hero" + +const FILE_PATH = path.join(process.cwd(), "contents", "pages", "databaseintro.md") + +export default async function DatabaseIntroPage() { + const raw = await fs.readFile(FILE_PATH, "utf8") + const { data, content } = matter(raw) + + const title = + typeof data.title === "string" ? data.title : "Printer Compatibility Database" + + return ( + <> + +
+
+ +
+
+ + ) +} diff --git a/app/documentation/[doc]/page.tsx b/app/documentation/[doc]/page.tsx new file mode 100644 index 00000000..8c7871ea --- /dev/null +++ b/app/documentation/[doc]/page.tsx @@ -0,0 +1,49 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import { MarkdownRenderer } from "@/components/markdown-renderer" + +export const dynamic = "force-static" +export const dynamicParams = false + +const DOCS_DIR = path.join(process.cwd(), "contents", "documentation") + +export async function generateStaticParams() { + const files = await fs.readdir(DOCS_DIR) + return files + .filter((f) => f.endsWith(".md")) + .map((file) => ({ + doc: file.replace(/\.md$/, ""), + })) +} + +export default async function DocumentationDetail({ + params, +}: { + params: Promise<{ doc: string }> +}) { + const { doc } = await params + + const filePath = path.join(DOCS_DIR, `${doc}.md`) + const raw = await fs.readFile(filePath, "utf8") + const { data, content } = matter(raw) + + const title = + typeof data.title === "string" + ? data.title + : doc.replace(/^\d+-/, "").replace(/-/g, " ") + + return ( +
+
+

+ {title} +

+ +
+ +
+
+
+ ) +} diff --git a/app/documentation/page.tsx b/app/documentation/page.tsx new file mode 100644 index 00000000..5079c268 --- /dev/null +++ b/app/documentation/page.tsx @@ -0,0 +1,64 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import Link from "next/link" +import { MarkdownRenderer } from "@/components/markdown-renderer" + +const PAGE_MD = path.join(process.cwd(), "contents", "pages", "documentation.md") +const DOCS_DIR = path.join(process.cwd(), "contents", "documentation") + +export default async function DocumentationPage() { + const raw = await fs.readFile(PAGE_MD, "utf8") + const { data, content } = matter(raw) + + const files = (await fs.readdir(DOCS_DIR)) + .filter((f) => f.endsWith(".md")) + .sort() + + const docs = await Promise.all( + files.map(async (file) => { + const raw = await fs.readFile(path.join(DOCS_DIR, file), "utf8") + const { data } = matter(raw) + + return { + slug: file.replace(/\.md$/, ""), + title: + typeof data.title === "string" + ? data.title + : file.replace(/\.md$/, ""), + } + }) + ) + + const hasContent = content != null && content.trim().length > 0 + + return ( +
+
+

+ {typeof data.title === "string" ? data.title : "Documentation"} +

+ + {hasContent && ( +
+ +
+ )} + +
    + {docs.map((doc) => ( +
  • + + {doc.title} + +
  • + ))} +
+
+
+ ) +} diff --git a/app/donations/page.tsx b/app/donations/page.tsx new file mode 100644 index 00000000..6cdddefe --- /dev/null +++ b/app/donations/page.tsx @@ -0,0 +1,32 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import { MarkdownRenderer } from "@/components/markdown-renderer" +import { PageHero } from "@/components/page-hero" + +const FILE_PATH = path.join( + process.cwd(), + "contents", + "pages", + "donations.md" +) + +export default async function DonationsPage() { + const raw = await fs.readFile(FILE_PATH, "utf8") + const { data } = matter(raw) + + const title = + typeof data.title === "string" ? data.title : "Donations" + + return ( + <> + + +
+
+ +
+
+ + ); +} diff --git a/app/downloads/page.tsx b/app/downloads/page.tsx new file mode 100644 index 00000000..d8e5747b --- /dev/null +++ b/app/downloads/page.tsx @@ -0,0 +1,69 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import Image from "next/image" +import { getAssetPath } from "@/lib/utils"; + +type FeatureItem = { + image_path: string + alt: string + title: string + url: string + btn_label?: string +} + +const FILE_PATH = path.join( + process.cwd(), + "contents", + "pages", + "downloads.md" +) + +export default async function DownloadsPage() { + const raw = await fs.readFile(FILE_PATH, "utf8") + const { data } = matter(raw) + + const title = + typeof data.title === "string" ? data.title : "Downloads" + + const features: FeatureItem[] = Array.isArray(data.feature_row) + ? data.feature_row + : [] + + return ( +
+
+

+ {title} +

+ +
+ {features.map((item, idx) => ( +
+
+ {item.alt} +
+

+ {item.title} +

+ + {item.btn_label ?? "Download"} + +
+ ))} +
+
+
+ ) +} diff --git a/app/driverless/page.tsx b/app/driverless/page.tsx new file mode 100644 index 00000000..e671c324 --- /dev/null +++ b/app/driverless/page.tsx @@ -0,0 +1,75 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import Image from "next/image" +import { MarkdownRenderer } from "@/components/markdown-renderer" +import { getAssetPath } from "@/lib/utils"; + +const FILE_PATH = path.join( + process.cwd(), + "contents", + "pages", + "driverless.md" +) + +const driverlessNavItems = [ + { name: "Introduction to Driverless Printing", href: "#introduction" }, + { name: "Standards And their PDLS", href: "#standards" }, + { name: "Workflow of Driverless Printing", href: "#workflow" }, +] + +export default async function DriverlessPage() { + const raw = await fs.readFile(FILE_PATH, "utf8") + const { data, content } = matter(raw) + + const title = + typeof data.title === "string" ? data.title : "Driverless Printing" + + return ( +
+
+
+ + +
+

+ {title} +

+ +
+ +
+
+
+
+
+ ) +} diff --git a/app/drivers/page.tsx b/app/drivers/page.tsx new file mode 100644 index 00000000..f110ddef --- /dev/null +++ b/app/drivers/page.tsx @@ -0,0 +1,19 @@ +"use client" + +import { useEffect } from "react" +import { siteConfig } from "@/config/site.config"; + +export default function DriversPage() { + useEffect(() => { + window.location.href = siteConfig.destinations.drivers + }, []) + + return ( +
+

Redirecting...

+

+ Redirecting to OpenPrinting Drivers database... +

+
+ ); +} diff --git a/assets/images/logo.png b/app/favicon.ico similarity index 100% rename from assets/images/logo.png rename to app/favicon.ico diff --git a/app/foomatic/driver/[id]/page.tsx b/app/foomatic/driver/[id]/page.tsx new file mode 100644 index 00000000..be3d1bc9 --- /dev/null +++ b/app/foomatic/driver/[id]/page.tsx @@ -0,0 +1,69 @@ +import fs from "fs/promises" +import path from "path" +import type { Metadata } from "next" +import type { DriverRecord, DriverSummary } from "@/lib/foomatic/types" +import DriverPageClient from "@/components/foomatic/DriverPageClient" +import { getSiteUrl } from "@/lib/site" + +async function getDriverSummaries(): Promise { + const filePath = path.join(process.cwd(), "public", "foomatic-db", "driversMap.json") + try { + const data = await fs.readFile(filePath, "utf-8") + const json = JSON.parse(data) + return json.drivers + } catch (error) { + if ((error as NodeJS.ErrnoException).code === "ENOENT") { + return [] + } + + throw error + } +} + +export async function generateStaticParams() { + const drivers = await getDriverSummaries() + return drivers.map((driver) => ({ + id: driver.id, + })) +} + +interface DriverPageProps { + params: Promise<{ + id: string + }> +} + +async function getDriver(id: string): Promise { + const filePath = path.join(process.cwd(), "public", "foomatic-db", "drivers", `${id}.json`) + try { + return JSON.parse(await fs.readFile(filePath, "utf-8")) as DriverRecord + } catch { + return null + } +} + +export async function generateMetadata({ params }: DriverPageProps): Promise { + const { id } = await params + const driver = await getDriver(id) + const name = driver?.name ?? id + const printerCount = driver?.printerCount ?? 0 + const title = `${name} — Printer driver | OpenPrinting` + const description = + driver?.shortDescription || + `The ${name} printer driver in the OpenPrinting database` + + (printerCount ? `, supporting ${printerCount} printer model${printerCount === 1 ? "" : "s"}.` : ".") + const canonical = getSiteUrl(`/foomatic/driver/${id}/`) + + return { + title, + description, + alternates: { canonical }, + openGraph: { title, description, url: canonical, type: "website" }, + } +} + +export default async function DriverPage({ params }: DriverPageProps) { + const { id } = await params + + return +} diff --git a/app/foomatic/driver/page.tsx b/app/foomatic/driver/page.tsx new file mode 100644 index 00000000..e0e4c172 --- /dev/null +++ b/app/foomatic/driver/page.tsx @@ -0,0 +1,17 @@ +import { Suspense } from "react" + +import DriverListClient from "@/components/foomatic/DriverListClient" + +export const metadata = { + title: "Printer Drivers | OpenPrinting Foomatic", + description: + "Browse the OpenPrinting Foomatic driver database. Find printer drivers, their supported printers, licenses, and project home pages.", +} + +export default function DriverIndexPage() { + return ( + + + + ) +} diff --git a/app/foomatic/page.tsx b/app/foomatic/page.tsx new file mode 100644 index 00000000..26d6e248 --- /dev/null +++ b/app/foomatic/page.tsx @@ -0,0 +1,566 @@ +"use client" + +import { useCallback, useEffect, useMemo, useState } from "react" +import { + ArrowLeft, + ArrowRight, + PrinterIcon, +} from "lucide-react" + +import PrinterSearch from "@/components/foomatic/PrinterSearch" +import Printers from "@/components/foomatic/Printers" +import { + FoomaticCard, + FoomaticHeroPill, + FoomaticPageSection, + FoomaticSelect, +} from "@/components/foomatic/shared" +import { Button } from "@/components/ui/button" +import { withBasePath } from "@/lib/foomatic/base-path" +import type { PrinterSummary } from "@/lib/foomatic/types" +import { calculateAccurateStatus } from "@/lib/foomatic/utils" + +const ITEMS_PER_PAGE_OPTIONS = [20, 50, 100, 200, -1] as const + +const STORAGE_KEYS = { + SEARCH: "printer_search", + MANUFACTURER: "printer_manufacturer", + DRIVER_TYPE: "printer_driver_type", + MECHANISM_TYPE: "printer_mechanism_type", + SUPPORT_LEVEL: "printer_support_level", + COLOR_CAPABILITY: "printer_color_capability", + PAGE: "printer_page", + ITEMS_PER_PAGE: "printer_items_per_page", +} as const + +function LoadingCard() { + return ( + +
+
+
+
+
+
+
+
+
+
+
+ + ) +} + +function PaginationControls({ + itemsPerPage, + setItemsPerPage, + setCurrentPage, + startIndex, + endIndex, + filteredLength, +}: { + itemsPerPage: number + setItemsPerPage: (n: number) => void + setCurrentPage: (n: number) => void + startIndex: number + endIndex: number + filteredLength: number +}) { + const displayStart = filteredLength === 0 ? 0 : startIndex + 1 + const displayEnd = filteredLength === 0 ? 0 : endIndex + + return ( + +
+
+ Results per page + { + const value = parseInt(event.target.value, 10) + setItemsPerPage(value) + setCurrentPage(1) + }} + className="w-full sm:w-40" + > + {ITEMS_PER_PAGE_OPTIONS.map((option) => ( + + ))} + +
+ +

+ Showing {displayStart}-{displayEnd} of {filteredLength} printer models +

+
+
+ ) +} + +export default function HomePage() { + const [printers, setPrinters] = useState([]) + const [manufacturers, setManufacturers] = useState([]) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + const [searchQuery, setSearchQuery] = useState("") + const [selectedManufacturer, setSelectedManufacturer] = useState("all") + const [selectedDriverType, setSelectedDriverType] = useState("all") + const [selectedMechanismType, setSelectedMechanismType] = useState("all") + const [selectedSupportLevel, setSelectedSupportLevel] = useState("all") + const [selectedColorCapability, setSelectedColorCapability] = useState("all") + const [currentPage, setCurrentPage] = useState(1) + const [itemsPerPage, setItemsPerPage] = useState(20) + + useEffect(() => { + if (typeof window === "undefined") { + return + } + + const savedSearch = localStorage.getItem(STORAGE_KEYS.SEARCH) + const savedManufacturer = localStorage.getItem(STORAGE_KEYS.MANUFACTURER) + const savedDriverType = localStorage.getItem(STORAGE_KEYS.DRIVER_TYPE) + const savedMechanismType = localStorage.getItem(STORAGE_KEYS.MECHANISM_TYPE) + const savedSupportLevel = localStorage.getItem(STORAGE_KEYS.SUPPORT_LEVEL) + const savedColorCapability = localStorage.getItem(STORAGE_KEYS.COLOR_CAPABILITY) + const savedPage = localStorage.getItem(STORAGE_KEYS.PAGE) + const savedItemsPerPage = localStorage.getItem(STORAGE_KEYS.ITEMS_PER_PAGE) + + if (savedSearch) setSearchQuery(String(savedSearch)) + if (savedManufacturer) setSelectedManufacturer(String(savedManufacturer)) + if (savedDriverType) setSelectedDriverType(String(savedDriverType)) + if (savedMechanismType) setSelectedMechanismType(String(savedMechanismType)) + if (savedSupportLevel) setSelectedSupportLevel(String(savedSupportLevel)) + if (savedColorCapability) setSelectedColorCapability(String(savedColorCapability)) + if (savedPage) { + const page = parseInt(savedPage, 10) + setCurrentPage(Number.isFinite(page) && page > 0 ? page : 1) + } + if (savedItemsPerPage) { + const savedValue = parseInt(savedItemsPerPage, 10) + setItemsPerPage(Number.isFinite(savedValue) ? savedValue : 20) + } + }, []) + + useEffect(() => { + async function fetchData() { + setLoading(true) + setError(null) + + try { + const response = await fetch(withBasePath("/foomatic-db/printersMap.json")) + + if (!response.ok) { + throw new Error("The printer directory is temporarily unavailable.") + } + + const data = await response.json() + const printersWithStatus: PrinterSummary[] = [] + const manufacturerSet = new Set() + + for (const printer of data.printers) { + let status = (printer.status || calculateAccurateStatus(printer)) as string + if (typeof status === "string" && status.toLowerCase() === "partial") { + status = "Mostly" + } + + printersWithStatus.push({ + ...printer, + status, + }) + + if (printer.manufacturer) { + manufacturerSet.add(printer.manufacturer) + } + } + + setPrinters(printersWithStatus) + setManufacturers(Array.from(manufacturerSet).sort()) + } catch (err) { + console.error("Failed to load printer data:", err) + setError( + err instanceof Error ? err.message : "The printer directory could not be loaded right now." + ) + } finally { + setLoading(false) + } + } + + fetchData() + }, []) + + const driverTypes = useMemo(() => { + const types = new Set() + printers.forEach((printer) => { + types.add((printer.driverCount ?? 0) > 0 ? "Drivers available" : "No listed drivers") + }) + return Array.from(types).sort() + }, [printers]) + + const mechanismTypes = useMemo(() => { + const types = new Set() + printers.forEach((printer) => { + if (printer.type) { + types.add(printer.type) + } + }) + return Array.from(types).sort() + }, [printers]) + + const supportLevels = useMemo( + () => ["Perfect", "Mostly", "Unsupported", "Unknown"], + [] + ) + + const colorCapabilities = useMemo( + () => ["color", "monochrome", "unknown"], + [] + ) + + const filteredPrinters = useMemo(() => { + let result = printers + + if (selectedManufacturer !== "all") { + result = result.filter((printer) => printer.manufacturer === selectedManufacturer) + } + + if (searchQuery) { + const queryLower = searchQuery.toLowerCase() + result = result.filter( + (printer) => + (printer.model && String(printer.model).toLowerCase().includes(queryLower)) || + (printer.manufacturer && + String(printer.manufacturer).toLowerCase().includes(queryLower)) + ) + } + + if (selectedDriverType !== "all") { + result = result.filter((printer) => + selectedDriverType === "Drivers available" + ? (printer.driverCount ?? 0) > 0 + : (printer.driverCount ?? 0) === 0 + ) + } + + if (selectedMechanismType !== "all") { + result = result.filter((printer) => printer.type === selectedMechanismType) + } + + if (selectedSupportLevel !== "all") { + result = result.filter((printer) => printer.status === selectedSupportLevel) + } + + if (selectedColorCapability !== "all") { + result = result.filter((printer) => { + const type = printer.type?.toLowerCase() || "" + const model = typeof printer.model === "string" ? printer.model.toLowerCase() : "" + + if (selectedColorCapability === "color") { + return type.includes("color") || model.includes("color") + } + + if (selectedColorCapability === "monochrome") { + return type.includes("mono") || type.includes("dot-matrix") || model.includes("mono") + } + + return true + }) + } + + return result + }, [ + printers, + searchQuery, + selectedManufacturer, + selectedDriverType, + selectedMechanismType, + selectedSupportLevel, + selectedColorCapability, + ]) + + useEffect(() => { + setCurrentPage(1) + }, [filteredPrinters]) + + useEffect(() => { + if (typeof window === "undefined") { + return + } + + localStorage.setItem(STORAGE_KEYS.SEARCH, String(searchQuery).trim()) + localStorage.setItem(STORAGE_KEYS.MANUFACTURER, selectedManufacturer) + localStorage.setItem(STORAGE_KEYS.DRIVER_TYPE, selectedDriverType) + localStorage.setItem(STORAGE_KEYS.MECHANISM_TYPE, selectedMechanismType) + localStorage.setItem(STORAGE_KEYS.SUPPORT_LEVEL, selectedSupportLevel) + localStorage.setItem(STORAGE_KEYS.COLOR_CAPABILITY, selectedColorCapability) + localStorage.setItem(STORAGE_KEYS.PAGE, currentPage.toString()) + localStorage.setItem(STORAGE_KEYS.ITEMS_PER_PAGE, itemsPerPage.toString()) + }, [ + searchQuery, + selectedManufacturer, + selectedDriverType, + selectedMechanismType, + selectedSupportLevel, + selectedColorCapability, + currentPage, + itemsPerPage, + ]) + + const resetFilters = useCallback(() => { + setSearchQuery("") + setSelectedManufacturer("all") + setSelectedDriverType("all") + setSelectedMechanismType("all") + setSelectedSupportLevel("all") + setSelectedColorCapability("all") + setCurrentPage(1) + setItemsPerPage(20) + + if (typeof window !== "undefined") { + Object.values(STORAGE_KEYS).forEach((key) => { + localStorage.removeItem(key) + }) + } + }, []) + + const totalPages = useMemo(() => { + if (itemsPerPage === -1) { + return 1 + } + return Math.ceil(filteredPrinters.length / itemsPerPage) + }, [filteredPrinters.length, itemsPerPage]) + + const displayedPrinters = useMemo(() => { + if (itemsPerPage === -1) { + return filteredPrinters + } + + const startIndex = Math.max(0, (currentPage - 1) * itemsPerPage) + const endIndex = startIndex + itemsPerPage + return filteredPrinters.slice(startIndex, endIndex) + }, [filteredPrinters, currentPage, itemsPerPage]) + + const startIndex = useMemo( + () => (itemsPerPage === -1 ? 0 : Math.max(0, (currentPage - 1) * itemsPerPage)), + [currentPage, itemsPerPage] + ) + + const endIndex = useMemo( + () => + itemsPerPage === -1 + ? filteredPrinters.length + : Math.min(startIndex + itemsPerPage, filteredPrinters.length), + [filteredPrinters.length, itemsPerPage, startIndex] + ) + + useEffect(() => { + if (itemsPerPage === -1) { + setCurrentPage(1) + return + } + + if (currentPage > totalPages) { + setCurrentPage(Math.max(1, totalPages)) + } + }, [currentPage, itemsPerPage, totalPages]) + + const goToPage = useCallback( + (page: number) => { + if (page >= 1 && page <= totalPages) { + setCurrentPage(page) + } + }, + [totalPages] + ) + + const getPageNumbers = useCallback(() => { + const pages: (number | string)[] = [] + const maxVisiblePages = 7 + + if (totalPages <= maxVisiblePages) { + for (let index = 1; index <= totalPages; index += 1) { + pages.push(index) + } + return pages + } + + if (currentPage <= 4) { + for (let index = 1; index <= 5; index += 1) { + pages.push(index) + } + pages.push("...", totalPages) + return pages + } + + if (currentPage >= totalPages - 3) { + pages.push(1, "...") + for (let index = totalPages - 4; index <= totalPages; index += 1) { + pages.push(index) + } + return pages + } + + pages.push(1, "...") + for (let index = currentPage - 1; index <= currentPage + 1; index += 1) { + pages.push(index) + } + pages.push("...", totalPages) + return pages + }, [currentPage, totalPages]) + + return ( +
+
+
+
+
+
+ + +
+ + OpenPrinting Foomatic database + + +

+ Foomatic + Foomatic + Printer Lookup +

+

+ Find support information for legacy printers, review available drivers, and open PPD + files for closer inspection. +

+
+
+
+ + + + + {error ? ( + +
+ +
+

Unable to load the printer directory

+

+ {error || "Please try again in a moment."} +

+
+ ) : loading ? ( +
+ {Array.from({ length: 6 }).map((_, index) => ( + + ))} +
+ ) : displayedPrinters.length > 0 ? ( +
+ + + + + {totalPages > 1 ? ( + +
+

+ Page {currentPage} of {totalPages} +

+

+ {searchQuery ? `Results for "${searchQuery}"` : "Browsing all printer models"} + {selectedManufacturer !== "all" ? ` in ${selectedManufacturer}` : ""} +

+
+ +
+ + +
+ {getPageNumbers().map((page, index) => + typeof page !== "number" ? ( + + ... + + ) : ( + + ) + )} +
+ + +
+
+ ) : null} +
+ ) : ( + +
+ +
+

No matching printers found

+

+ Try a different model name, broaden your filters, or clear the current search to see more results. +

+
+ )} +
+
+
+ ) +} diff --git a/app/foomatic/printer/[id]/page.tsx b/app/foomatic/printer/[id]/page.tsx new file mode 100644 index 00000000..7e14f384 --- /dev/null +++ b/app/foomatic/printer/[id]/page.tsx @@ -0,0 +1,68 @@ +import fs from "fs/promises" +import path from "path" +import type { Metadata } from "next" +import type { Printer, PrinterSummary } from "@/lib/foomatic/types" +import PrinterPageClient from "@/components/foomatic/PrinterPageClient" +import { getSiteUrl } from "@/lib/site" + +async function getPrinterSummaries(): Promise { + const filePath = path.join(process.cwd(), "public", "foomatic-db", "printersMap.json") + try { + const data = await fs.readFile(filePath, "utf-8") + const json = JSON.parse(data) + return json.printers + } catch (error) { + if ((error as NodeJS.ErrnoException).code === "ENOENT") { + return [] + } + + throw error + } +} + +export async function generateStaticParams() { + const printers = await getPrinterSummaries() + return printers.map((printer) => ({ + id: printer.id, + })) +} + +interface PrinterPageProps { + params: Promise<{ + id: string + }> +} + +async function getPrinter(id: string): Promise { + const filePath = path.join(process.cwd(), "public", "foomatic-db", "printers", `${id}.json`) + try { + return JSON.parse(await fs.readFile(filePath, "utf-8")) as Printer + } catch { + return null + } +} + +export async function generateMetadata({ params }: PrinterPageProps): Promise { + const { id } = await params + const printer = await getPrinter(id) + const name = printer ? `${printer.manufacturer} ${printer.model}` : id + const driverCount = printer?.drivers?.length ?? 0 + const title = `${name} — Printer support & drivers | OpenPrinting` + const description = printer + ? `Support information, recommended driver, and ${driverCount} available driver${driverCount === 1 ? "" : "s"} for the ${name} on Linux and Unix via OpenPrinting.` + : `Printer support information for ${id} from the OpenPrinting database.` + const canonical = getSiteUrl(`/foomatic/printer/${id}/`) + + return { + title, + description, + alternates: { canonical }, + openGraph: { title, description, url: canonical, type: "website" }, + } +} + +export default async function PrinterPage({ params }: PrinterPageProps) { + const { id } = await params + + return +} diff --git a/app/foomatic/view-ppd/page.tsx b/app/foomatic/view-ppd/page.tsx new file mode 100644 index 00000000..40c6e69a --- /dev/null +++ b/app/foomatic/view-ppd/page.tsx @@ -0,0 +1,11 @@ +import { Suspense } from "react" + +import PpdViewerClient from "@/components/foomatic/PpdViewerClient" + +export default function ViewPpdPage() { + return ( + + + + ) +} diff --git a/app/globals.css b/app/globals.css new file mode 100644 index 00000000..e5c6d60e --- /dev/null +++ b/app/globals.css @@ -0,0 +1,211 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 93%; + --foreground: 220 13% 18%; + --card: 0 0% 100%; + --card-foreground: 220 13% 18%; + --popover: 0 0% 100%; + --popover-foreground: 220 13% 18%; + --primary: 197 100% 40%; + --primary-foreground: 0 0% 100%; + --secondary: 210 3% 94%; + --secondary-foreground: 220 13% 18%; + --muted: 180 5% 98%; + --muted-foreground: 220 6% 37%; + --accent: 210 3% 94%; + --accent-foreground: 220 13% 18%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + --ring: 240 10% 3.9%; + --radius: 0.5rem; + } + + .dark { + --background: 0 0% 0%; + --foreground: 0 0% 98%; + --card: 0 0% 4%; + --card-foreground: 0 0% 98%; + --popover: 0 0% 4%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 0 0% 4%; + --secondary: 0 0% 8%; + --secondary-foreground: 0 0% 98%; + --muted: 0 0% 10%; + --muted-foreground: 0 0% 55%; + --accent: 0 0% 10%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 12%; + --input: 0 0% 12%; + --ring: 0 0% 83.9%; + } +} + +@layer base { + * { + @apply border-border; + } + + body { + @apply bg-background text-foreground; + } + + html { + scroll-behavior: smooth; + } +} + +.hero-glow { + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + background: radial-gradient(ellipse 80% 50% at 50% -20%, rgba(120, 119, 198, 0.15), transparent); + pointer-events: none; +} + +.hero-glow-blue { + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + background: radial-gradient(ellipse 60% 40% at 50% 0%, rgba(59, 130, 246, 0.12), transparent); + pointer-events: none; +} + +.hero-banner-image { + position: absolute; + inset: 0; + background-size: cover; + background-position: 80% 0; + opacity: 0.15; + mix-blend-mode: screen; + pointer-events: none; +} + +.grid-pattern { + background-image: linear-gradient(rgba(0, 0, 0, 0.04) 1px, transparent 1px), + linear-gradient(90deg, rgba(0, 0, 0, 0.04) 1px, transparent 1px); + background-size: 64px 64px; +} + +.dark .grid-pattern { + background-image: linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), + linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px); +} + +.section-divider { + height: 1px; + background: linear-gradient(to right, + transparent, + rgba(0, 0, 0, 0.1) 20%, + rgba(0, 0, 0, 0.1) 80%, + transparent); +} + +.dark .section-divider { + background: linear-gradient(to right, + transparent, + rgba(255, 255, 255, 0.08) 20%, + rgba(255, 255, 255, 0.08) 80%, + transparent); +} + +.card-glow { + transition: box-shadow 0.3s ease, border-color 0.3s ease; +} + +.card-glow:hover { + box-shadow: 0 0 30px -5px rgba(59, 130, 246, 0.1), 0 8px 24px -8px rgba(0, 0, 0, 0.4); +} + +.text-gradient { + background: linear-gradient(to bottom right, #ffffff 30%, rgba(255, 255, 255, 0.38)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +.text-gradient-foreground { + background: linear-gradient( + to bottom right, + hsl(var(--foreground)) 30%, + hsl(var(--foreground) / 0.5) + ); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +.text-gradient-blue { + background: linear-gradient(135deg, #60a5fa 0%, #3b82f6 50%, #2563eb 100%); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +::-webkit-scrollbar { + width: 6px; +} + +::-webkit-scrollbar-track { + background: transparent; +} + +::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, 0.15); + border-radius: 3px; +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(0, 0, 0, 0.25); +} + +.dark::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.1); +} + +.dark::-webkit-scrollbar-thumb:hover { + background: rgba(255, 255, 255, 0.2); +} + + +.about-us-content .prose h2:first-of-type::after { + content: ""; + display: block; + width: 40%; + max-width: 12rem; + height: 2px; + background: hsl(var(--foreground)); + margin-top: 0.5rem; +} + +.about-us-content .prose h2:first-of-type+ul a { + color: hsl(var(--primary)); + text-decoration: underline; +} + +.prose { + overflow-wrap: break-word; + word-wrap: break-word; +} + +.prose a { + word-break: break-all; +} + +.prose iframe { + max-width: 100%; + aspect-ratio: 16 / 9; + height: auto; +} \ No newline at end of file diff --git a/app/gsoc/[year]/[project]/page.tsx b/app/gsoc/[year]/[project]/page.tsx new file mode 100644 index 00000000..fca7f0b9 --- /dev/null +++ b/app/gsoc/[year]/[project]/page.tsx @@ -0,0 +1,559 @@ +import Link from "next/link"; +import Image from "next/image"; +import { MarkdownRenderer } from "@/components/markdown-renderer"; +import { TableOfContents } from "@/components/table-of-contents"; +import { + getGsocProject, + getGsocProjectsByYear, + getGsocYears, +} from "@/lib/gsoc"; +import { + getContributorImageSrc, + getContributorsBySlug, + mentorImages, +} from "@/data/gsoc-contributors"; +import { getWorkSummary } from "@/data/gsoc-work-summaries"; +import { getMentorsBySlug } from "@/data/gsoc-mentors"; +import { GsocContributorInlineSocials } from "@/components/gsoc-contributor-socials"; +import { + ArrowLeft, + User, + ExternalLink, + FileText, + Quote, + CheckCircle2, + XCircle, + AlertCircle, + Shield, + Lightbulb, +} from "lucide-react"; +import { siteConfig } from "@/config/site.config"; + +const basePath = siteConfig.urls.basePath; + +export async function generateStaticParams() { + const years = await getGsocYears(); + const allParams: Array<{ year: string; project: string }> = []; + + for (const year of years) { + const projects = await getGsocProjectsByYear(year); + for (const project of projects) { + allParams.push({ year, project: project.slug }); + } + } + + return allParams; +} + +/* ---------- small helpers ---------- */ + +function StatusBadge({ + status, +}: { + status: "passed" | "failed" | "withdrawn"; +}) { + const cfg = { + passed: { + icon: CheckCircle2, + label: "Passed", + cls: "border-green-500/20 bg-green-500/10 text-green-700 dark:text-green-400", + }, + failed: { + icon: XCircle, + label: "Failed", + cls: "border-red-500/20 bg-red-500/10 text-red-700 dark:text-red-400", + }, + withdrawn: { + icon: AlertCircle, + label: "Withdrawn", + cls: "border-yellow-500/20 bg-yellow-500/10 text-yellow-700 dark:text-yellow-400", + }, + }[status]; + const Icon = cfg.icon; + return ( + + + {cfg.label} + + ); +} + +/* ---------- page ---------- */ + +export default async function GsocProjectPage({ + params, +}: { + params: Promise<{ year: string; project: string }>; +}) { + const { year, project } = await params; + const post = await getGsocProject(year, decodeURIComponent(project)); + const yearProjects = await getGsocProjectsByYear(year); + const currentSlug = decodeURIComponent(project); + const contributors = getContributorsBySlug(Number(year), currentSlug); + + // gather work summaries for each contributor + const workSummaries = contributors + .map((c) => ({ + contributor: c, + summary: getWorkSummary(c.name, Number(year)), + })) + .filter( + ( + ws, + ): ws is { + contributor: (typeof contributors)[0]; + summary: NonNullable>; + } => !!ws.summary, + ); + + const isCompleted = contributors.length > 0; + const mentors = isCompleted + ? [...new Set(contributors.flatMap((c) => c.mentors))] + : getMentorsBySlug(Number(year), currentSlug); + const skills = [...new Set(contributors.flatMap((c) => c.desiredKnowledge))]; + const license = contributors.find((c) => c.codeLicense)?.codeLicense; + + return ( +
+
+ {/* Back link */} + + + Back to GSoC {year} + + +
+ {/* ── Left sidebar (desktop) ── */} + {(isCompleted || mentors.length > 0) && ( + + )} + + {/* ── Mobile info ── */} + {(isCompleted || mentors.length > 0) && ( +
+ {/* Contributors (completed only) */} + {isCompleted && ( +
+ {contributors.map((contributor, idx) => { + const contributorImage = getContributorImageSrc(contributor); + return ( +
+
+ {contributorImage ? ( + {contributor.name} + ) : ( + + + + )} + + {contributor.name} + +
+ +
+ ); + })} +
+ {workSummaries.map((ws, idx) => ( + + ))} +
+
+ )} + + {/* Mentors — always */} + {mentors.length > 0 && ( +
+ + {mentors.length === 1 ? "Mentor" : "Mentors"}: + + {mentors.map((m) => ( + + {mentorImages[m] ? ( + {m} + ) : ( + + )} + {m} + + ))} +
+ )} + + {/* Mobile links (completed only) */} + {isCompleted && + (() => { + const links: { label: string; href: string }[] = []; + for (const ws of workSummaries) { + if (ws.summary.workProductUrl) + links.push({ + label: "Final Report", + href: ws.summary.workProductUrl, + }); + } + for (const c of contributors) { + if (c.projectUrl) + links.push({ + label: "GSoC Archive", + href: c.projectUrl, + }); + if (c.codeUrl) + links.push({ label: "Code", href: c.codeUrl }); + } + const unique = links.filter( + (l, i, arr) => + arr.findIndex((x) => x.href === l.href) === i, + ); + if (unique.length === 0) return null; + return ( +
+ {unique.map((link) => ( + + + {link.label} + + ))} +
+ ); + })()} + + {/* Mobile ToC */} +
+ +
+
+ )} + + {/* ── Main content column ── */} +
+ {/* Title area */} +
+
+ + GSoC {year} + + {!isCompleted && ( + + Project Idea + + )} +
+

+ {post.title} +

+
+
+ + {/* Work summary card (for completed projects) */} + {workSummaries.length > 0 && ( +
+ {workSummaries.map((ws, idx) => ( +
+
+
+ +
+
+

+ Work Summary + {contributors.length > 1 && ( + + {" "} + — {ws.contributor.name} + + )} +

+

+ {ws.summary.summary} +

+
+
+ + {ws.summary.quote && ( +
+
+ +

+ “{ws.summary.quote}” +

+
+

+ — {ws.contributor.name} +

+
+ )} + + {ws.summary.workProductUrl && ( + + )} +
+ ))} +
+ )} + + {/* Markdown content */} +
+
+ +
+
+
+ + {/* ── Right sidebar ── */} + +
+
+
+ ); +} diff --git a/app/gsoc/[year]/page.tsx b/app/gsoc/[year]/page.tsx new file mode 100644 index 00000000..eb1b9e24 --- /dev/null +++ b/app/gsoc/[year]/page.tsx @@ -0,0 +1,45 @@ +import { + getGsocYearOverview, + getGsocYears, + getGsocPostsByYear, + getGsocProjectsByYear, +} from "@/lib/gsoc"; +import { + getContributorsByYear, + getOrgUrlByYear, +} from "@/data/gsoc-contributors"; +import { getWorkSummariesByYear } from "@/data/gsoc-work-summaries"; +import { GsocYearClient } from "@/components/gsoc-year-client"; + +export async function generateStaticParams() { + const years = await getGsocYears(); + return years.map((year) => ({ year })); +} + +export default async function GsocYearPage({ + params, +}: { + params: Promise<{ year: string }>; +}) { + const { year } = await params; + const overview = await getGsocYearOverview(year); + const projects = await getGsocProjectsByYear(year); + const contributors = getContributorsByYear(Number(year)); + const orgUrl = getOrgUrlByYear(Number(year)); + const allPostsByYear = await getGsocPostsByYear(); + const relatedPosts = allPostsByYear[year] ?? []; + const workSummaries = getWorkSummariesByYear(Number(year)); + + return ( + + ); +} diff --git a/app/gsoc/page.tsx b/app/gsoc/page.tsx new file mode 100644 index 00000000..28f72de9 --- /dev/null +++ b/app/gsoc/page.tsx @@ -0,0 +1,104 @@ +import Link from "next/link"; +import { getGsocYearSummaries } from "@/lib/gsoc"; +import { getContributorsByYear } from "@/data/gsoc-contributors"; +import { ArrowRight, Users, FolderOpen } from "lucide-react"; +import { GsocOrgBanner } from "@/components/gsoc-org-banner"; + +export default async function GsocIndexPage() { + const years = await getGsocYearSummaries(); + + return ( +
+ {/* Hero banner */} +
+
+
+
+

+ Open Source Contributions +

+

+ Google Summer{" "} + of Code +

+

+ OpenPrinting participates in GSoC under The Linux Foundation, + mentoring contributors on printing infrastructure, desktop + integration, and open-source development. +

+
+
+ +
+ + {/* Org info banner */} +
+
+ +
+
+ +
+ + {/* Year cards */} +
+
+
+

+ Browse by Year +

+

+ All Editions +

+
+ +
+ {years.map((item) => { + const contributors = getContributorsByYear(Number(item.year)); + return ( + +
+

+ {item.year} +

+ + GSoC + +
+ +
+
+ + + {item.projectCount} project{" "} + {item.projectCount === 1 ? "idea" : "ideas"} + +
+ {contributors.length > 0 && ( +
+ + + {contributors.length} contributor + {contributors.length === 1 ? "" : "s"} + +
+ )} +
+ +
+ View projects + +
+ + ); + })} +
+
+
+
+ ); +} diff --git a/app/gsod-2020-students/page.tsx b/app/gsod-2020-students/page.tsx new file mode 100644 index 00000000..59bfec2e --- /dev/null +++ b/app/gsod-2020-students/page.tsx @@ -0,0 +1,51 @@ +import Image from "next/image" +import { notFound } from "next/navigation" +import { GsodHero } from "@/components/gsod-hero" +import { getGsodContributorBySlug } from "@/data/gsod-contributors" +import { siteConfig } from "@/config/site.config"; + +const basePath = siteConfig.urls.basePath + +export default function GSoD2020StudentsPage() { + const contributor = getGsodContributorBySlug("gsod-2020-students") + + if (!contributor) { + notFound() + } + + return ( +
+ + +
+ +
+
+
+
+
+ {contributor.name} +
+ +

{contributor.name}

+

+ {contributor.title} +

+
+
+
+
+
+ ) +} diff --git a/app/gsod/page.tsx b/app/gsod/page.tsx new file mode 100644 index 00000000..a1e8e7d0 --- /dev/null +++ b/app/gsod/page.tsx @@ -0,0 +1,142 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import Link from "next/link" +import { ArrowRight, FolderOpen, Users } from "lucide-react" +import { GsodHero } from "@/components/gsod-hero" + +const FILE_PATH = path.join(process.cwd(), "contents", "pages", "gsod.md") + +type SectionItem = { + title: string + href: string +} + +type Section = { + title: string + items: SectionItem[] +} + +function parseSections(content: string): Section[] { + const lines = content.split(/\r?\n/) + const sections: Section[] = [] + let currentSection: Section | null = null + + for (const line of lines) { + const sectionMatch = /^##\s+(.*)$/.exec(line.trim()) + + if (sectionMatch) { + currentSection = { + title: sectionMatch[1].trim(), + items: [], + } + sections.push(currentSection) + continue + } + + const itemMatch = /^###\s+(?:\d+\.\s+)?\[(.+)\]\((.+)\)$/.exec(line.trim()) + + if (itemMatch && currentSection) { + currentSection.items.push({ + title: itemMatch[1].trim(), + href: itemMatch[2].trim(), + }) + } + } + + return sections +} + +function getSectionMeta(title: string) { + if (title.toLowerCase().includes("students")) { + return { + eyebrow: "Browse Students", + icon: Users, + badge: "Students", + action: "View page", + } + } + + return { + eyebrow: "Browse Projects", + icon: FolderOpen, + badge: "Projects", + action: "View page", + } +} + +export default async function GSoDPage() { + const raw = await fs.readFile(FILE_PATH, "utf8") + const { data, content } = matter(raw) + + const title = + typeof data.title === "string" ? data.title : "GSoD - OpenPrinting" + const sections = parseSections(content) + + return ( +
+ + +
+ + {sections.map((section, index) => { + const meta = getSectionMeta(section.title) + const Icon = meta.icon + + return ( +
+
+
+
+

+ {meta.eyebrow} +

+

+ {section.title} +

+
+ +
+ {section.items.map((item) => ( + +
+
+ +
+ + {meta.badge} + +
+ +

+ {item.title} +

+ +
+ {meta.action} + +
+ + ))} +
+
+
+ + {index < sections.length - 1 ? ( +
+ ) : null} +
+ ) + })} +
+ ) +} diff --git a/app/gsod2020/[slug]/page.tsx b/app/gsod2020/[slug]/page.tsx new file mode 100644 index 00000000..f2e82eda --- /dev/null +++ b/app/gsod2020/[slug]/page.tsx @@ -0,0 +1,76 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import Link from "next/link" +import { notFound } from "next/navigation" +import { ArrowLeft } from "lucide-react" +import { MarkdownRenderer } from "@/components/markdown-renderer" +import { GsodHero } from "@/components/gsod-hero" + +const IDEAS_DIR = path.join(process.cwd(), "contents", "gsod", "gsod2020") + +async function getIdeaBySlug(slug: string) { + const filePath = path.join(IDEAS_DIR, `${slug}.md`) + + try { + const raw = await fs.readFile(filePath, "utf8") + const { data, content } = matter(raw) + const title = + typeof data.title === "string" ? data.title : slug.replace(/-/g, " ") + + return { title, content } + } catch { + return null + } +} + +export async function generateStaticParams() { + const files = await fs.readdir(IDEAS_DIR) + return files + .filter((f) => f.endsWith(".md")) + .map((f) => ({ slug: f.replace(/\.md$/, "") })) +} + +export default async function GSoD2020IdeaPage({ + params, +}: { + params: Promise<{ slug: string }> +}) { + const { slug } = await params + const idea = await getIdeaBySlug(slug) + + if (!idea) notFound() + + return ( +
+ + +
+ +
+
+ + + Back to GSoD 2020 + +
+
+ +
+
+
+ +
+
+
+
+ ) +} + diff --git a/app/gsod2020/page.tsx b/app/gsod2020/page.tsx new file mode 100644 index 00000000..cc566433 --- /dev/null +++ b/app/gsod2020/page.tsx @@ -0,0 +1,103 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import Link from "next/link" +import { ArrowRight, Lightbulb } from "lucide-react" +import { MarkdownRenderer } from "@/components/markdown-renderer" +import { GsodHero } from "@/components/gsod-hero" + +const MAIN_FILE = path.join(process.cwd(), "contents", "pages", "gsod2020.md") +const IDEAS_DIR = path.join(process.cwd(), "contents", "gsod", "gsod2020") + +type Idea = { + title: string + slug: string +} + +export default async function GSoD2020Page() { + const raw = await fs.readFile(MAIN_FILE, "utf8") + const { data, content } = matter(raw) + + const title = + typeof data.title === "string" + ? data.title + : "Google Season of Docs 2020" + + const cleanedContent = content + .replace(/

\s*Project Ideas\s*<\/h1>\s*
\s*<\/div>\s*/gi, "") + .replace(/^\s*#\s*Project Ideas\s*$/gim, "") + + const files = await fs.readdir(IDEAS_DIR) + + const ideas: Idea[] = [] + + for (const file of files.sort()) { + if (!file.endsWith(".md")) continue + + const filePath = path.join(IDEAS_DIR, file) + const fileContent = await fs.readFile(filePath, "utf8") + const { data } = matter(fileContent) + + ideas.push({ + title: typeof data.title === "string" ? data.title : file.replace(".md", ""), + slug: file.replace(/\.md$/, ""), + }) + } + + return ( +
+ + +
+ +
+
+
+ +
+
+
+ + {ideas.length > 0 && ( +
+
+

Project Ideas

+ +
+ {ideas.map((idea) => ( + +
+
+ +
+ + Idea + +
+ +

+ {idea.title} +

+ +
+ Open idea + +
+ + ))} +
+
+
+ )} +
+ ) +} \ No newline at end of file diff --git a/app/history/page.tsx b/app/history/page.tsx new file mode 100644 index 00000000..d75c000a --- /dev/null +++ b/app/history/page.tsx @@ -0,0 +1,27 @@ +import fs from "fs/promises" +import path from "path" +import matter from "gray-matter" +import { MarkdownRenderer } from "@/components/markdown-renderer" +import { PageHero } from "@/components/page-hero" + +const FILE_PATH = path.join(process.cwd(), "contents", "pages", "history.md") + +export default async function HistoryPage() { + const raw = await fs.readFile(FILE_PATH, "utf8") + const { data, content } = matter(raw) + + const title = + typeof data.title === "string" ? data.title : "History" + + return ( + <> + + +
+
+ +
+
+ + ) +} diff --git a/app/layout.tsx b/app/layout.tsx new file mode 100644 index 00000000..4638940d --- /dev/null +++ b/app/layout.tsx @@ -0,0 +1,50 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono, Inter } from "next/font/google"; +import "./globals.css"; +import Navbar from "@/components/navbar"; +import Footer from "@/components/footer"; +import { ThemeProvider } from "@/components/theme-provider"; +import { siteConfig } from "@/config/site.config"; +import { getSiteUrl } from "@/lib/site"; + +const inter = Inter({ subsets: ["latin"] }) + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: siteConfig.brand.title, + description: siteConfig.brand.description, + alternates: { + types: { + "application/rss+xml": getSiteUrl(siteConfig.urls.rssPath), + }, + }, +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + + + {children} +