Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ vmemo/ # Repository root
- If ownership is unclear, place logic in the backend.
- Respect Ash conventions first; do not model new behavior Ecto-first.
- Encapsulate external REST calls in dedicated SDK modules.
- For JavaScript assets, use `assets/vendor/` vendoring patterns instead of assuming npm-style app tooling.
- For CSS and JavaScript external dependencies, use `assets/package.json` and
`assets/package-lock.json`; do not copy package source into `assets/vendor/`.

## Phoenix / LiveView implementation rules
- See detailed rules in `.agents/skills/vmemo-coding-guides/SKILL.md`.
Expand Down
10 changes: 9 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# syntax=docker/dockerfile:1.6
FROM elixir:1.19.5-otp-28 AS base
FROM node:24.14.1-bookworm-slim AS node

FROM base AS builder

Expand All @@ -9,15 +10,22 @@ RUN apt-get update -y && \

WORKDIR /app

COPY --from=node /usr/local/bin/node /usr/local/bin/node
COPY --from=node /usr/local/lib/node_modules /usr/local/lib/node_modules
RUN ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm && \
ln -s /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx

ENV MIX_ENV=prod
ENV HEX_HTTP_TIMEOUT=120
ENV HEX_HTTP_CONCURRENCY=1
ENV HEX_HTTP_RETRIES=3

COPY mix.exs mix.lock ./
COPY assets/package.json assets/package-lock.json ./assets/
RUN mix local.hex --force && \
mix local.rebar --force && \
mix deps.get --only prod
mix deps.get --only prod && \
npm ci --prefix assets

COPY . .
RUN mix compile
Expand Down
22 changes: 7 additions & 15 deletions assets/css/app.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/* See the Tailwind configuration guide for advanced usage
https://tailwindcss.com/docs/configuration */

@import "tailwindcss" source(none);
@import url("https://fonts.googleapis.com/css2?family=Manrope:wght@500;600;700;800&family=Work+Sans:wght@400;500;600&display=swap");
@import "../vendor/choices.min.css";
@import "tailwindcss" source(none);
@import "choices.js/public/assets/styles/choices.min.css";
@source "../css";
@source "../js";
@source "../../lib/vmemo_web";
Expand All @@ -12,22 +12,14 @@
navigation: auto;
}

/* A Tailwind plugin that makes "hero-#{ICON}" classes available.
The heroicons installation itself is managed by your mix.exs */
@plugin "../vendor/heroicons";
/* A Tailwind plugin that makes "hero-#{ICON}" classes available. */
@plugin "../js/heroicons_plugin";

/* daisyUI Tailwind Plugin. You can update this file by fetching the latest version with:
curl -sLO https://github.com/saadeghi/daisyui/releases/latest/download/daisyui.js
Make sure to look at the daisyUI changelog: https://daisyui.com/docs/changelog/ */
@plugin "../vendor/daisyui" {
@plugin "daisyui" {
themes: false;
}

/* daisyUI theme plugin. You can update this file by fetching the latest version with:
curl -sLO https://github.com/saadeghi/daisyui/releases/latest/download/daisyui-theme.js
We ship with a light theme inspired on Phoenix/GitHub colors.
Build your own at: https://daisyui.com/theme-generator/ */
@plugin "../vendor/daisyui-theme" {
@plugin "daisyui/theme" {
name: "light";
default: true;
prefersdark: false;
Expand Down Expand Up @@ -63,7 +55,7 @@
--noise: 0;
}

@plugin "../vendor/daisyui-theme" {
@plugin "daisyui/theme" {
name: "dark";
default: false;
prefersdark: true;
Expand Down
14 changes: 2 additions & 12 deletions assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,8 @@
// to get started and then uncomment the line below.
// import "./user_socket.js"

// You can include dependencies in two ways.
//
// The simplest option is to put them in assets/vendor and
// import them using relative paths:
//
// import "../vendor/some-package.js"
//
// Alternatively, you can `npm install some-package --prefix assets` and import
// them using a path starting with the package name:
//
// import "some-package"
//
// External JavaScript and CSS dependencies are installed from assets/package.json.
// Phoenix packages are resolved from Mix deps through NODE_PATH in npm scripts.

import { Resizer } from "./hooks/resizer"
import { InfiniteScroll } from "./hooks/infinite_scroll"
Expand Down
55 changes: 55 additions & 0 deletions assets/js/heroicons_plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const fs = require("fs")
const path = require("path")
const plugin = require("tailwindcss/plugin")

const heroiconsPackagePath = path.dirname(require.resolve("heroicons/package.json"))
const iconsDir = fs.existsSync(path.join(heroiconsPackagePath, "optimized"))
? path.join(heroiconsPackagePath, "optimized")
: heroiconsPackagePath

module.exports = plugin(function ({ matchComponents, theme }) {
const values = {}
const icons = [
["", "24/outline"],
["-solid", "24/solid"],
["-mini", "20/solid"],
["-micro", "16/solid"],
]

icons.forEach(([suffix, dir]) => {
fs.readdirSync(path.join(iconsDir, dir)).forEach((file) => {
const name = path.basename(file, ".svg") + suffix
values[name] = { name, fullPath: path.join(iconsDir, dir, file) }
})
})

matchComponents(
{
hero: ({ name, fullPath }) => {
const content = encodeURIComponent(
fs.readFileSync(fullPath).toString().replace(/\r?\n|\r/g, "")
)
let size = theme("spacing.6")

if (name.endsWith("-mini")) {
size = theme("spacing.5")
} else if (name.endsWith("-micro")) {
size = theme("spacing.4")
}

return {
[`--hero-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
"-webkit-mask": `var(--hero-${name})`,
mask: `var(--hero-${name})`,
"mask-repeat": "no-repeat",
"background-color": "currentColor",
"vertical-align": "middle",
display: "inline-block",
width: size,
height: size,
}
},
},
{ values }
)
})
2 changes: 1 addition & 1 deletion assets/js/hooks/tag_input.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Choices from "../../vendor/choices.min.js"
import Choices from "choices.js"

export const TagInput = {
mounted() {
Expand Down
Loading